From eb31861b54ac51d0cbc2f3262e42fd536ac32509 Mon Sep 17 00:00:00 2001 From: chenos Date: Sun, 4 Jul 2021 22:04:15 +0800 Subject: [PATCH] improve code --- .../blocks/DesignableSchemaField/index.tsx | 22 +- packages/client/src/blocks/add-new/form.ts | 73 ---- packages/client/src/blocks/add-new/index.md | 101 +++++- packages/client/src/blocks/add-new/index.tsx | 213 +++++++---- .../client/src/blocks/add-new/markdown.ts | 8 - packages/client/src/blocks/add-new/table.ts | 86 ----- .../client/src/blocks/block-item/index.tsx | 172 +++++++++ .../client/src/blocks/block-item/style.less | 43 +++ .../client/src/blocks/drag-and-drop/index.tsx | 16 + .../client/src/blocks/form-item/index.tsx | 89 +++-- .../client/src/blocks/form/DesignableBar.tsx | 43 --- packages/client/src/blocks/form/index.md | 343 ++---------------- packages/client/src/blocks/form/index.tsx | 93 ++++- packages/client/src/blocks/form/style.less | 45 +++ .../client/src/blocks/grid/demos/demo1.tsx | 180 +++------ packages/client/src/blocks/grid/index.md | 2 +- packages/client/src/blocks/grid/index.tsx | 223 ++++++------ packages/client/src/blocks/grid/style.less | 5 +- .../drag-and-drop/index.tsx} | 67 +++- packages/client/src/index.md | 2 +- 20 files changed, 900 insertions(+), 926 deletions(-) delete mode 100644 packages/client/src/blocks/add-new/form.ts delete mode 100644 packages/client/src/blocks/add-new/markdown.ts delete mode 100644 packages/client/src/blocks/add-new/table.ts create mode 100644 packages/client/src/blocks/block-item/index.tsx create mode 100644 packages/client/src/blocks/block-item/style.less create mode 100644 packages/client/src/blocks/drag-and-drop/index.tsx delete mode 100644 packages/client/src/blocks/form/DesignableBar.tsx create mode 100644 packages/client/src/blocks/form/style.less rename packages/client/src/{blocks/grid/hooks.tsx => components/drag-and-drop/index.tsx} (90%) diff --git a/packages/client/src/blocks/DesignableSchemaField/index.tsx b/packages/client/src/blocks/DesignableSchemaField/index.tsx index dcdb32aff..e5f7ff5bc 100644 --- a/packages/client/src/blocks/DesignableSchemaField/index.tsx +++ b/packages/client/src/blocks/DesignableSchemaField/index.tsx @@ -20,7 +20,7 @@ import { observable } from '@formily/reactive'; import { uid, clone } from '@formily/shared'; import { ArrayCollapse, ArrayTable, FormLayout } from '@formily/antd'; -import { Space, Card, Modal } from 'antd'; +import { Space, Card, Modal, Spin } from 'antd'; import { Action, useLogin, useRegister, useSubmit } from '../action'; import { AddNew } from '../add-new'; import { Cascader } from '../cascader'; @@ -45,6 +45,8 @@ import { Tabs } from '../tabs'; import { TimePicker } from '../time-picker'; import { Upload } from '../upload'; import { FormItem } from '../form-item'; +import { BlockItem } from '../block-item'; +import { DragAndDrop } from '../drag-and-drop'; import { CodeOutlined } from '@ant-design/icons'; import Editor from '@monaco-editor/react'; @@ -60,13 +62,17 @@ export const scope = { }; export const components = { + Card, Div, Space, - Card, ArrayCollapse, ArrayTable, FormLayout, + + DragAndDrop, + + BlockItem, FormItem, Action, @@ -171,7 +177,7 @@ export function useDesignable(path?: any) { const currentSchema = findPropertyByPath(schema, schemaPath); console.log('useDesignable', { schema, schemaPath, currentSchema }); return { - schema: (currentSchema || {} as any), + schema: currentSchema || ({} as Schema), refresh, prepend: (property: ISchema, targetPath?: any): Schema => { let target = currentSchema; @@ -192,7 +198,7 @@ export function useDesignable(path?: any) { current.parent.removeProperty(current.name); properties[current.name] = current.toJSON(); }); - console.log({ properties }, target.properties) + console.log({ properties }, target.properties); target.setProperties(properties); refresh(); return target.properties[property.name]; @@ -263,7 +269,6 @@ export function useDesignable(path?: any) { return; } s.parent.removeProperty(s.name); - console.log('s.parent.properties', s.name, s.parent.properties) if (Object.keys(s.parent.properties || {}).length === 0) { remove(s.parent); } @@ -337,7 +342,12 @@ const CodePreview = ({ schema }) => { return ( <> setVisible(true)} /> - setVisible(false)} visible={visible}> + setVisible(false)} + onCancel={() => setVisible(false)} + visible={visible} + > ({ - type: 'void', - name: `form_${uid()}`, - 'x-decorator': 'Card', - 'x-component': 'Form', - properties: { - grid: { - type: 'void', - 'x-component': 'Grid', - properties: { - [`gr_${uid()}`]: { - type: 'void', - 'x-component': 'Grid.Row', - properties: { - [`gc_${uid()}`]: { - type: 'void', - 'x-component': 'Grid.Col', - 'x-component-props': { - size: 1, - }, - properties: { - [`gb_${uid()}`]: { - type: 'void', - 'x-component': 'Grid.Block', - properties: { - [`gbn_${uid()}`]: { - type: 'void', - 'x-component': 'AddNew.FormItem', - }, - }, - }, - }, - }, - }, - }, - }, - }, - actions: { - type: 'void', - // 'x-decorator': 'Div', - 'x-component': 'Space', - properties: { - submit: { - type: 'void', - 'x-component': 'Action', - 'x-component-props': { - // block: true, - type: 'primary', - useAction: '{{ useLogin }}', - style: { - // width: '100%', - }, - }, - title: '提交', - }, - reset: { - type: 'void', - 'x-component': 'Action', - 'x-component-props': { - // block: true, - useAction: '{{ useLogin }}', - style: { - // width: '100%', - }, - }, - title: '重置', - }, - }, - }, - }, -}) \ No newline at end of file diff --git a/packages/client/src/blocks/add-new/index.md b/packages/client/src/blocks/add-new/index.md index 88dd52f03..1faaf1948 100644 --- a/packages/client/src/blocks/add-new/index.md +++ b/packages/client/src/blocks/add-new/index.md @@ -1,5 +1,5 @@ --- -title: AddNew - 新增区块 +title: AddNew - 新增 nav: title: 组件 path: /client @@ -9,18 +9,34 @@ group: path: /client/components --- -# AddNew - 新增区块 +# AddNew - 新增 -## 新增普通区块 +可用于新增区块 AddNew 或表单项 AddNew.FormItem,支持常规布局也支持 Grid 布局。 + +## 代码演示 + +### 基本使用 ```tsx import React from 'react'; +import { ISchema } from '@formily/react'; +import { uid } from '@formily/shared'; import { SchemaRenderer } from '../'; -const schema = { - type: 'void', - name: 'addnew', - 'x-component': 'AddNew', +const schema: ISchema = { + type: 'object', + properties: { + [uid()]: { + type: 'void', + 'x-component': 'DragAndDrop', + properties: { + [uid()]: { + type: 'void', + 'x-component': 'AddNew', + } + } + }, + }, }; export default () => { @@ -28,16 +44,79 @@ export default () => { } ``` -## 新增表单区块 +### Grid 布局的 AddNew ```tsx import React from 'react'; +import { ISchema } from '@formily/react'; +import { uid } from '@formily/shared'; import { SchemaRenderer } from '../'; -const schema = { +const schema: ISchema = { type: 'void', - name: 'addnew', - 'x-component': 'AddNew.FormItem', + name: uid(), + 'x-component': 'Grid', + properties: { + [`row_${uid()}`]: { + type: 'void', + 'x-component': 'Grid.Row', + properties: { + [`col_${uid()}`]: { + type: 'void', + 'x-component': 'Grid.Col', + 'x-component-props': { + width: 30, + }, + properties: { + [uid()]: { + type: 'void', + 'x-component': 'AddNew', + }, + }, + }, + }, + }, + }, +}; + +export default () => { + return +} +``` + +### Grid 布局的 AddNew.FormItem + +```tsx +import React from 'react'; +import { ISchema } from '@formily/react'; +import { uid } from '@formily/shared'; +import { SchemaRenderer } from '../'; + +const schema: ISchema = { + type: 'void', + name: uid(), + 'x-component': 'Grid', + properties: { + [`row_${uid()}`]: { + type: 'void', + 'x-component': 'Grid.Row', + properties: { + [`col_${uid()}`]: { + type: 'void', + 'x-component': 'Grid.Col', + 'x-component-props': { + width: 30, + }, + properties: { + [uid()]: { + type: 'void', + 'x-component': 'AddNew.FormItem', + }, + }, + }, + }, + }, + }, }; export default () => { diff --git a/packages/client/src/blocks/add-new/index.tsx b/packages/client/src/blocks/add-new/index.tsx index 454d5b413..754319669 100644 --- a/packages/client/src/blocks/add-new/index.tsx +++ b/packages/client/src/blocks/add-new/index.tsx @@ -15,6 +15,7 @@ import { useFieldSchema, RecursionField, Schema, + ISchema, } from '@formily/react'; import { Menu, @@ -26,6 +27,8 @@ import { Modal, Button, Spin, + Switch, + Checkbox, } from 'antd'; import { MenuOutlined, @@ -46,46 +49,84 @@ import { import { useDesignable, useSchemaPath } from '../DesignableSchemaField'; import { uid } from '@formily/shared'; -export const AddNew: any = observer((props) => { - const { schema, insertBefore } = useDesignable(); - const path = useSchemaPath(); - if (schema.parent['x-component'] === 'Grid.Block') { - path.pop(); // block - path.pop(); // col - path.pop(); // row +const generateGridBlock = (schema: ISchema) => { + const name = schema.name || uid(); + return { + type: 'void', + name: uid(), + 'x-component': 'Grid.Row', + properties: { + [uid()]: { + type: 'void', + 'x-component': 'Grid.Col', + properties: { + [name]: schema, + }, + }, + }, + }; +}; + +const isGridBlock = (schema: Schema) => { + if (schema.parent['x-component'] !== 'Grid.Col') { + return false; } + // Grid.Col 里有多少 Block + if (Object.keys(schema.parent.properties).length > 1) { + return false; + } + // 有多少 Grid.Row + if (Object.keys(schema.parent.parent.properties).length > 1) { + return false; + } + return true; +}; + +export const AddNew: any = observer((props: any) => { + const { ghost, defaultAction } = props; + const { schema, insertBefore, insertAfter } = useDesignable(); + const path = useSchemaPath(); + return ( + + + 数据表1 + + + 新增数据表 + + + + 数据表1 + + + 新增数据表 + { - insertBefore({ + let data: ISchema = { type: 'void', - name: uid(), - "x-component": 'Grid.Row', - properties: { - [uid()]: { - type: 'void', - "x-component": 'Grid.Col', - properties: { - [uid()]: { - type: 'void', - "x-component": 'Grid.Block', - properties: { - [uid()]: { - type: 'void', - title: uid(), - 'x-designable-bar': 'FormItem.DesignableBar', - "x-decorator": 'FormItem', - 'x-component': 'Markdown', - } - } - }, - }, - }, - }, - }, [...path]); + title: uid(), + 'x-designable-bar': 'BlockItem.DesignableBar', + 'x-decorator': 'BlockItem', + 'x-component': 'Markdown', + }; + console.log('isGridBlock(schema)', isGridBlock(schema)); + if (isGridBlock(schema)) { + path.pop(); + path.pop(); + data = generateGridBlock(data); + } + if (data) { + if (defaultAction === 'insertAfter') { + insertAfter(data, [...path]); + } else { + insertBefore(data, [...path]); + } + } }} > 新建 Markdown @@ -93,59 +134,85 @@ export const AddNew: any = observer((props) => { } > - + {ghost ? : } ); }); -AddNew.FormItem = observer((props) => { - const { schema, insertBefore } = useDesignable(); +AddNew.FormItem = observer((props: any) => { + const { ghost, defaultAction } = props; + const { schema, insertBefore, insertAfter } = useDesignable(); const path = useSchemaPath(); - if (schema.parent['x-component'] === 'Grid.Block') { - path.pop(); // block - path.pop(); // col - path.pop(); // row - } return ( - { - insertBefore({ - type: 'void', - name: uid(), - "x-component": 'Grid.Row', - properties: { - [uid()]: { - type: 'void', - "x-component": 'Grid.Col', - properties: { - [uid()]: { - type: 'void', - "x-component": 'Grid.Block', - properties: { - [uid()]: { - type: 'void', - title: uid(), - 'x-designable-bar': 'FormItem.DesignableBar', - "x-decorator": 'FormItem', - 'x-component': 'Markdown', - } - } - }, - }, - }, - }, - }, [...path]); - }} - > - 字段 1 - + + { + let data: ISchema = { + type: 'void', + title: uid(), + 'x-designable-bar': 'FormItem.DesignableBar', + 'x-decorator': 'FormItem', + 'x-component': 'Markdown', + }; + if (isGridBlock(schema)) { + path.pop(); + path.pop(); + data = generateGridBlock(data); + } + if (data) { + if (defaultAction === 'insertAfter') { + insertAfter(data, [...path]); + } else { + insertBefore(data, [...path]); + } + } + }} + > + 字段 1 + + + 字段2 + + + 字段3 + + + 字段4 + + + 字段5 + + + 字段6 + + + 字段7 + + + + + + 单行文本 + + 多行文本 + 手机号 + 数字 + 说明文本 + } > - + {ghost ? : } ); }); diff --git a/packages/client/src/blocks/add-new/markdown.ts b/packages/client/src/blocks/add-new/markdown.ts deleted file mode 100644 index f5261165d..000000000 --- a/packages/client/src/blocks/add-new/markdown.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { uid } from '@formily/shared'; - -export default () => ({ - name: `markdown_${uid()}`, - type: 'string', - 'x-component': 'Markdown', - 'x-component-props': {}, -}); diff --git a/packages/client/src/blocks/add-new/table.ts b/packages/client/src/blocks/add-new/table.ts deleted file mode 100644 index 48ddac372..000000000 --- a/packages/client/src/blocks/add-new/table.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { uid } from '@formily/shared'; - -export default () => ({ - name: `t_${uid()}`, - type: 'array', - 'x-component': 'Table', - default: [{ field1: 'a', field2: 'b' }, { field1: 'a', field2: 'b' }], - 'x-component-props': {}, - properties: { - [`a_${uid()}`]: { - type: 'void', - 'x-component': 'Table.ActionBar', - properties: { - action1: { - type: 'object', - title: '按钮1', - 'x-component': 'Table.BulkAction.Popover', - 'x-component-props': {}, - properties: {}, - }, - action2: { - type: 'void', - title: '按钮2', - 'x-component': 'Table.BulkAction', - 'x-component-props': {}, - }, - }, - }, - [`a_${uid()}`]: { - type: 'void', - 'x-component': 'Table.ActionBar', - 'x-component-props': { - align: 'bottom', - }, - properties: { - pagination: { - type: 'void', - 'x-component': 'Table.Pagination', - 'x-component-props': { - defaultCurrent: 1, - total: 50, - }, - }, - }, - }, - [`c_${uid()}`]: { - type: 'void', - title: '字段1', - 'x-component': 'Table.Column', - 'x-component-props': { - title: 'z1', - width: 100, - // DesignableBar: 'Table.Column.DesignableBar', - }, - 'x-designable-bar': 'Table.Column.DesignableBar', - properties: { - field1: { - type: 'string', - required: true, - 'x-decorator-props': { - feedbackLayout: 'popover', - }, - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - }, - }, - [`c_${uid()}`]: { - type: 'void', - title: '字段2', - 'x-component': 'Table.Column', - properties: { - field2: { - type: 'string', - title: '字段2', - required: true, - 'x-decorator-props': { - feedbackLayout: 'popover', - }, - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - }, - }, - }, -}); \ No newline at end of file diff --git a/packages/client/src/blocks/block-item/index.tsx b/packages/client/src/blocks/block-item/index.tsx new file mode 100644 index 000000000..5fa1f5c2d --- /dev/null +++ b/packages/client/src/blocks/block-item/index.tsx @@ -0,0 +1,172 @@ +import React, { createContext, useContext, useState } from 'react'; +import { + connect, + mapProps, + mapReadPretty, + observer, + SchemaOptionsContext, + useField, + useFieldSchema, +} from '@formily/react'; +import { FormItem as FormilyFormItem } from '@formily/antd'; +import { Dropdown, Menu, Space } from 'antd'; +import classNames from 'classnames'; +import { MenuOutlined, DragOutlined } from '@ant-design/icons'; +import './style.less'; +import get from 'lodash/get'; +import { GridBlockContext } from '../grid'; +import { uid } from '@formily/shared'; +import { useDesignable, useSchemaPath } from '../DesignableSchemaField'; +import { AddNew } from '../add-new'; +import { Card } from 'antd'; +import { + mergeRefs, + DraggableBlockContext, + useBlockDragAndDrop, + useDragDropUID, +} from '../../components/drag-and-drop'; +import cls from 'classnames'; + +function Blank() { + return null; +} + +function useDesignableBar() { + const schema = useFieldSchema(); + const options = useContext(SchemaOptionsContext); + const DesignableBar = get(options.components, schema['x-designable-bar']); + + return { + DesignableBar: DesignableBar || Blank, + }; +} + +const DraggableBlock = (props) => { + const { children, ...others } = props; + const { DesignableBar } = useDesignableBar(); + const { isDragging, dragRef, previewRef, isOver, onTopHalf, dropRef } = + useBlockDragAndDrop(); + const schema = useFieldSchema(); + const [active, setActive] = useState(false); + return ( + +
{ + setActive(true); + console.log('e.onMouseEnter', new Date().toString()); + }} + onMouseMove={(event) => { + let dropElement = document.elementFromPoint( + event.clientX, + event.clientY, + ); + const dropIds = []; + while (dropElement) { + if (!dropElement.getAttribute) { + dropElement = dropElement.parentNode as HTMLElement; + continue; + } + const dropId = dropElement.getAttribute('data-drop-id'); + if (dropId) { + dropIds.push(dropId); + } + // if (dropId && dropId !== schema.name) { + // setActive(false); + // break; + // } + dropElement = dropElement.parentNode as HTMLElement; + } + if (dropIds.length > 0) { + setActive(dropIds[0] === schema.name); + } + console.log('e.onMouseMove', dropIds, schema.name); + }} + onMouseLeave={(e) => { + setActive(false); + console.log('e.onMouseLeave', new Date().toString()); + }} + ref={mergeRefs([previewRef, dropRef])} + className={cls('nb-grid-block', 'designable-form-item', { + 'top-half': onTopHalf, + hover: isOver, + active, + dragging: isDragging, + })} + style={{ marginBottom: 24 }} + > + {children} + +
+
+ ); +}; + +const Block = (props) => { + return ( +
+ {props.children} +
+ ); +}; + +export const BlockItem: any = observer((props) => { + const uid = useDragDropUID(); + return React.createElement(uid ? DraggableBlock : Block, props); +}); + +// export const BlockItem: any = connect((props) => { +// const { children, ...others } = props; +// const { DesignableBar } = useDesignableBar(); +// return ( +//
+// {children} +// +//
+// ); +// }); + +BlockItem.DesignableBar = () => { + const field = useField(); + const { schema, refresh } = useDesignable(); + const [visible, setVisible] = useState(false); + const { dragRef } = useContext(DraggableBlockContext); + return ( +
+ { + e.stopPropagation(); + }} + className={classNames('designable-bar-actions', { active: visible })} + > + + + {dragRef && } + { + setVisible(visible); + }} + overlay={ + + { + const title = uid(); + schema.title = title; + field.title = title; + setVisible(false); + refresh(); + }} + > + 点击修改按钮文案 + + + } + > + + + + +
+ ); +}; diff --git a/packages/client/src/blocks/block-item/style.less b/packages/client/src/blocks/block-item/style.less new file mode 100644 index 000000000..668fc5808 --- /dev/null +++ b/packages/client/src/blocks/block-item/style.less @@ -0,0 +1,43 @@ +.designable-form-item { + position: relative; + &.active { + > .designable-bar { + display: block; + } + } + > .designable-bar { + z-index: 1; + pointer-events: none; + display: none; + position: absolute; + top: 0; + right: -0; + left: -0; + bottom: -0; + border-radius: 2px; + border: 2px solid #1890ff; + &.active { + display: block; + } + .designable-bar-actions { + pointer-events: auto; + position: absolute; + right: 0; + line-height: 1rem; + color: #fff; + z-index: 10; + padding: 0 3px; + .ant-space { + gap: 1px !important; + } + .anticon { + width: 16px; + height: 16px; + vertical-align: top; + line-height: 16px; + font-size: 10px; + background-color: #1890ff; + } + } + } +} \ No newline at end of file diff --git a/packages/client/src/blocks/drag-and-drop/index.tsx b/packages/client/src/blocks/drag-and-drop/index.tsx new file mode 100644 index 000000000..61e446699 --- /dev/null +++ b/packages/client/src/blocks/drag-and-drop/index.tsx @@ -0,0 +1,16 @@ + +import React from 'react'; +import { observer, useFieldSchema } from '@formily/react'; +import { + DragDropManagerProvider, +} from './../../components/drag-and-drop'; + +export const DragAndDrop = observer((props) => { + const schema = useFieldSchema(); + console.log('DragAndDrop') + return ( + +
{props.children}
+
+ ) +}); diff --git a/packages/client/src/blocks/form-item/index.tsx b/packages/client/src/blocks/form-item/index.tsx index fde6721f4..d8c9bcf6f 100644 --- a/packages/client/src/blocks/form-item/index.tsx +++ b/packages/client/src/blocks/form-item/index.tsx @@ -1,37 +1,31 @@ import React, { useContext, useState } from 'react'; -import { connect, mapProps, mapReadPretty, SchemaOptionsContext, useField, useFieldSchema } from '@formily/react'; +import { + connect, + mapProps, + mapReadPretty, + observer, + SchemaOptionsContext, + useField, + useFieldSchema, +} from '@formily/react'; import { FormItem as FormilyFormItem } from '@formily/antd'; import { Dropdown, Menu, Space } from 'antd'; import classNames from 'classnames'; import { MenuOutlined, DragOutlined } from '@ant-design/icons'; -import './style.less'; +// import './style.less'; import get from 'lodash/get'; import { GridBlockContext } from '../grid'; import { uid } from '@formily/shared'; import { useDesignable } from '../DesignableSchemaField'; - -function Blank() { - return null; -} - -function useDesignableBar() { - const schema = useFieldSchema(); - const options = useContext(SchemaOptionsContext); - const DesignableBar = get(options.components, schema['x-designable-bar']); - - return { - DesignableBar: DesignableBar || Blank, - }; -} +import { AddNew } from '../add-new'; +import { BlockItem } from '../block-item'; +import { DraggableBlockContext } from '../../components/drag-and-drop'; export const FormItem: any = connect((props) => { - const { DesignableBar } = useDesignableBar(); return ( -
+ - {/* {dragRef &&
Drag
} */} - -
+ ); }); @@ -39,7 +33,7 @@ FormItem.DesignableBar = () => { const field = useField(); const { schema, refresh } = useDesignable(); const [visible, setVisible] = useState(false); - const { dragRef } = useContext(GridBlockContext); + const { dragRef } = useContext(DraggableBlockContext); return (
{ className={classNames('designable-bar-actions', { active: visible })} > - - { - setVisible(visible); - }} - overlay={ - - { - const title = uid(); - schema.title = title; - field.title = title; - setVisible(false); - refresh(); - }} - > - 点击修改按钮文案 - - - } - > - - + + {dragRef && } + { + setVisible(visible); + }} + overlay={ + + { + const title = uid(); + schema.title = title; + field.title = title; + setVisible(false); + refresh(); + }} + > + 点击修改按钮文案 + + + } + > + +
diff --git a/packages/client/src/blocks/form/DesignableBar.tsx b/packages/client/src/blocks/form/DesignableBar.tsx deleted file mode 100644 index 9cf72c589..000000000 --- a/packages/client/src/blocks/form/DesignableBar.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import React, { useState } from 'react'; -import classNames from 'classnames'; -import { useField, observer, RecursionField, Schema } from '@formily/react'; -import { Dropdown, Menu } from 'antd'; -import { - MenuOutlined, - ArrowUpOutlined, - ArrowDownOutlined, - DeleteOutlined, -} from '@ant-design/icons'; - -export const DesignableBar = (props) => { - const [active, setActive] = useState(false); - return ( - <> - { - setActive(false); - }} - icon={} - > - 在上方插入区块 - - { - setActive(false); - }} - icon={} - > - 在下方插入区块 - - - { - setActive(false); - }} - icon={} - > - 删除区块 - - - ); -}; diff --git a/packages/client/src/blocks/form/index.md b/packages/client/src/blocks/form/index.md index 8baa76e7f..e86fbddb5 100644 --- a/packages/client/src/blocks/form/index.md +++ b/packages/client/src/blocks/form/index.md @@ -57,162 +57,45 @@ export default () => { ```tsx import React from 'react'; import { SchemaRenderer } from '../'; +import { uid } from '@formily/shared'; const schema = { type: 'void', - name: 'item3', + name: uid(), 'x-decorator': 'Card', 'x-component': 'Form', properties: { - grid: { + [uid()]: { type: 'void', - title: 'aa', 'x-component': 'Grid', properties: { - row1: { + [`row_${uid()}`]: { type: 'void', 'x-component': 'Grid.Row', properties: { - col1: { + [`col_${uid()}`]: { type: 'void', 'x-component': 'Grid.Col', - 'x-component-props': { - size: 1 / 2, - }, properties: { - block11: { - type: 'void', - 'x-component': 'Grid.Block', - 'x-component-props': { - title: 'block11', - }, - properties: { - field1: { - type: 'string', - required: true, - title: '字段1', - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - }, + [`block_${uid()}`]: { + type: 'string', + required: true, + title: '字段1', + 'x-decorator': 'FormItem', + 'x-component': 'Input', }, }, }, - col2: { + [`col_${uid()}`]: { type: 'void', 'x-component': 'Grid.Col', - 'x-component-props': { - size: 1 / 2, - isLast: true, - }, properties: { - block21: { - type: 'void', - 'x-component': 'Grid.Block', - 'x-component-props': { - title: 'block21', - }, - properties: { - field2: { - type: 'string', - required: true, - title: '字段2', - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - }, - }, - }, - }, - }, - }, - row2: { - type: 'void', - 'x-component': 'Grid.Row', - properties: { - col21: { - type: 'void', - 'x-component': 'Grid.Col', - 'x-component-props': { - size: 1 / 3, - }, - properties: { - block211: { - type: 'void', - 'x-component': 'Grid.Block', - 'x-component-props': { - title: 'block211', - }, - properties: { - field3: { - type: 'string', - required: true, - title: '字段3', - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - }, - }, - }, - }, - col22: { - type: 'void', - 'x-component': 'Grid.Col', - 'x-component-props': { - size: 2 / 3, - isLast: true, - }, - properties: { - block221: { - type: 'void', - 'x-component': 'Grid.Block', - 'x-component-props': { - title: 'block221', - }, - properties: { - field4: { - type: 'string', - required: true, - title: '字段4', - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - }, - }, - }, - }, - }, - }, - row3: { - type: 'void', - 'x-component': 'Grid.Row', - "x-component-props": { - isLast: true, - }, - properties: { - col31: { - type: 'void', - 'x-component': 'Grid.Col', - 'x-component-props': { - size: 1, - isLast: true, - }, - properties: { - block311: { - type: 'void', - 'x-component': 'Grid.Block', - 'x-component-props': { - title: 'block311', - }, - properties: { - field5: { - type: 'string', - required: true, - title: '字段5', - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - }, + [`block_${uid()}`]: { + type: 'string', + required: true, + title: '字段2', + 'x-decorator': 'FormItem', + 'x-component': 'Input', }, }, }, @@ -271,192 +154,44 @@ import { uid } from '@formily/shared'; const schema = { type: 'void', - name: `form_${uid()}`, + name: uid(), 'x-decorator': 'Card', 'x-component': 'Form', + 'x-designable-bar': 'Form.DesignableBar', properties: { - grid: { + [uid()]: { type: 'void', 'x-component': 'Grid', properties: { - row1: { + [`row_${uid()}`]: { type: 'void', 'x-component': 'Grid.Row', properties: { - col1: { + [`col_${uid()}`]: { type: 'void', 'x-component': 'Grid.Col', - 'x-component-props': { - size: 1 / 2, - }, properties: { - block11: { - type: 'void', - 'x-component': 'Grid.Block', - 'x-component-props': { - title: 'block11', - }, - 'x-designable-bar': 'Input.DesignableBar', - properties: { - field1: { - type: 'string', - required: true, - title: '字段1', - 'x-designable-bar': 'FormItem.DesignableBar', - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - }, + [`block_${uid()}`]: { + type: 'string', + required: true, + title: '字段1', + 'x-decorator': 'FormItem', + 'x-designable-bar': 'FormItem.DesignableBar', + 'x-component': 'Input', }, }, }, - col2: { + [`col_${uid()}`]: { type: 'void', 'x-component': 'Grid.Col', - 'x-component-props': { - size: 1 / 2, - isLast: true, - }, properties: { - block21: { - type: 'void', - 'x-component': 'Grid.Block', - 'x-component-props': { - title: 'block21', - }, - 'x-designable-bar': 'Input.DesignableBar', - properties: { - field2: { - type: 'string', - required: true, - title: '字段2', - 'x-designable-bar': 'FormItem.DesignableBar', - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - }, - }, - }, - }, - }, - }, - row2: { - type: 'void', - 'x-component': 'Grid.Row', - properties: { - col21: { - type: 'void', - 'x-component': 'Grid.Col', - 'x-component-props': { - size: 1 / 3, - }, - properties: { - block211: { - type: 'void', - 'x-component': 'Grid.Block', - 'x-component-props': { - title: 'block211', - }, - 'x-designable-bar': 'Input.DesignableBar', - properties: { - field3: { - type: 'string', - required: true, - title: '字段3', - 'x-designable-bar': 'FormItem.DesignableBar', - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - }, - }, - }, - }, - col22: { - type: 'void', - 'x-component': 'Grid.Col', - 'x-component-props': { - size: 2 / 3, - isLast: true, - }, - properties: { - block221: { - type: 'void', - 'x-component': 'Grid.Block', - 'x-component-props': { - title: 'block221', - }, - 'x-designable-bar': 'Input.DesignableBar', - properties: { - field4: { - type: 'string', - required: true, - title: '字段4', - 'x-designable-bar': 'FormItem.DesignableBar', - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - }, - }, - }, - }, - }, - }, - row3: { - type: 'void', - 'x-component': 'Grid.Row', - "x-component-props": { - isLast: true, - }, - properties: { - col31: { - type: 'void', - 'x-component': 'Grid.Col', - 'x-component-props': { - size: 1, - isLast: true, - }, - properties: { - block311: { - type: 'void', - 'x-component': 'Grid.Block', - 'x-component-props': { - title: 'block311', - }, - properties: { - field5: { - type: 'string', - required: true, - title: '字段5', - 'x-designable-bar': 'FormItem.DesignableBar', - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - }, - }, - }, - }, - }, - }, - [`gr_${uid()}`]: { - type: 'void', - 'x-component': 'Grid.Row', - properties: { - [`gc_${uid()}`]: { - type: 'void', - 'x-component': 'Grid.Col', - 'x-component-props': { - size: 1, - }, - properties: { - [`gb_${uid()}`]: { - type: 'void', - 'x-component': 'Grid.Block', - properties: { - [`gbn_${uid()}`]: { - type: 'void', - 'x-component': 'AddNew.FormItem', - }, - }, + [`block_${uid()}`]: { + type: 'string', + required: true, + title: '字段2', + 'x-decorator': 'FormItem', + 'x-designable-bar': 'FormItem.DesignableBar', + 'x-component': 'Input', }, }, }, @@ -497,7 +232,7 @@ const schema = { }, }, }, -}; +} export default () => { return ( diff --git a/packages/client/src/blocks/form/index.tsx b/packages/client/src/blocks/form/index.tsx index 8cd48f8fc..e6d6ecf72 100644 --- a/packages/client/src/blocks/form/index.tsx +++ b/packages/client/src/blocks/form/index.tsx @@ -1,29 +1,82 @@ -import React, { useMemo } from 'react'; +import React, { useContext, useMemo, useRef, useState } from 'react'; import { createForm } from '@formily/core'; -import { FormProvider, Schema, useFieldSchema } from '@formily/react'; +import { SchemaOptionsContext, Schema, useFieldSchema } from '@formily/react'; import { SchemaRenderer, useDesignable } from '../DesignableSchemaField'; -import { DesignableBar } from './DesignableBar'; +import get from 'lodash/get'; +import { Dropdown, Menu } from 'antd'; +import { + MenuOutlined, + ArrowUpOutlined, + ArrowDownOutlined, + DeleteOutlined, +} from '@ant-design/icons'; +import { useMouseEvents } from 'beautiful-react-hooks'; +import cls from 'classnames'; + +import './style.less'; + +function Blank() { + return null; +} + +function useDesignableBar() { + const schema = useFieldSchema(); + const options = useContext(SchemaOptionsContext); + const DesignableBar = get(options.components, schema['x-designable-bar']); + + return { + DesignableBar: DesignableBar || Blank, + }; +} export const Form = (props) => { const schema = useFieldSchema(); const { schema: designableSchema, refresh } = useDesignable(); - return { - designableSchema.properties = subSchema.properties; - refresh(); - }} schema={schema.toJSON()} onlyRenderProperties/> + const { DesignableBar } = useDesignableBar(); + const ref = useRef(); + const [active, setActive] = useState(false); + const { onMouseEnter, onMouseLeave, onMouseMove } = useMouseEvents(ref); + onMouseEnter((e: React.MouseEvent) => { + setActive(true); + }); - // return ( - // - // - // - // ); + onMouseLeave((e: React.MouseEvent) => { + setActive(false); + }); + + onMouseMove((e: React.MouseEvent) => { + + }); + return ( +
+ { + designableSchema.properties = subSchema.properties; + refresh(); + }} + schema={schema.toJSON()} + onlyRenderProperties + /> + +
+ ); }; -Form.DesignableBar = DesignableBar; +Form.DesignableBar = (props) => { + const { active } = props; + return ( +
+
+ + 表单配置 + + } + > + + +
+
+ ); +}; diff --git a/packages/client/src/blocks/form/style.less b/packages/client/src/blocks/form/style.less new file mode 100644 index 000000000..105993089 --- /dev/null +++ b/packages/client/src/blocks/form/style.less @@ -0,0 +1,45 @@ +.nb-form { + position: relative; + padding: 24px; + margin: -24px; + &.active { + > .designable-bar { + display: block; + } + } + > .designable-bar { + z-index: 1; + pointer-events: none; + display: none; + position: absolute; + top: 0; + right: -0; + left: -0; + bottom: -0; + border-radius: 2px; + border: 2px solid #1890ff; + &.active { + display: block; + } + .designable-bar-actions { + pointer-events: auto; + position: absolute; + right: 0; + line-height: 1rem; + color: #fff; + z-index: 10; + padding: 0 3px; + .ant-space { + gap: 1px !important; + } + .anticon { + width: 16px; + height: 16px; + vertical-align: top; + line-height: 16px; + font-size: 10px; + background-color: #1890ff; + } + } + } +} \ No newline at end of file diff --git a/packages/client/src/blocks/grid/demos/demo1.tsx b/packages/client/src/blocks/grid/demos/demo1.tsx index 7965d61ef..cd09f364b 100644 --- a/packages/client/src/blocks/grid/demos/demo1.tsx +++ b/packages/client/src/blocks/grid/demos/demo1.tsx @@ -8,12 +8,7 @@ import { RecursionField, useField, } from '@formily/react'; -import { Input } from '../../input'; -import { FormItem } from '../../form-item'; -import { createDesignableSchemaField } from '../../DesignableSchemaField'; -import { createForm } from '@formily/core'; -import { Grid } from '../'; -import { Card } from 'antd'; +import { SchemaRenderer } from '../../'; const schema: ISchema = { type: 'void', @@ -31,31 +26,19 @@ const schema: ISchema = { width: 30, }, properties: { - [`block_${uid()}`]: { - type: 'void', - 'x-component': 'Grid.Block', - properties: { - [uid()]: { - type: 'string', - title: uid(), - 'x-designable-bar': 'FormItem.DesignableBar', - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - }, + [uid()]: { + type: 'string', + title: uid(), + 'x-designable-bar': 'FormItem.DesignableBar', + 'x-decorator': 'FormItem', + 'x-component': 'Input', }, - [`block_${uid()}`]: { - type: 'void', - 'x-component': 'Grid.Block', - properties: { - [uid()]: { - type: 'string', - title: uid(), - 'x-designable-bar': 'FormItem.DesignableBar', - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - }, + [uid()]: { + type: 'string', + title: uid(), + 'x-designable-bar': 'FormItem.DesignableBar', + 'x-decorator': 'FormItem', + 'x-component': 'Input', }, }, }, @@ -66,18 +49,12 @@ const schema: ISchema = { width: 70, }, properties: { - [`block_${uid()}`]: { - type: 'void', - 'x-component': 'Grid.Block', - properties: { - [uid()]: { - type: 'string', - title: uid(), - 'x-designable-bar': 'FormItem.DesignableBar', - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - }, + [uid()]: { + type: 'string', + title: uid(), + 'x-designable-bar': 'FormItem.DesignableBar', + 'x-decorator': 'FormItem', + 'x-component': 'Input', }, }, }, @@ -91,18 +68,12 @@ const schema: ISchema = { type: 'void', 'x-component': 'Grid.Col', properties: { - [`block_${uid()}`]: { - type: 'void', - 'x-component': 'Grid.Block', - properties: { - [uid()]: { - type: 'string', - title: uid(), - 'x-designable-bar': 'FormItem.DesignableBar', - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - }, + [uid()]: { + type: 'string', + title: uid(), + 'x-designable-bar': 'FormItem.DesignableBar', + 'x-decorator': 'FormItem', + 'x-component': 'Input', }, }, }, @@ -116,14 +87,15 @@ const schema: ISchema = { type: 'void', 'x-component': 'Grid.Col', properties: { - [`block_${uid()}`]: { + [uid()]: { type: 'void', - 'x-component': 'Grid.Block', + name: uid(), + 'x-decorator': 'FormItem', + 'x-designable-bar': 'FormItem.DesignableBar', + 'x-component': 'Card', properties: { [uid()]: { type: 'void', - name: uid(), - 'x-decorator': 'Card', 'x-component': 'Grid', properties: { [`row_${uid()}`]: { @@ -137,18 +109,12 @@ const schema: ISchema = { width: 30, }, properties: { - [`block_${uid()}`]: { - type: 'void', - 'x-component': 'Grid.Block', - properties: { - [uid()]: { - type: 'string', - title: uid(), - 'x-designable-bar': 'FormItem.DesignableBar', - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - }, + [uid()]: { + type: 'string', + title: uid(), + 'x-designable-bar': 'FormItem.DesignableBar', + 'x-decorator': 'FormItem', + 'x-component': 'Input', }, }, }, @@ -159,18 +125,12 @@ const schema: ISchema = { width: 70, }, properties: { - [`block_${uid()}`]: { - type: 'void', - 'x-component': 'Grid.Block', - properties: { - [uid()]: { - type: 'string', - title: uid(), - 'x-designable-bar': 'FormItem.DesignableBar', - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - }, + [uid()]: { + type: 'string', + title: uid(), + 'x-designable-bar': 'FormItem.DesignableBar', + 'x-decorator': 'FormItem', + 'x-component': 'Input', }, }, }, @@ -184,18 +144,12 @@ const schema: ISchema = { type: 'void', 'x-component': 'Grid.Col', properties: { - [`block_${uid()}`]: { - type: 'void', - 'x-component': 'Grid.Block', - properties: { - [uid()]: { - type: 'string', - title: uid(), - 'x-designable-bar': 'FormItem.DesignableBar', - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - }, + [uid()]: { + type: 'string', + title: uid(), + 'x-designable-bar': 'FormItem.DesignableBar', + 'x-decorator': 'FormItem', + 'x-component': 'Input', }, }, }, @@ -209,18 +163,12 @@ const schema: ISchema = { type: 'void', 'x-component': 'Grid.Col', properties: { - [`block_${uid()}`]: { - type: 'void', - 'x-component': 'Grid.Block', - properties: { - [uid()]: { - type: 'string', - title: uid(), - 'x-designable-bar': 'FormItem.DesignableBar', - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - }, + [uid()]: { + type: 'string', + title: uid(), + 'x-designable-bar': 'FormItem.DesignableBar', + 'x-decorator': 'FormItem', + 'x-component': 'Input', }, }, }, @@ -237,26 +185,8 @@ const schema: ISchema = { }, }; -const DesignableSchemaField = createDesignableSchemaField({ - components: { - Grid, - Input, - FormItem, - Card, - }, -}); - -const form = createForm(); - export default () => { return ( - - - + ); }; diff --git a/packages/client/src/blocks/grid/index.md b/packages/client/src/blocks/grid/index.md index f1579299f..8b8f08a3c 100644 --- a/packages/client/src/blocks/grid/index.md +++ b/packages/client/src/blocks/grid/index.md @@ -73,4 +73,4 @@ group: - 100% - \ No newline at end of file + diff --git a/packages/client/src/blocks/grid/index.tsx b/packages/client/src/blocks/grid/index.tsx index 44ae41ab2..6698260f9 100644 --- a/packages/client/src/blocks/grid/index.tsx +++ b/packages/client/src/blocks/grid/index.tsx @@ -22,13 +22,14 @@ import './style.less'; import cls from 'classnames'; import { useDesignable, useSchemaPath } from '../DesignableSchemaField'; -import { DragDropManagerProvider, useColResizer } from './hooks'; -import { useDrag, useDrop, mergeRefs } from './hooks'; - -export const GridContext = createContext({ - ref: null, - gridName: null, -}); +import { + useDrag, + useDrop, + mergeRefs, + useColResizer, + useDragDropUID, + DragDropManagerProvider, +} from './../../components/drag-and-drop'; const ColumnSizeContext = createContext(null); @@ -37,10 +38,10 @@ export const GridBlockContext = createContext({ }); const RowDivider = ({ name, onDrop }) => { - const { gridName } = useContext(GridContext); + const uid = useDragDropUID(); const { isOver, dropRef } = useDrop({ uid: `row_divider_${name}`, - accept: gridName, + accept: uid, shallow: true, onDrop, }); @@ -54,11 +55,11 @@ const RowDivider = ({ name, onDrop }) => { const ColDivider = (props: any) => { const { name, onDragEnd, resizable, onDrop } = props; - const { gridName } = useContext(GridContext); + const uid = useDragDropUID(); const { isDragging, dragRef } = useColResizer({ onDragEnd }); const { isOver, dropRef } = useDrop({ uid: `col_divider_${name}`, - accept: gridName, + accept: uid, shallow: true, onDrop, }); @@ -87,67 +88,65 @@ export const Grid: any = observer((props) => { deepRemove, } = useDesignable(); return ( - - -
- { - const blockSchema = e.dragItem.schema; - const path = [...e.dragItem.path]; - prepend({ - type: 'void', - 'x-component': 'Grid.Row', - properties: { - [uid()]: { - type: 'void', - 'x-component': 'Grid.Col', - properties: { - [blockSchema.name]: blockSchema, - }, + +
+ { + const blockSchema = e.dragItem.schema; + const path = [...e.dragItem.path]; + prepend({ + type: 'void', + 'x-component': 'Grid.Row', + properties: { + [uid()]: { + type: 'void', + 'x-component': 'Grid.Col', + properties: { + [blockSchema.name]: blockSchema, }, }, - }); - deepRemove(path); - }} - /> - {schema.mapProperties((property, key, index) => { - return ( - <> -
- -
- { - const blockSchema = e.dragItem.schema; - const path = [...e.dragItem.path]; - insertAfter( - { - type: 'void', - 'x-component': 'Grid.Row', - properties: { - [uid()]: { - type: 'void', - 'x-component': 'Grid.Col', - properties: { - [blockSchema.name]: blockSchema, - }, + }, + }); + deepRemove(path); + }} + /> + {schema.mapProperties((property, key, index) => { + return ( + <> +
+ +
+ { + const blockSchema = e.dragItem.schema; + const path = [...e.dragItem.path]; + insertAfter( + { + type: 'void', + 'x-component': 'Grid.Row', + properties: { + [uid()]: { + type: 'void', + 'x-component': 'Grid.Col', + properties: { + [blockSchema.name]: blockSchema, }, }, }, - [...gridPath, key], - ); - deepRemove(path); - }} - /> - - ); - })} -
- + }, + [...gridPath, key], + ); + deepRemove(path); + }} + /> + + ); + })} +
); }); @@ -244,52 +243,44 @@ Grid.Col = observer((props) => { ); }); -Grid.Block = observer((props) => { - const schema = useFieldSchema(); - const ctx = useContext(GridContext); - const path = useSchemaPath(); - const { isDragging, dragRef, previewRef } = useDrag({ - type: ctx.gridName, - onDragStart() { - console.log('onDragStart'); - }, - onDragEnd(event) { - console.log('onDragEnd', event.data); - }, - onDrag(event) { - // console.log('onDrag'); - }, - item: { - path, - schema: schema.toJSON(), - }, - }); - const { isOver, onTopHalf, dropRef } = useDrop({ - uid: schema.name, - accept: ctx.gridName, - data: {}, - canDrop: !isDragging, - }); - useEffect(() => { - if (ctx.ref && ctx.ref.current) { - (ctx.ref.current as HTMLElement).className = isDragging - ? 'nb-grid dragging' - : 'nb-grid'; - } - console.log('ctx.ref.current'); - }, [isDragging]); - return ( - -
- {props.children} -
-
- ); -}); +// Grid.Block = observer((props) => { +// const schema = useFieldSchema(); +// const uid = useDragDropUID(); +// const path = useSchemaPath(); +// const { isDragging, dragRef, previewRef } = useDrag({ +// type: uid, +// onDragStart() { +// console.log('onDragStart'); +// }, +// onDragEnd(event) { +// console.log('onDragEnd', event.data); +// }, +// onDrag(event) { +// // console.log('onDrag'); +// }, +// item: { +// path, +// schema: schema.toJSON(), +// }, +// }); +// const { isOver, onTopHalf, dropRef } = useDrop({ +// uid: schema.name, +// accept: uid, +// data: {}, +// canDrop: !isDragging, +// }); +// return ( +// +//
+// {props.children} +//
+//
+// ); +// }); diff --git a/packages/client/src/blocks/grid/style.less b/packages/client/src/blocks/grid/style.less index 28c9930cf..d115c2f39 100644 --- a/packages/client/src/blocks/grid/style.less +++ b/packages/client/src/blocks/grid/style.less @@ -35,8 +35,11 @@ body.dragging { } } -.nb-grid.dragging { +.nb-grid { position: relative; +} + +body.dragging { .nb-grid-col-divider { &.hover { background: #e6f7ff; diff --git a/packages/client/src/blocks/grid/hooks.tsx b/packages/client/src/components/drag-and-drop/index.tsx similarity index 90% rename from packages/client/src/blocks/grid/hooks.tsx rename to packages/client/src/components/drag-and-drop/index.tsx index 495ae5277..9a8a9d3ee 100644 --- a/packages/client/src/blocks/grid/hooks.tsx +++ b/packages/client/src/components/drag-and-drop/index.tsx @@ -1,11 +1,16 @@ import React, { createContext, useContext, useEffect, useRef } from 'react'; import { useState } from 'react'; import { useMouseEvents, useWillUnmount } from 'beautiful-react-hooks'; -import { useField } from '@formily/react'; +import { useField, useFieldSchema } from '@formily/react'; import { useMount } from 'ahooks'; import constate from 'constate'; +import { useSchemaPath } from '../../blocks'; -export function useDragDropManager() { +export const DraggableBlockContext = createContext({ + dragRef: null, +}); + +export function useDragDropManager({ uid }) { const [drag, setDrag] = useState(null); const [drop, setDrop] = useState(null); const [drops, setDrops] = useState({}); @@ -17,19 +22,18 @@ export function useDragDropManager() { const getDrop = (dropId) => { return drops[dropId]; }; - return { drag, drop, drops, setDrag, addDrop, setDrop, getDrop }; + return { uid, drag, drop, drops, setDrag, addDrop, setDrop, getDrop }; } const [DragDropManagerProvider, useDragDropManagerContext] = constate(useDragDropManager); -export { DragDropManagerProvider, useDragDropManagerContext }; +export function useDragDropUID() { + const { uid } = useDragDropManagerContext(); + return uid; +} -// export const DragDropManagerContext = createContext({ -// drag: null, -// drops: {}, -// name: `${Math.random()}`, -// }); +export { DragDropManagerProvider, useDragDropManagerContext }; export function mergeRefs( refs: Array | React.LegacyRef>, @@ -289,7 +293,7 @@ export function useDrop(options) { if (!drag || drag.type !== accept) { return; } - console.log('drag.dropIds', drag.dropIds, dropId) + console.log('drag.dropIds', drag.dropIds, dropId); if (drag.dropIds && drag.dropIds.includes(dropId)) { const top = event.clientY - dropRef.current.getBoundingClientRect().top; const onTop = top < dropRef.current.clientHeight / 2; @@ -380,7 +384,11 @@ export function useColResizer(options?: any) { const els = parent.querySelectorAll(':scope > .nb-grid-col'); const size = []; const gap = dragRef.current.clientWidth; - console.log('parent.clientWidth', parent.clientWidth, dragRef.current.clientWidth ); + console.log( + 'parent.clientWidth', + parent.clientWidth, + dragRef.current.clientWidth, + ); els.forEach((el: HTMLDivElement) => { const w = (100 * el.clientWidth) / parent.clientWidth; const w2 = @@ -411,3 +419,40 @@ export function useColResizer(options?: any) { return { isDragging, dragOffset, dragRef, columns }; } + +export function useBlockDragAndDrop() { + const schema = useFieldSchema(); + const uid = useDragDropUID(); + const path = useSchemaPath(); + const { isDragging, dragRef, previewRef } = useDrag({ + type: uid, + onDragStart() { + console.log('onDragStart'); + }, + onDragEnd(event) { + console.log('onDragEnd', event.data); + }, + onDrag(event) { + // console.log('onDrag'); + }, + item: { + path, + schema: schema.toJSON(), + }, + }); + const { isOver, onTopHalf, dropRef } = useDrop({ + uid: schema.name, + accept: uid, + data: {}, + canDrop: !isDragging, + }); + + return { + isDragging, + dragRef, + previewRef, + isOver, + onTopHalf, + dropRef, + }; +} diff --git a/packages/client/src/index.md b/packages/client/src/index.md index 10c4f416b..c7a0d674e 100644 --- a/packages/client/src/index.md +++ b/packages/client/src/index.md @@ -10,7 +10,7 @@ group: path: /client --- - +