improve code
This commit is contained in:
parent
5e181c3ade
commit
eb31861b54
@ -20,7 +20,7 @@ import { observable } from '@formily/reactive';
|
|||||||
import { uid, clone } from '@formily/shared';
|
import { uid, clone } from '@formily/shared';
|
||||||
import { ArrayCollapse, ArrayTable, FormLayout } from '@formily/antd';
|
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 { Action, useLogin, useRegister, useSubmit } from '../action';
|
||||||
import { AddNew } from '../add-new';
|
import { AddNew } from '../add-new';
|
||||||
import { Cascader } from '../cascader';
|
import { Cascader } from '../cascader';
|
||||||
@ -45,6 +45,8 @@ import { Tabs } from '../tabs';
|
|||||||
import { TimePicker } from '../time-picker';
|
import { TimePicker } from '../time-picker';
|
||||||
import { Upload } from '../upload';
|
import { Upload } from '../upload';
|
||||||
import { FormItem } from '../form-item';
|
import { FormItem } from '../form-item';
|
||||||
|
import { BlockItem } from '../block-item';
|
||||||
|
import { DragAndDrop } from '../drag-and-drop';
|
||||||
|
|
||||||
import { CodeOutlined } from '@ant-design/icons';
|
import { CodeOutlined } from '@ant-design/icons';
|
||||||
import Editor from '@monaco-editor/react';
|
import Editor from '@monaco-editor/react';
|
||||||
@ -60,13 +62,17 @@ export const scope = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const components = {
|
export const components = {
|
||||||
|
Card,
|
||||||
Div,
|
Div,
|
||||||
Space,
|
Space,
|
||||||
Card,
|
|
||||||
|
|
||||||
ArrayCollapse,
|
ArrayCollapse,
|
||||||
ArrayTable,
|
ArrayTable,
|
||||||
FormLayout,
|
FormLayout,
|
||||||
|
|
||||||
|
DragAndDrop,
|
||||||
|
|
||||||
|
BlockItem,
|
||||||
FormItem,
|
FormItem,
|
||||||
|
|
||||||
Action,
|
Action,
|
||||||
@ -171,7 +177,7 @@ export function useDesignable(path?: any) {
|
|||||||
const currentSchema = findPropertyByPath(schema, schemaPath);
|
const currentSchema = findPropertyByPath(schema, schemaPath);
|
||||||
console.log('useDesignable', { schema, schemaPath, currentSchema });
|
console.log('useDesignable', { schema, schemaPath, currentSchema });
|
||||||
return {
|
return {
|
||||||
schema: (currentSchema || {} as any),
|
schema: currentSchema || ({} as Schema),
|
||||||
refresh,
|
refresh,
|
||||||
prepend: (property: ISchema, targetPath?: any): Schema => {
|
prepend: (property: ISchema, targetPath?: any): Schema => {
|
||||||
let target = currentSchema;
|
let target = currentSchema;
|
||||||
@ -192,7 +198,7 @@ export function useDesignable(path?: any) {
|
|||||||
current.parent.removeProperty(current.name);
|
current.parent.removeProperty(current.name);
|
||||||
properties[current.name] = current.toJSON();
|
properties[current.name] = current.toJSON();
|
||||||
});
|
});
|
||||||
console.log({ properties }, target.properties)
|
console.log({ properties }, target.properties);
|
||||||
target.setProperties(properties);
|
target.setProperties(properties);
|
||||||
refresh();
|
refresh();
|
||||||
return target.properties[property.name];
|
return target.properties[property.name];
|
||||||
@ -263,7 +269,6 @@ export function useDesignable(path?: any) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
s.parent.removeProperty(s.name);
|
s.parent.removeProperty(s.name);
|
||||||
console.log('s.parent.properties', s.name, s.parent.properties)
|
|
||||||
if (Object.keys(s.parent.properties || {}).length === 0) {
|
if (Object.keys(s.parent.properties || {}).length === 0) {
|
||||||
remove(s.parent);
|
remove(s.parent);
|
||||||
}
|
}
|
||||||
@ -337,7 +342,12 @@ const CodePreview = ({ schema }) => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<CodeOutlined onClick={() => setVisible(true)} />
|
<CodeOutlined onClick={() => setVisible(true)} />
|
||||||
<Modal width={'50%'} onCancel={() => setVisible(false)} visible={visible}>
|
<Modal
|
||||||
|
width={'50%'}
|
||||||
|
onOk={() => setVisible(false)}
|
||||||
|
onCancel={() => setVisible(false)}
|
||||||
|
visible={visible}
|
||||||
|
>
|
||||||
<Editor
|
<Editor
|
||||||
height="60vh"
|
height="60vh"
|
||||||
defaultLanguage="json"
|
defaultLanguage="json"
|
||||||
|
@ -1,73 +0,0 @@
|
|||||||
import { uid } from '@formily/shared';
|
|
||||||
|
|
||||||
export default () => ({
|
|
||||||
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: '重置',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
title: AddNew - 新增区块
|
title: AddNew - 新增
|
||||||
nav:
|
nav:
|
||||||
title: 组件
|
title: 组件
|
||||||
path: /client
|
path: /client
|
||||||
@ -9,18 +9,34 @@ group:
|
|||||||
path: /client/components
|
path: /client/components
|
||||||
---
|
---
|
||||||
|
|
||||||
# AddNew - 新增区块
|
# AddNew - 新增
|
||||||
|
|
||||||
## 新增普通区块
|
可用于新增区块 AddNew 或表单项 AddNew.FormItem,支持常规布局也支持 Grid 布局。
|
||||||
|
|
||||||
|
## 代码演示
|
||||||
|
|
||||||
|
### 基本使用
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { ISchema } from '@formily/react';
|
||||||
|
import { uid } from '@formily/shared';
|
||||||
import { SchemaRenderer } from '../';
|
import { SchemaRenderer } from '../';
|
||||||
|
|
||||||
const schema = {
|
const schema: ISchema = {
|
||||||
type: 'void',
|
type: 'object',
|
||||||
name: 'addnew',
|
properties: {
|
||||||
'x-component': 'AddNew',
|
[uid()]: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'DragAndDrop',
|
||||||
|
properties: {
|
||||||
|
[uid()]: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'AddNew',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
@ -28,16 +44,79 @@ export default () => {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## 新增表单区块
|
### Grid 布局的 AddNew
|
||||||
|
|
||||||
```tsx
|
```tsx
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { ISchema } from '@formily/react';
|
||||||
|
import { uid } from '@formily/shared';
|
||||||
import { SchemaRenderer } from '../';
|
import { SchemaRenderer } from '../';
|
||||||
|
|
||||||
const schema = {
|
const schema: ISchema = {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
name: 'addnew',
|
name: uid(),
|
||||||
'x-component': 'AddNew.FormItem',
|
'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 <SchemaRenderer schema={schema} />
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 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 () => {
|
export default () => {
|
||||||
|
@ -15,6 +15,7 @@ import {
|
|||||||
useFieldSchema,
|
useFieldSchema,
|
||||||
RecursionField,
|
RecursionField,
|
||||||
Schema,
|
Schema,
|
||||||
|
ISchema,
|
||||||
} from '@formily/react';
|
} from '@formily/react';
|
||||||
import {
|
import {
|
||||||
Menu,
|
Menu,
|
||||||
@ -26,6 +27,8 @@ import {
|
|||||||
Modal,
|
Modal,
|
||||||
Button,
|
Button,
|
||||||
Spin,
|
Spin,
|
||||||
|
Switch,
|
||||||
|
Checkbox,
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
import {
|
import {
|
||||||
MenuOutlined,
|
MenuOutlined,
|
||||||
@ -46,46 +49,84 @@ import {
|
|||||||
import { useDesignable, useSchemaPath } from '../DesignableSchemaField';
|
import { useDesignable, useSchemaPath } from '../DesignableSchemaField';
|
||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
|
|
||||||
export const AddNew: any = observer((props) => {
|
const generateGridBlock = (schema: ISchema) => {
|
||||||
const { schema, insertBefore } = useDesignable();
|
const name = schema.name || uid();
|
||||||
const path = useSchemaPath();
|
return {
|
||||||
if (schema.parent['x-component'] === 'Grid.Block') {
|
type: 'void',
|
||||||
path.pop(); // block
|
name: uid(),
|
||||||
path.pop(); // col
|
'x-component': 'Grid.Row',
|
||||||
path.pop(); // 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 (
|
return (
|
||||||
<Dropdown
|
<Dropdown
|
||||||
overlay={
|
overlay={
|
||||||
<Menu>
|
<Menu>
|
||||||
|
<Menu.SubMenu title={'新建表格'}>
|
||||||
|
<Menu.ItemGroup title={'选择数据表'}>
|
||||||
|
<Menu.Item>数据表1</Menu.Item>
|
||||||
|
</Menu.ItemGroup>
|
||||||
|
<Menu.Divider></Menu.Divider>
|
||||||
|
<Menu.Item>新增数据表</Menu.Item>
|
||||||
|
</Menu.SubMenu>
|
||||||
|
<Menu.SubMenu title={'新建表单'}>
|
||||||
|
<Menu.ItemGroup title={'选择数据表'}>
|
||||||
|
<Menu.Item>数据表1</Menu.Item>
|
||||||
|
</Menu.ItemGroup>
|
||||||
|
<Menu.Divider></Menu.Divider>
|
||||||
|
<Menu.Item>新增数据表</Menu.Item>
|
||||||
|
</Menu.SubMenu>
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
insertBefore({
|
let data: ISchema = {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
name: uid(),
|
title: uid(),
|
||||||
"x-component": 'Grid.Row',
|
'x-designable-bar': 'BlockItem.DesignableBar',
|
||||||
properties: {
|
'x-decorator': 'BlockItem',
|
||||||
[uid()]: {
|
'x-component': 'Markdown',
|
||||||
type: 'void',
|
};
|
||||||
"x-component": 'Grid.Col',
|
console.log('isGridBlock(schema)', isGridBlock(schema));
|
||||||
properties: {
|
if (isGridBlock(schema)) {
|
||||||
[uid()]: {
|
path.pop();
|
||||||
type: 'void',
|
path.pop();
|
||||||
"x-component": 'Grid.Block',
|
data = generateGridBlock(data);
|
||||||
properties: {
|
}
|
||||||
[uid()]: {
|
if (data) {
|
||||||
type: 'void',
|
if (defaultAction === 'insertAfter') {
|
||||||
title: uid(),
|
insertAfter(data, [...path]);
|
||||||
'x-designable-bar': 'FormItem.DesignableBar',
|
} else {
|
||||||
"x-decorator": 'FormItem',
|
insertBefore(data, [...path]);
|
||||||
'x-component': 'Markdown',
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}, [...path]);
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
新建 Markdown
|
新建 Markdown
|
||||||
@ -93,59 +134,85 @@ export const AddNew: any = observer((props) => {
|
|||||||
</Menu>
|
</Menu>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Button icon={<PlusOutlined />}></Button>
|
{ghost ? <PlusOutlined /> : <Button icon={<PlusOutlined />}></Button>}
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
AddNew.FormItem = observer((props) => {
|
AddNew.FormItem = observer((props: any) => {
|
||||||
const { schema, insertBefore } = useDesignable();
|
const { ghost, defaultAction } = props;
|
||||||
|
const { schema, insertBefore, insertAfter } = useDesignable();
|
||||||
const path = useSchemaPath();
|
const path = useSchemaPath();
|
||||||
if (schema.parent['x-component'] === 'Grid.Block') {
|
|
||||||
path.pop(); // block
|
|
||||||
path.pop(); // col
|
|
||||||
path.pop(); // row
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<Dropdown
|
<Dropdown
|
||||||
overlay={
|
overlay={
|
||||||
<Menu>
|
<Menu>
|
||||||
<Menu.Item
|
<Menu.ItemGroup title={'选择已有字段'}>
|
||||||
onClick={() => {
|
<Menu.Item
|
||||||
insertBefore({
|
style={{
|
||||||
type: 'void',
|
minWidth: 150,
|
||||||
name: uid(),
|
}}
|
||||||
"x-component": 'Grid.Row',
|
onClick={() => {
|
||||||
properties: {
|
let data: ISchema = {
|
||||||
[uid()]: {
|
type: 'void',
|
||||||
type: 'void',
|
title: uid(),
|
||||||
"x-component": 'Grid.Col',
|
'x-designable-bar': 'FormItem.DesignableBar',
|
||||||
properties: {
|
'x-decorator': 'FormItem',
|
||||||
[uid()]: {
|
'x-component': 'Markdown',
|
||||||
type: 'void',
|
};
|
||||||
"x-component": 'Grid.Block',
|
if (isGridBlock(schema)) {
|
||||||
properties: {
|
path.pop();
|
||||||
[uid()]: {
|
path.pop();
|
||||||
type: 'void',
|
data = generateGridBlock(data);
|
||||||
title: uid(),
|
}
|
||||||
'x-designable-bar': 'FormItem.DesignableBar',
|
if (data) {
|
||||||
"x-decorator": 'FormItem',
|
if (defaultAction === 'insertAfter') {
|
||||||
'x-component': 'Markdown',
|
insertAfter(data, [...path]);
|
||||||
}
|
} else {
|
||||||
}
|
insertBefore(data, [...path]);
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
},
|
}}
|
||||||
},
|
>
|
||||||
}, [...path]);
|
<Checkbox /> 字段 1
|
||||||
}}
|
</Menu.Item>
|
||||||
>
|
<Menu.Item>
|
||||||
字段 1
|
<Checkbox /> 字段2
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
<Menu.Item>
|
||||||
|
<Checkbox /> 字段3
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item>
|
||||||
|
<Checkbox /> 字段4
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item>
|
||||||
|
<Checkbox /> 字段5
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item>
|
||||||
|
<Checkbox /> 字段6
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item>
|
||||||
|
<Checkbox /> 字段7
|
||||||
|
</Menu.Item>
|
||||||
|
</Menu.ItemGroup>
|
||||||
|
<Menu.Divider />
|
||||||
|
<Menu.SubMenu title={'新增字段'}>
|
||||||
|
<Menu.Item
|
||||||
|
style={{
|
||||||
|
minWidth: 150,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
单行文本
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item>多行文本</Menu.Item>
|
||||||
|
<Menu.Item>手机号</Menu.Item>
|
||||||
|
<Menu.Item>数字</Menu.Item>
|
||||||
|
<Menu.Item>说明文本</Menu.Item>
|
||||||
|
</Menu.SubMenu>
|
||||||
</Menu>
|
</Menu>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Button icon={<PlusOutlined />}></Button>
|
{ghost ? <PlusOutlined /> : <Button icon={<PlusOutlined />}></Button>}
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
import { uid } from '@formily/shared';
|
|
||||||
|
|
||||||
export default () => ({
|
|
||||||
name: `markdown_${uid()}`,
|
|
||||||
type: 'string',
|
|
||||||
'x-component': 'Markdown',
|
|
||||||
'x-component-props': {},
|
|
||||||
});
|
|
@ -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',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
172
packages/client/src/blocks/block-item/index.tsx
Normal file
172
packages/client/src/blocks/block-item/index.tsx
Normal file
@ -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 (
|
||||||
|
<DraggableBlockContext.Provider value={{ dragRef }}>
|
||||||
|
<div
|
||||||
|
onMouseEnter={(e) => {
|
||||||
|
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}
|
||||||
|
<DesignableBar />
|
||||||
|
</div>
|
||||||
|
</DraggableBlockContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Block = (props) => {
|
||||||
|
return (
|
||||||
|
<div className={cls('nb-grid-block', 'designable-form-item')}>
|
||||||
|
{props.children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
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 (
|
||||||
|
// <div {...others} style={{marginBottom: 24}} className={'designable-form-item'}>
|
||||||
|
// {children}
|
||||||
|
// <DesignableBar />
|
||||||
|
// </div>
|
||||||
|
// );
|
||||||
|
// });
|
||||||
|
|
||||||
|
BlockItem.DesignableBar = () => {
|
||||||
|
const field = useField();
|
||||||
|
const { schema, refresh } = useDesignable();
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
const { dragRef } = useContext(DraggableBlockContext);
|
||||||
|
return (
|
||||||
|
<div className={classNames('designable-bar', { active: visible })}>
|
||||||
|
<span
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
}}
|
||||||
|
className={classNames('designable-bar-actions', { active: visible })}
|
||||||
|
>
|
||||||
|
<Space size={'small'}>
|
||||||
|
<AddNew defaultAction={'insertAfter'} ghost />
|
||||||
|
{dragRef && <DragOutlined ref={dragRef} />}
|
||||||
|
<Dropdown
|
||||||
|
trigger={['click']}
|
||||||
|
visible={visible}
|
||||||
|
onVisibleChange={(visible) => {
|
||||||
|
setVisible(visible);
|
||||||
|
}}
|
||||||
|
overlay={
|
||||||
|
<Menu>
|
||||||
|
<Menu.Item
|
||||||
|
onClick={(e) => {
|
||||||
|
const title = uid();
|
||||||
|
schema.title = title;
|
||||||
|
field.title = title;
|
||||||
|
setVisible(false);
|
||||||
|
refresh();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
点击修改按钮文案
|
||||||
|
</Menu.Item>
|
||||||
|
</Menu>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<MenuOutlined />
|
||||||
|
</Dropdown>
|
||||||
|
</Space>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
43
packages/client/src/blocks/block-item/style.less
Normal file
43
packages/client/src/blocks/block-item/style.less
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
packages/client/src/blocks/drag-and-drop/index.tsx
Normal file
16
packages/client/src/blocks/drag-and-drop/index.tsx
Normal file
@ -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 (
|
||||||
|
<DragDropManagerProvider uid={schema.name}>
|
||||||
|
<div className={'nb-dnd'}>{props.children}</div>
|
||||||
|
</DragDropManagerProvider>
|
||||||
|
)
|
||||||
|
});
|
@ -1,37 +1,31 @@
|
|||||||
import React, { useContext, useState } from 'react';
|
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 { FormItem as FormilyFormItem } from '@formily/antd';
|
||||||
import { Dropdown, Menu, Space } from 'antd';
|
import { Dropdown, Menu, Space } from 'antd';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { MenuOutlined, DragOutlined } from '@ant-design/icons';
|
import { MenuOutlined, DragOutlined } from '@ant-design/icons';
|
||||||
import './style.less';
|
// import './style.less';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import { GridBlockContext } from '../grid';
|
import { GridBlockContext } from '../grid';
|
||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import { useDesignable } from '../DesignableSchemaField';
|
import { useDesignable } from '../DesignableSchemaField';
|
||||||
|
import { AddNew } from '../add-new';
|
||||||
function Blank() {
|
import { BlockItem } from '../block-item';
|
||||||
return null;
|
import { DraggableBlockContext } from '../../components/drag-and-drop';
|
||||||
}
|
|
||||||
|
|
||||||
function useDesignableBar() {
|
|
||||||
const schema = useFieldSchema();
|
|
||||||
const options = useContext(SchemaOptionsContext);
|
|
||||||
const DesignableBar = get(options.components, schema['x-designable-bar']);
|
|
||||||
|
|
||||||
return {
|
|
||||||
DesignableBar: DesignableBar || Blank,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const FormItem: any = connect((props) => {
|
export const FormItem: any = connect((props) => {
|
||||||
const { DesignableBar } = useDesignableBar();
|
|
||||||
return (
|
return (
|
||||||
<div className={'designable-form-item'}>
|
<BlockItem>
|
||||||
<FormilyFormItem {...props} />
|
<FormilyFormItem {...props} />
|
||||||
{/* {dragRef && <div ref={dragRef}>Drag</div>} */}
|
</BlockItem>
|
||||||
<DesignableBar/>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -39,7 +33,7 @@ FormItem.DesignableBar = () => {
|
|||||||
const field = useField();
|
const field = useField();
|
||||||
const { schema, refresh } = useDesignable();
|
const { schema, refresh } = useDesignable();
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const { dragRef } = useContext(GridBlockContext);
|
const { dragRef } = useContext(DraggableBlockContext);
|
||||||
return (
|
return (
|
||||||
<div className={classNames('designable-bar', { active: visible })}>
|
<div className={classNames('designable-bar', { active: visible })}>
|
||||||
<span
|
<span
|
||||||
@ -49,31 +43,32 @@ FormItem.DesignableBar = () => {
|
|||||||
className={classNames('designable-bar-actions', { active: visible })}
|
className={classNames('designable-bar-actions', { active: visible })}
|
||||||
>
|
>
|
||||||
<Space size={'small'}>
|
<Space size={'small'}>
|
||||||
<DragOutlined ref={dragRef} />
|
<AddNew.FormItem defaultAction={'insertAfter'} ghost />
|
||||||
<Dropdown
|
{dragRef && <DragOutlined ref={dragRef} />}
|
||||||
trigger={['click']}
|
<Dropdown
|
||||||
visible={visible}
|
trigger={['click']}
|
||||||
onVisibleChange={(visible) => {
|
visible={visible}
|
||||||
setVisible(visible);
|
onVisibleChange={(visible) => {
|
||||||
}}
|
setVisible(visible);
|
||||||
overlay={
|
}}
|
||||||
<Menu>
|
overlay={
|
||||||
<Menu.Item
|
<Menu>
|
||||||
onClick={(e) => {
|
<Menu.Item
|
||||||
const title = uid();
|
onClick={(e) => {
|
||||||
schema.title = title;
|
const title = uid();
|
||||||
field.title = title;
|
schema.title = title;
|
||||||
setVisible(false);
|
field.title = title;
|
||||||
refresh();
|
setVisible(false);
|
||||||
}}
|
refresh();
|
||||||
>
|
}}
|
||||||
点击修改按钮文案
|
>
|
||||||
</Menu.Item>
|
点击修改按钮文案
|
||||||
</Menu>
|
</Menu.Item>
|
||||||
}
|
</Menu>
|
||||||
>
|
}
|
||||||
<MenuOutlined/>
|
>
|
||||||
</Dropdown>
|
<MenuOutlined />
|
||||||
|
</Dropdown>
|
||||||
</Space>
|
</Space>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -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 (
|
|
||||||
<>
|
|
||||||
<Menu.Item
|
|
||||||
onClick={() => {
|
|
||||||
setActive(false);
|
|
||||||
}}
|
|
||||||
icon={<ArrowUpOutlined />}
|
|
||||||
>
|
|
||||||
在上方插入区块
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Item
|
|
||||||
onClick={() => {
|
|
||||||
setActive(false);
|
|
||||||
}}
|
|
||||||
icon={<ArrowDownOutlined />}
|
|
||||||
>
|
|
||||||
在下方插入区块
|
|
||||||
</Menu.Item>
|
|
||||||
<Menu.Divider />
|
|
||||||
<Menu.Item
|
|
||||||
onClick={() => {
|
|
||||||
setActive(false);
|
|
||||||
}}
|
|
||||||
icon={<DeleteOutlined />}
|
|
||||||
>
|
|
||||||
删除区块
|
|
||||||
</Menu.Item>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
@ -57,162 +57,45 @@ export default () => {
|
|||||||
```tsx
|
```tsx
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { SchemaRenderer } from '../';
|
import { SchemaRenderer } from '../';
|
||||||
|
import { uid } from '@formily/shared';
|
||||||
|
|
||||||
const schema = {
|
const schema = {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
name: 'item3',
|
name: uid(),
|
||||||
'x-decorator': 'Card',
|
'x-decorator': 'Card',
|
||||||
'x-component': 'Form',
|
'x-component': 'Form',
|
||||||
properties: {
|
properties: {
|
||||||
grid: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: 'aa',
|
|
||||||
'x-component': 'Grid',
|
'x-component': 'Grid',
|
||||||
properties: {
|
properties: {
|
||||||
row1: {
|
[`row_${uid()}`]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Grid.Row',
|
'x-component': 'Grid.Row',
|
||||||
properties: {
|
properties: {
|
||||||
col1: {
|
[`col_${uid()}`]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Grid.Col',
|
'x-component': 'Grid.Col',
|
||||||
'x-component-props': {
|
|
||||||
size: 1 / 2,
|
|
||||||
},
|
|
||||||
properties: {
|
properties: {
|
||||||
block11: {
|
[`block_${uid()}`]: {
|
||||||
type: 'void',
|
type: 'string',
|
||||||
'x-component': 'Grid.Block',
|
required: true,
|
||||||
'x-component-props': {
|
title: '字段1',
|
||||||
title: 'block11',
|
'x-decorator': 'FormItem',
|
||||||
},
|
'x-component': 'Input',
|
||||||
properties: {
|
|
||||||
field1: {
|
|
||||||
type: 'string',
|
|
||||||
required: true,
|
|
||||||
title: '字段1',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
col2: {
|
[`col_${uid()}`]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Grid.Col',
|
'x-component': 'Grid.Col',
|
||||||
'x-component-props': {
|
|
||||||
size: 1 / 2,
|
|
||||||
isLast: true,
|
|
||||||
},
|
|
||||||
properties: {
|
properties: {
|
||||||
block21: {
|
[`block_${uid()}`]: {
|
||||||
type: 'void',
|
type: 'string',
|
||||||
'x-component': 'Grid.Block',
|
required: true,
|
||||||
'x-component-props': {
|
title: '字段2',
|
||||||
title: 'block21',
|
'x-decorator': 'FormItem',
|
||||||
},
|
'x-component': 'Input',
|
||||||
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',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -271,192 +154,44 @@ import { uid } from '@formily/shared';
|
|||||||
|
|
||||||
const schema = {
|
const schema = {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
name: `form_${uid()}`,
|
name: uid(),
|
||||||
'x-decorator': 'Card',
|
'x-decorator': 'Card',
|
||||||
'x-component': 'Form',
|
'x-component': 'Form',
|
||||||
|
'x-designable-bar': 'Form.DesignableBar',
|
||||||
properties: {
|
properties: {
|
||||||
grid: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Grid',
|
'x-component': 'Grid',
|
||||||
properties: {
|
properties: {
|
||||||
row1: {
|
[`row_${uid()}`]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Grid.Row',
|
'x-component': 'Grid.Row',
|
||||||
properties: {
|
properties: {
|
||||||
col1: {
|
[`col_${uid()}`]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Grid.Col',
|
'x-component': 'Grid.Col',
|
||||||
'x-component-props': {
|
|
||||||
size: 1 / 2,
|
|
||||||
},
|
|
||||||
properties: {
|
properties: {
|
||||||
block11: {
|
[`block_${uid()}`]: {
|
||||||
type: 'void',
|
type: 'string',
|
||||||
'x-component': 'Grid.Block',
|
required: true,
|
||||||
'x-component-props': {
|
title: '字段1',
|
||||||
title: 'block11',
|
'x-decorator': 'FormItem',
|
||||||
},
|
'x-designable-bar': 'FormItem.DesignableBar',
|
||||||
'x-designable-bar': 'Input.DesignableBar',
|
'x-component': 'Input',
|
||||||
properties: {
|
|
||||||
field1: {
|
|
||||||
type: 'string',
|
|
||||||
required: true,
|
|
||||||
title: '字段1',
|
|
||||||
'x-designable-bar': 'FormItem.DesignableBar',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
col2: {
|
[`col_${uid()}`]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Grid.Col',
|
'x-component': 'Grid.Col',
|
||||||
'x-component-props': {
|
|
||||||
size: 1 / 2,
|
|
||||||
isLast: true,
|
|
||||||
},
|
|
||||||
properties: {
|
properties: {
|
||||||
block21: {
|
[`block_${uid()}`]: {
|
||||||
type: 'void',
|
type: 'string',
|
||||||
'x-component': 'Grid.Block',
|
required: true,
|
||||||
'x-component-props': {
|
title: '字段2',
|
||||||
title: 'block21',
|
'x-decorator': 'FormItem',
|
||||||
},
|
'x-designable-bar': 'FormItem.DesignableBar',
|
||||||
'x-designable-bar': 'Input.DesignableBar',
|
'x-component': 'Input',
|
||||||
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',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -497,7 +232,7 @@ const schema = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
return (
|
return (
|
||||||
|
@ -1,29 +1,82 @@
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useContext, useMemo, useRef, useState } from 'react';
|
||||||
import { createForm } from '@formily/core';
|
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 { 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) => {
|
export const Form = (props) => {
|
||||||
const schema = useFieldSchema();
|
const schema = useFieldSchema();
|
||||||
const { schema: designableSchema, refresh } = useDesignable();
|
const { schema: designableSchema, refresh } = useDesignable();
|
||||||
return <SchemaRenderer onRefresh={(subSchema: Schema) => {
|
const { DesignableBar } = useDesignableBar();
|
||||||
designableSchema.properties = subSchema.properties;
|
const ref = useRef();
|
||||||
refresh();
|
const [active, setActive] = useState(false);
|
||||||
}} schema={schema.toJSON()} onlyRenderProperties/>
|
const { onMouseEnter, onMouseLeave, onMouseMove } = useMouseEvents(ref);
|
||||||
|
onMouseEnter((e: React.MouseEvent) => {
|
||||||
|
setActive(true);
|
||||||
|
});
|
||||||
|
|
||||||
// return (
|
onMouseLeave((e: React.MouseEvent) => {
|
||||||
// <FormProvider form={form}>
|
setActive(false);
|
||||||
// <DesignableSchemaField
|
});
|
||||||
// schema={{
|
|
||||||
// type: 'object',
|
onMouseMove((e: React.MouseEvent) => {
|
||||||
// properties: {
|
|
||||||
// ...schema,
|
});
|
||||||
// },
|
return (
|
||||||
// }}
|
<div ref={ref} className={'nb-form'}>
|
||||||
// />
|
<SchemaRenderer
|
||||||
// </FormProvider>
|
onRefresh={(subSchema: Schema) => {
|
||||||
// );
|
designableSchema.properties = subSchema.properties;
|
||||||
|
refresh();
|
||||||
|
}}
|
||||||
|
schema={schema.toJSON()}
|
||||||
|
onlyRenderProperties
|
||||||
|
/>
|
||||||
|
<DesignableBar active={active}/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
Form.DesignableBar = DesignableBar;
|
Form.DesignableBar = (props) => {
|
||||||
|
const { active } = props;
|
||||||
|
return (
|
||||||
|
<div className={cls('designable-bar', { active })}>
|
||||||
|
<div className={'designable-bar-actions'}>
|
||||||
|
<Dropdown
|
||||||
|
overlay={
|
||||||
|
<Menu>
|
||||||
|
<Menu.Item>表单配置</Menu.Item>
|
||||||
|
</Menu>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<MenuOutlined />
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
45
packages/client/src/blocks/form/style.less
Normal file
45
packages/client/src/blocks/form/style.less
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,12 +8,7 @@ import {
|
|||||||
RecursionField,
|
RecursionField,
|
||||||
useField,
|
useField,
|
||||||
} from '@formily/react';
|
} from '@formily/react';
|
||||||
import { Input } from '../../input';
|
import { SchemaRenderer } from '../../';
|
||||||
import { FormItem } from '../../form-item';
|
|
||||||
import { createDesignableSchemaField } from '../../DesignableSchemaField';
|
|
||||||
import { createForm } from '@formily/core';
|
|
||||||
import { Grid } from '../';
|
|
||||||
import { Card } from 'antd';
|
|
||||||
|
|
||||||
const schema: ISchema = {
|
const schema: ISchema = {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
@ -31,31 +26,19 @@ const schema: ISchema = {
|
|||||||
width: 30,
|
width: 30,
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
[`block_${uid()}`]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'string',
|
||||||
'x-component': 'Grid.Block',
|
title: uid(),
|
||||||
properties: {
|
'x-designable-bar': 'FormItem.DesignableBar',
|
||||||
[uid()]: {
|
'x-decorator': 'FormItem',
|
||||||
type: 'string',
|
'x-component': 'Input',
|
||||||
title: uid(),
|
|
||||||
'x-designable-bar': 'FormItem.DesignableBar',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
[`block_${uid()}`]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'string',
|
||||||
'x-component': 'Grid.Block',
|
title: uid(),
|
||||||
properties: {
|
'x-designable-bar': 'FormItem.DesignableBar',
|
||||||
[uid()]: {
|
'x-decorator': 'FormItem',
|
||||||
type: 'string',
|
'x-component': 'Input',
|
||||||
title: uid(),
|
|
||||||
'x-designable-bar': 'FormItem.DesignableBar',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -66,18 +49,12 @@ const schema: ISchema = {
|
|||||||
width: 70,
|
width: 70,
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
[`block_${uid()}`]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'string',
|
||||||
'x-component': 'Grid.Block',
|
title: uid(),
|
||||||
properties: {
|
'x-designable-bar': 'FormItem.DesignableBar',
|
||||||
[uid()]: {
|
'x-decorator': 'FormItem',
|
||||||
type: 'string',
|
'x-component': 'Input',
|
||||||
title: uid(),
|
|
||||||
'x-designable-bar': 'FormItem.DesignableBar',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -91,18 +68,12 @@ const schema: ISchema = {
|
|||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Grid.Col',
|
'x-component': 'Grid.Col',
|
||||||
properties: {
|
properties: {
|
||||||
[`block_${uid()}`]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'string',
|
||||||
'x-component': 'Grid.Block',
|
title: uid(),
|
||||||
properties: {
|
'x-designable-bar': 'FormItem.DesignableBar',
|
||||||
[uid()]: {
|
'x-decorator': 'FormItem',
|
||||||
type: 'string',
|
'x-component': 'Input',
|
||||||
title: uid(),
|
|
||||||
'x-designable-bar': 'FormItem.DesignableBar',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -116,14 +87,15 @@ const schema: ISchema = {
|
|||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Grid.Col',
|
'x-component': 'Grid.Col',
|
||||||
properties: {
|
properties: {
|
||||||
[`block_${uid()}`]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Grid.Block',
|
name: uid(),
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-designable-bar': 'FormItem.DesignableBar',
|
||||||
|
'x-component': 'Card',
|
||||||
properties: {
|
properties: {
|
||||||
[uid()]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
name: uid(),
|
|
||||||
'x-decorator': 'Card',
|
|
||||||
'x-component': 'Grid',
|
'x-component': 'Grid',
|
||||||
properties: {
|
properties: {
|
||||||
[`row_${uid()}`]: {
|
[`row_${uid()}`]: {
|
||||||
@ -137,18 +109,12 @@ const schema: ISchema = {
|
|||||||
width: 30,
|
width: 30,
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
[`block_${uid()}`]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'string',
|
||||||
'x-component': 'Grid.Block',
|
title: uid(),
|
||||||
properties: {
|
'x-designable-bar': 'FormItem.DesignableBar',
|
||||||
[uid()]: {
|
'x-decorator': 'FormItem',
|
||||||
type: 'string',
|
'x-component': 'Input',
|
||||||
title: uid(),
|
|
||||||
'x-designable-bar': 'FormItem.DesignableBar',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -159,18 +125,12 @@ const schema: ISchema = {
|
|||||||
width: 70,
|
width: 70,
|
||||||
},
|
},
|
||||||
properties: {
|
properties: {
|
||||||
[`block_${uid()}`]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'string',
|
||||||
'x-component': 'Grid.Block',
|
title: uid(),
|
||||||
properties: {
|
'x-designable-bar': 'FormItem.DesignableBar',
|
||||||
[uid()]: {
|
'x-decorator': 'FormItem',
|
||||||
type: 'string',
|
'x-component': 'Input',
|
||||||
title: uid(),
|
|
||||||
'x-designable-bar': 'FormItem.DesignableBar',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -184,18 +144,12 @@ const schema: ISchema = {
|
|||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Grid.Col',
|
'x-component': 'Grid.Col',
|
||||||
properties: {
|
properties: {
|
||||||
[`block_${uid()}`]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'string',
|
||||||
'x-component': 'Grid.Block',
|
title: uid(),
|
||||||
properties: {
|
'x-designable-bar': 'FormItem.DesignableBar',
|
||||||
[uid()]: {
|
'x-decorator': 'FormItem',
|
||||||
type: 'string',
|
'x-component': 'Input',
|
||||||
title: uid(),
|
|
||||||
'x-designable-bar': 'FormItem.DesignableBar',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -209,18 +163,12 @@ const schema: ISchema = {
|
|||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Grid.Col',
|
'x-component': 'Grid.Col',
|
||||||
properties: {
|
properties: {
|
||||||
[`block_${uid()}`]: {
|
[uid()]: {
|
||||||
type: 'void',
|
type: 'string',
|
||||||
'x-component': 'Grid.Block',
|
title: uid(),
|
||||||
properties: {
|
'x-designable-bar': 'FormItem.DesignableBar',
|
||||||
[uid()]: {
|
'x-decorator': 'FormItem',
|
||||||
type: 'string',
|
'x-component': 'Input',
|
||||||
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 () => {
|
export default () => {
|
||||||
return (
|
return (
|
||||||
<FormProvider form={form}>
|
<SchemaRenderer schema={schema} />
|
||||||
<DesignableSchemaField schema={{
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
[schema.name]: schema,
|
|
||||||
}
|
|
||||||
}} />
|
|
||||||
</FormProvider>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -22,13 +22,14 @@ import './style.less';
|
|||||||
import cls from 'classnames';
|
import cls from 'classnames';
|
||||||
|
|
||||||
import { useDesignable, useSchemaPath } from '../DesignableSchemaField';
|
import { useDesignable, useSchemaPath } from '../DesignableSchemaField';
|
||||||
import { DragDropManagerProvider, useColResizer } from './hooks';
|
import {
|
||||||
import { useDrag, useDrop, mergeRefs } from './hooks';
|
useDrag,
|
||||||
|
useDrop,
|
||||||
export const GridContext = createContext({
|
mergeRefs,
|
||||||
ref: null,
|
useColResizer,
|
||||||
gridName: null,
|
useDragDropUID,
|
||||||
});
|
DragDropManagerProvider,
|
||||||
|
} from './../../components/drag-and-drop';
|
||||||
|
|
||||||
const ColumnSizeContext = createContext(null);
|
const ColumnSizeContext = createContext(null);
|
||||||
|
|
||||||
@ -37,10 +38,10 @@ export const GridBlockContext = createContext({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const RowDivider = ({ name, onDrop }) => {
|
const RowDivider = ({ name, onDrop }) => {
|
||||||
const { gridName } = useContext(GridContext);
|
const uid = useDragDropUID();
|
||||||
const { isOver, dropRef } = useDrop({
|
const { isOver, dropRef } = useDrop({
|
||||||
uid: `row_divider_${name}`,
|
uid: `row_divider_${name}`,
|
||||||
accept: gridName,
|
accept: uid,
|
||||||
shallow: true,
|
shallow: true,
|
||||||
onDrop,
|
onDrop,
|
||||||
});
|
});
|
||||||
@ -54,11 +55,11 @@ const RowDivider = ({ name, onDrop }) => {
|
|||||||
|
|
||||||
const ColDivider = (props: any) => {
|
const ColDivider = (props: any) => {
|
||||||
const { name, onDragEnd, resizable, onDrop } = props;
|
const { name, onDragEnd, resizable, onDrop } = props;
|
||||||
const { gridName } = useContext(GridContext);
|
const uid = useDragDropUID();
|
||||||
const { isDragging, dragRef } = useColResizer({ onDragEnd });
|
const { isDragging, dragRef } = useColResizer({ onDragEnd });
|
||||||
const { isOver, dropRef } = useDrop({
|
const { isOver, dropRef } = useDrop({
|
||||||
uid: `col_divider_${name}`,
|
uid: `col_divider_${name}`,
|
||||||
accept: gridName,
|
accept: uid,
|
||||||
shallow: true,
|
shallow: true,
|
||||||
onDrop,
|
onDrop,
|
||||||
});
|
});
|
||||||
@ -87,67 +88,65 @@ export const Grid: any = observer((props) => {
|
|||||||
deepRemove,
|
deepRemove,
|
||||||
} = useDesignable();
|
} = useDesignable();
|
||||||
return (
|
return (
|
||||||
<DragDropManagerProvider>
|
<DragDropManagerProvider uid={schema.name}>
|
||||||
<GridContext.Provider value={{ ref, gridName: schema.name }}>
|
<div ref={ref} className={'nb-grid'}>
|
||||||
<div ref={ref} className={'nb-grid'}>
|
<RowDivider
|
||||||
<RowDivider
|
key={`${schema.name}_0`}
|
||||||
key={`${schema.name}_0`}
|
name={`${schema.name}_0`}
|
||||||
name={`${schema.name}_0`}
|
onDrop={(e) => {
|
||||||
onDrop={(e) => {
|
const blockSchema = e.dragItem.schema;
|
||||||
const blockSchema = e.dragItem.schema;
|
const path = [...e.dragItem.path];
|
||||||
const path = [...e.dragItem.path];
|
prepend({
|
||||||
prepend({
|
type: 'void',
|
||||||
type: 'void',
|
'x-component': 'Grid.Row',
|
||||||
'x-component': 'Grid.Row',
|
properties: {
|
||||||
properties: {
|
[uid()]: {
|
||||||
[uid()]: {
|
type: 'void',
|
||||||
type: 'void',
|
'x-component': 'Grid.Col',
|
||||||
'x-component': 'Grid.Col',
|
properties: {
|
||||||
properties: {
|
[blockSchema.name]: blockSchema,
|
||||||
[blockSchema.name]: blockSchema,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
deepRemove(path);
|
});
|
||||||
}}
|
deepRemove(path);
|
||||||
/>
|
}}
|
||||||
{schema.mapProperties((property, key, index) => {
|
/>
|
||||||
return (
|
{schema.mapProperties((property, key, index) => {
|
||||||
<>
|
return (
|
||||||
<div style={{ display: 'flex' }} className={'nb-grid-row'}>
|
<>
|
||||||
<RecursionField name={property.name} schema={property} />
|
<div style={{ display: 'flex' }} className={'nb-grid-row'}>
|
||||||
</div>
|
<RecursionField name={property.name} schema={property} />
|
||||||
<RowDivider
|
</div>
|
||||||
key={`${schema.name}_${index + 1}`}
|
<RowDivider
|
||||||
name={`${schema.name}_${index + 1}`}
|
key={`${schema.name}_${index + 1}`}
|
||||||
onDrop={(e) => {
|
name={`${schema.name}_${index + 1}`}
|
||||||
const blockSchema = e.dragItem.schema;
|
onDrop={(e) => {
|
||||||
const path = [...e.dragItem.path];
|
const blockSchema = e.dragItem.schema;
|
||||||
insertAfter(
|
const path = [...e.dragItem.path];
|
||||||
{
|
insertAfter(
|
||||||
type: 'void',
|
{
|
||||||
'x-component': 'Grid.Row',
|
type: 'void',
|
||||||
properties: {
|
'x-component': 'Grid.Row',
|
||||||
[uid()]: {
|
properties: {
|
||||||
type: 'void',
|
[uid()]: {
|
||||||
'x-component': 'Grid.Col',
|
type: 'void',
|
||||||
properties: {
|
'x-component': 'Grid.Col',
|
||||||
[blockSchema.name]: blockSchema,
|
properties: {
|
||||||
},
|
[blockSchema.name]: blockSchema,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
[...gridPath, key],
|
},
|
||||||
);
|
[...gridPath, key],
|
||||||
deepRemove(path);
|
);
|
||||||
}}
|
deepRemove(path);
|
||||||
/>
|
}}
|
||||||
</>
|
/>
|
||||||
);
|
</>
|
||||||
})}
|
);
|
||||||
</div>
|
})}
|
||||||
</GridContext.Provider>
|
</div>
|
||||||
</DragDropManagerProvider>
|
</DragDropManagerProvider>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -244,52 +243,44 @@ Grid.Col = observer((props) => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
Grid.Block = observer((props) => {
|
// Grid.Block = observer((props) => {
|
||||||
const schema = useFieldSchema();
|
// const schema = useFieldSchema();
|
||||||
const ctx = useContext(GridContext);
|
// const uid = useDragDropUID();
|
||||||
const path = useSchemaPath();
|
// const path = useSchemaPath();
|
||||||
const { isDragging, dragRef, previewRef } = useDrag({
|
// const { isDragging, dragRef, previewRef } = useDrag({
|
||||||
type: ctx.gridName,
|
// type: uid,
|
||||||
onDragStart() {
|
// onDragStart() {
|
||||||
console.log('onDragStart');
|
// console.log('onDragStart');
|
||||||
},
|
// },
|
||||||
onDragEnd(event) {
|
// onDragEnd(event) {
|
||||||
console.log('onDragEnd', event.data);
|
// console.log('onDragEnd', event.data);
|
||||||
},
|
// },
|
||||||
onDrag(event) {
|
// onDrag(event) {
|
||||||
// console.log('onDrag');
|
// // console.log('onDrag');
|
||||||
},
|
// },
|
||||||
item: {
|
// item: {
|
||||||
path,
|
// path,
|
||||||
schema: schema.toJSON(),
|
// schema: schema.toJSON(),
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
const { isOver, onTopHalf, dropRef } = useDrop({
|
// const { isOver, onTopHalf, dropRef } = useDrop({
|
||||||
uid: schema.name,
|
// uid: schema.name,
|
||||||
accept: ctx.gridName,
|
// accept: uid,
|
||||||
data: {},
|
// data: {},
|
||||||
canDrop: !isDragging,
|
// canDrop: !isDragging,
|
||||||
});
|
// });
|
||||||
useEffect(() => {
|
// return (
|
||||||
if (ctx.ref && ctx.ref.current) {
|
// <GridBlockContext.Provider value={{ dragRef }}>
|
||||||
(ctx.ref.current as HTMLElement).className = isDragging
|
// <div
|
||||||
? 'nb-grid dragging'
|
// ref={mergeRefs([previewRef, dropRef])}
|
||||||
: 'nb-grid';
|
// className={cls('nb-grid-block', {
|
||||||
}
|
// 'top-half': onTopHalf,
|
||||||
console.log('ctx.ref.current');
|
// hover: isOver,
|
||||||
}, [isDragging]);
|
// dragging: isDragging,
|
||||||
return (
|
// })}
|
||||||
<GridBlockContext.Provider value={{ dragRef }}>
|
// >
|
||||||
<div
|
// {props.children}
|
||||||
ref={mergeRefs([previewRef, dropRef])}
|
// </div>
|
||||||
className={cls('nb-grid-block', {
|
// </GridBlockContext.Provider>
|
||||||
'top-half': onTopHalf,
|
// );
|
||||||
hover: isOver,
|
// });
|
||||||
dragging: isDragging,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
</GridBlockContext.Provider>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
@ -35,8 +35,11 @@ body.dragging {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.nb-grid.dragging {
|
.nb-grid {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.dragging {
|
||||||
.nb-grid-col-divider {
|
.nb-grid-col-divider {
|
||||||
&.hover {
|
&.hover {
|
||||||
background: #e6f7ff;
|
background: #e6f7ff;
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
import React, { createContext, useContext, useEffect, useRef } from 'react';
|
import React, { createContext, useContext, useEffect, useRef } from 'react';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useMouseEvents, useWillUnmount } from 'beautiful-react-hooks';
|
import { useMouseEvents, useWillUnmount } from 'beautiful-react-hooks';
|
||||||
import { useField } from '@formily/react';
|
import { useField, useFieldSchema } from '@formily/react';
|
||||||
import { useMount } from 'ahooks';
|
import { useMount } from 'ahooks';
|
||||||
import constate from 'constate';
|
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 [drag, setDrag] = useState(null);
|
||||||
const [drop, setDrop] = useState(null);
|
const [drop, setDrop] = useState(null);
|
||||||
const [drops, setDrops] = useState({});
|
const [drops, setDrops] = useState({});
|
||||||
@ -17,19 +22,18 @@ export function useDragDropManager() {
|
|||||||
const getDrop = (dropId) => {
|
const getDrop = (dropId) => {
|
||||||
return drops[dropId];
|
return drops[dropId];
|
||||||
};
|
};
|
||||||
return { drag, drop, drops, setDrag, addDrop, setDrop, getDrop };
|
return { uid, drag, drop, drops, setDrag, addDrop, setDrop, getDrop };
|
||||||
}
|
}
|
||||||
|
|
||||||
const [DragDropManagerProvider, useDragDropManagerContext] =
|
const [DragDropManagerProvider, useDragDropManagerContext] =
|
||||||
constate(useDragDropManager);
|
constate(useDragDropManager);
|
||||||
|
|
||||||
export { DragDropManagerProvider, useDragDropManagerContext };
|
export function useDragDropUID() {
|
||||||
|
const { uid } = useDragDropManagerContext();
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
|
|
||||||
// export const DragDropManagerContext = createContext<any>({
|
export { DragDropManagerProvider, useDragDropManagerContext };
|
||||||
// drag: null,
|
|
||||||
// drops: {},
|
|
||||||
// name: `${Math.random()}`,
|
|
||||||
// });
|
|
||||||
|
|
||||||
export function mergeRefs<T = any>(
|
export function mergeRefs<T = any>(
|
||||||
refs: Array<React.MutableRefObject<T> | React.LegacyRef<T>>,
|
refs: Array<React.MutableRefObject<T> | React.LegacyRef<T>>,
|
||||||
@ -289,7 +293,7 @@ export function useDrop(options) {
|
|||||||
if (!drag || drag.type !== accept) {
|
if (!drag || drag.type !== accept) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log('drag.dropIds', drag.dropIds, dropId)
|
console.log('drag.dropIds', drag.dropIds, dropId);
|
||||||
if (drag.dropIds && drag.dropIds.includes(dropId)) {
|
if (drag.dropIds && drag.dropIds.includes(dropId)) {
|
||||||
const top = event.clientY - dropRef.current.getBoundingClientRect().top;
|
const top = event.clientY - dropRef.current.getBoundingClientRect().top;
|
||||||
const onTop = top < dropRef.current.clientHeight / 2;
|
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 els = parent.querySelectorAll(':scope > .nb-grid-col');
|
||||||
const size = [];
|
const size = [];
|
||||||
const gap = dragRef.current.clientWidth;
|
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) => {
|
els.forEach((el: HTMLDivElement) => {
|
||||||
const w = (100 * el.clientWidth) / parent.clientWidth;
|
const w = (100 * el.clientWidth) / parent.clientWidth;
|
||||||
const w2 =
|
const w2 =
|
||||||
@ -411,3 +419,40 @@ export function useColResizer(options?: any) {
|
|||||||
|
|
||||||
return { isDragging, dragOffset, dragRef, columns };
|
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,
|
||||||
|
};
|
||||||
|
}
|
@ -10,7 +10,7 @@ group:
|
|||||||
path: /client
|
path: /client
|
||||||
---
|
---
|
||||||
|
|
||||||
<code src="./demos/demo1.tsx"/>
|
<!-- <code src="./demos/demo1.tsx"/> -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user