diff --git a/packages/client/src/schema-component/antd/action/ActionBar.tsx b/packages/client/src/schema-component/antd/action/ActionBar.tsx
index 41e540263..fc3bb0f1f 100644
--- a/packages/client/src/schema-component/antd/action/ActionBar.tsx
+++ b/packages/client/src/schema-component/antd/action/ActionBar.tsx
@@ -5,7 +5,7 @@ import { useComponent } from '../../hooks';
export const ActionBar = () => {
const fieldSchema = useFieldSchema();
- const Initializer = useComponent(fieldSchema['x-initializer']);
+ const ActionInitializer = useComponent(fieldSchema['x-action-initializer']);
return (
@@ -26,7 +26,7 @@ export const ActionBar = () => {
})}
- {Initializer &&
}
+ {ActionInitializer &&
}
);
};
diff --git a/packages/client/src/schema-component/antd/array-table/ArrayTable.tsx b/packages/client/src/schema-component/antd/array-table/ArrayTable.tsx
index 4d1653940..438214ea8 100644
--- a/packages/client/src/schema-component/antd/array-table/ArrayTable.tsx
+++ b/packages/client/src/schema-component/antd/array-table/ArrayTable.tsx
@@ -11,7 +11,7 @@ const isColumnComponent = (schema: Schema) => {
const useTableColumns = () => {
const field = useField();
const schema = useFieldSchema();
- const Initializer = useComponent(schema['x-initializer']);
+ const Initializer = useComponent(schema['x-column-initializer']);
const columns = schema
.reduceProperties((buf, s) => {
if (isColumnComponent(s)) {
diff --git a/packages/client/src/schema-component/hooks/useDesignable.tsx b/packages/client/src/schema-component/hooks/useDesignable.tsx
index 76756e890..ff5659070 100644
--- a/packages/client/src/schema-component/hooks/useDesignable.tsx
+++ b/packages/client/src/schema-component/hooks/useDesignable.tsx
@@ -332,8 +332,8 @@ export function useDesignable() {
update(key);
refresh();
},
- remove() {
- dn.remove();
+ remove(schema: any, options?: any) {
+ dn.remove(schema, options);
},
insertAdjacent(position: Position, schema: ISchema, options: InsertAdjacentOptions = {}) {
dn.insertAdjacent(position, schema, options);
diff --git a/packages/client/src/schema-initializer/SchemaInitializer.tsx b/packages/client/src/schema-initializer/SchemaInitializer.tsx
index faf002f90..a1cddfc98 100644
--- a/packages/client/src/schema-initializer/SchemaInitializer.tsx
+++ b/packages/client/src/schema-initializer/SchemaInitializer.tsx
@@ -12,6 +12,7 @@ export const SchemaInitializer = () => null;
SchemaInitializer.Button = observer((props: any) => {
const { wrap = defaultWrap, items = [], insertPosition, dropdown, ...others } = props;
const { insertAdjacent, findComponent } = useDesignable();
+ const [visible, setVisible] = useState(false);
const menu = (
);
- const [visible, setVisible] = useState(false);
return (
{
children: [
{
title: 'Table',
- component: 'TableBlockInitializer',
+ component: TableBlockInitializerItem,
},
{
title: 'Form',
- component: 'FormBlockInitializer',
+ component: FormBlockInitializerItem,
},
],
},
@@ -39,7 +39,7 @@ const InitializerButton = observer((props: any) => {
);
});
-const TableBlockInitializer = (props) => {
+const TableBlockInitializerItem = (props) => {
const { insert } = props;
return (
{
);
};
-const FormBlockInitializer = (props) => {
+const FormBlockInitializerItem = (props) => {
const { insert } = props;
return (
{
export default function App() {
return (
-
+
{
+const ActionInitializerButton = observer((props: any) => {
return (
schema}
insertPosition={'beforeEnd'}
style={{ marginLeft: 8 }}
items={[
@@ -15,15 +22,21 @@ const InitializerButton = observer((props: any) => {
{
title: 'Create',
key: 'create',
- component: 'ActionInitializer',
+ component: 'ActionInitializerItem',
schema: {
+ title: 'Create',
+ 'x-action': 'posts:create',
'x-align': 'left',
},
},
{
title: 'Update',
key: 'update',
- component: 'ActionInitializer',
+ schema: {
+ title: 'Update',
+ 'x-action': 'posts:update',
+ },
+ component: 'ActionInitializerItem',
},
],
},
@@ -34,44 +47,70 @@ const InitializerButton = observer((props: any) => {
);
});
-const ActionInitializer = (props) => {
+const useCurrentActionSchema = (action: string) => {
+ const fieldSchema = useFieldSchema();
+ const { remove } = useDesignable();
+ const schema = fieldSchema.reduceProperties((buf, s) => {
+ if (s['x-action'] === action) {
+ return s;
+ }
+ return buf;
+ });
+ return {
+ schema,
+ exists: !!schema,
+ remove() {
+ schema && remove(schema);
+ },
+ };
+};
+
+const ActionInitializerItem = (props) => {
const { title, schema, insert } = props;
+ const { exists, remove } = useCurrentActionSchema(schema['x-action']);
return (
{
+ if (exists) {
+ return remove();
+ }
insert({
type: 'void',
- title: info.key,
'x-component': 'Action',
...schema,
});
}}
>
- {title}
+
+ {title}
+
);
};
export default function App() {
return (
-
+
diff --git a/packages/client/src/schema-initializer/demos/demo3.tsx b/packages/client/src/schema-initializer/demos/demo3.tsx
index c55e6c6b9..bff1f9497 100644
--- a/packages/client/src/schema-initializer/demos/demo3.tsx
+++ b/packages/client/src/schema-initializer/demos/demo3.tsx
@@ -1,33 +1,46 @@
-import { Field } from '@formily/core';
-import { observer, useField } from '@formily/react';
-import { SchemaComponent, SchemaComponentProvider, SchemaInitializer } from '@nocobase/client';
+import { observer, Schema, useFieldSchema } from '@formily/react';
+import {
+ Form,
+ FormItem,
+ Markdown,
+ SchemaComponent,
+ SchemaComponentProvider,
+ SchemaInitializer,
+ useDesignable
+} from '@nocobase/client';
+import { Input, Switch } from 'antd';
import React from 'react';
-const Hello = observer((props) => {
- const field = useField();
- return (
-
- {field.title}
-
- );
-});
-
const useFormItemInitializerFields = () => {
return [
{
- key: 'field1',
- title: 'Field1',
+ key: 'name',
+ title: 'Name',
component: 'FormItemInitializer',
+ schema: {
+ type: 'string',
+ title: 'Name',
+ 'x-component': 'Input',
+ 'x-decorator': 'FormItem',
+ 'x-collection-field': 'posts.name',
+ },
},
{
- key: 'field2',
- title: 'Field2',
+ key: 'title',
+ title: 'Title',
component: 'FormItemInitializer',
+ schema: {
+ type: 'string',
+ title: 'Title',
+ 'x-component': 'Input',
+ 'x-decorator': 'FormItem',
+ 'x-collection-field': 'posts.title',
+ },
},
];
};
-const InitializerButton = observer((props: any) => {
+const FormItemInitializerButton = observer((props: any) => {
return (
schema}
@@ -51,19 +64,48 @@ const InitializerButton = observer((props: any) => {
);
});
+const useCurrentFieldSchema = (path: string) => {
+ const fieldSchema = useFieldSchema();
+ const { remove } = useDesignable();
+ const findFieldSchema = (schema: Schema) => {
+ return schema.reduceProperties((buf, s) => {
+ if (s['x-collection-field'] === path) {
+ return s;
+ }
+ const child = findFieldSchema(s);
+ if (child) {
+ return child;
+ }
+ return buf;
+ });
+ };
+ const schema = findFieldSchema(fieldSchema);
+ return {
+ schema,
+ exists: !!schema,
+ remove() {
+ schema && remove(schema);
+ },
+ };
+};
+
const FormItemInitializer = (props) => {
- const { title, insert } = props;
+ const { title, schema, insert } = props;
+ const { exists, remove } = useCurrentFieldSchema(schema['x-collection-field']);
return (
{
+ onClick={() => {
+ if (exists) {
+ return remove();
+ }
insert({
- type: 'void',
- title: info.key,
- 'x-component': 'Hello',
+ ...schema,
});
}}
>
- {title}
+
+ {title}
+
);
};
@@ -75,8 +117,9 @@ const AddTextFormItemInitializer = (props) => {
onClick={(info) => {
insert({
type: 'void',
- title: 'Text',
- 'x-component': 'Hello',
+ 'x-component': 'Markdown.Void',
+ 'x-decorator': 'FormItem',
+ // 'x-editable': false,
});
}}
>
@@ -89,7 +132,7 @@ const Page = (props) => {
return (
{props.children}
-
+
);
};
@@ -97,23 +140,28 @@ const Page = (props) => {
export default function App() {
return (
{
const fields = [
{
- key: 'field1',
- title: 'Field1',
+ key: 'name',
+ title: 'Name',
+ schema: {
+ type: 'string',
+ name: 'name',
+ 'x-collection-field': 'posts.name',
+ 'x-component': 'Input',
+ },
component: ColumnInitializer,
},
{
- key: 'field2',
- title: 'Field2',
- component: 'ColumnInitializer',
+ key: 'title',
+ title: 'Title',
+ schema: {
+ type: 'string',
+ name: 'title',
+ 'x-collection-field': 'posts.title',
+ 'x-component': 'Input',
+ },
+ component: ColumnInitializer,
},
];
return fields;
@@ -35,26 +55,56 @@ export const InitializerButton = observer((props: any) => {
);
});
+const useCurrentColumnSchema = (path: string) => {
+ const fieldSchema = useFieldSchema();
+ const { remove } = useDesignable();
+ const findFieldSchema = (schema: Schema) => {
+ return schema.reduceProperties((buf, s) => {
+ if (s['x-collection-field'] === path) {
+ return s;
+ }
+ const child = findFieldSchema(s);
+ if (child) {
+ return child;
+ }
+ return buf;
+ });
+ };
+ const schema = findFieldSchema(fieldSchema);
+ return {
+ schema,
+ exists: !!schema,
+ remove() {
+ schema && remove(schema.parent);
+ },
+ };
+};
+
export const ColumnInitializer = (props) => {
- const { title, insert } = props;
+ const { title, schema, insert } = props;
+ const { exists, remove } = useCurrentColumnSchema(schema['x-collection-field']);
return (
{
+ onClick={() => {
+ if (exists) {
+ return remove();
+ }
insert({
type: 'void',
- title: 'Name',
+ title: schema.name,
'x-component': 'ArrayTable.Column',
properties: {
- name: {
- type: 'string',
- 'x-component': 'Input',
+ [schema.name]: {
'x-read-pretty': true,
+ ...schema,
},
},
});
}}
>
- {title}
+
+ {title}
+
);
};
@@ -70,7 +120,7 @@ const schema = {
{ id: 3, name: 'Name3' },
],
'x-component': 'ArrayTable',
- 'x-initializer': 'InitializerButton',
+ 'x-column-initializer': 'InitializerButton',
'x-component-props': {
rowKey: 'id',
},
@@ -83,6 +133,7 @@ const schema = {
name: {
type: 'string',
'x-component': 'Input',
+ 'x-collection-field': 'posts.name',
'x-read-pretty': true,
},
},
@@ -94,7 +145,7 @@ const schema = {
export default function App() {
return (
-
+
);
diff --git a/packages/client/src/schema-initializer/index.md b/packages/client/src/schema-initializer/index.md
index 957db7acc..aca365ba2 100644
--- a/packages/client/src/schema-initializer/index.md
+++ b/packages/client/src/schema-initializer/index.md
@@ -9,87 +9,39 @@ group:
用于配置各种 schema 的初始化
-## SchemaInitializerProvider
-
-```tsx | pure
-
-```
-
-目前可能需要配置 shortcuts 的有:
-
-```ts
-const shortcuts = {
- // 表单可选操作
- FormAction: [],
- // 抽屉表单可选操作
- DrawerFormAction: [],
- // 对话框表单可选操作
- ModalFormAction: [],
- // 详情区块可选操作
- DetailsAction: [],
- // 表格区块可选操作
- TableAction: [],
- // 表格行可选操作
- TableRowAction: [],
- // 日历可选操作
- CalendarAction: [],
- // 普通页面可添加区块
- Block: [],
- // 当前数据页面可添加区块
- RecordBlock: [],
- // 可添加的表单项
- FormItem: [],
- // 可添加的表格列
- TableColumn: [],
-};
-```
-
## SchemaInitializer.Button
常规区块的初始化按钮
```tsx | pure
- schema}
- // 插入位置
- insertPosition={'beforeBegin'}
- // 从上下文获取 shortcuts 里配置的 items
- shortcut={'Block'}
- items={[
- {
- title: 'Data blocks',
- children: [
- {
- title: 'Table',
- component: 'TableBlockInitializer',
- },
- {
- title: 'Form',
- component: 'FormBlockInitializer',
- },
- ],
- },
- ]}
->Create block
+const items = [
+ {
+ title: 'Data blocks',
+ children: [
+ {
+ title: 'Table',
+ component: 'TableBlockInitializerItem',
+ },
+ {
+ title: 'Form',
+ component: 'FormBlockInitializerItem',
+ },
+ ],
+ },
+];
+
+export const AddBlockButton = () => {
+ return (
+ schema}
+ // 插入位置
+ insertPosition={'beforeBegin'}
+ // 菜单项
+ items={items}
+ >Create block
+ );
+}
```
动态字段的配置
@@ -100,25 +52,27 @@ const useFormItemInitializerFields = () => {
return fields.map(field => {
return {
key: field.name,
- component: 'FormItemInitializer'
+ component: 'FormItemInitializerItem'
}
});
}
- schema}
- // 插入位置
- insertPosition={'beforeBegin'}
- // 从上下文获取 shortcuts 里配置的 items
- shortcut={'Block'}
- items={[
- {
- title: 'Display fields',
- children: useFormItemInitializerFields(),
- },
- ]}
->Configure fields
+export const AddFieldButton = () => {
+ return (
+ schema}
+ // 插入位置
+ insertPosition={'beforeBegin'}
+ items={[
+ {
+ title: 'Display fields',
+ children: useFormItemInitializerFields(),
+ },
+ ]}
+ >Configure fields
+ )
+}
```
## SchemaInitializer.Item
@@ -126,7 +80,7 @@ const useFormItemInitializerFields = () => {
扩展项
```tsx | pure
-const TableBlockInitializer = (props) => {
+const TableBlockInitializerItem = (props) => {
const { insert } = props;
return (