From c9aa381045be6f71f5eafb7c8080f603bc5bedb0 Mon Sep 17 00:00:00 2001 From: chenos Date: Thu, 15 Jul 2021 18:47:21 +0800 Subject: [PATCH] refactor: action/menu/schema-renderer... --- .../src/components/icon-picker/index.tsx | 54 ++ .../route-schema-renderer/index.tsx | 26 +- .../src/components/schema-renderer/index.tsx | 41 +- .../client/src/schemas/action/demos/demo1.tsx | 30 - .../client/src/schemas/action/demos/demo2.tsx | 16 - .../client/src/schemas/action/demos/demo3.tsx | 16 - .../client/src/schemas/action/demos/demo4.tsx | 92 --- .../src/schemas/action/designableBar.tsx | 61 -- packages/client/src/schemas/action/index.md | 466 +++++++------- packages/client/src/schemas/action/index.tsx | 568 +++++++----------- .../client/src/schemas/form-item/index.tsx | 6 +- packages/client/src/schemas/form/index.md | 32 +- packages/client/src/schemas/form/index.tsx | 96 ++- .../client/src/schemas/icon-picker/index.tsx | 75 +-- packages/client/src/schemas/index.tsx | 11 +- .../client/src/schemas/menu/demos/demo1.tsx | 86 +++ .../client/src/schemas/menu/demos/demo2.tsx | 90 +++ .../client/src/schemas/menu/demos/demo3.tsx | 68 +++ .../client/src/schemas/menu/demos/demo4.tsx | 98 +++ packages/client/src/schemas/menu/index.md | 531 +--------------- packages/client/src/schemas/menu/index.tsx | 433 +++---------- .../client/src/schemas/table/demos/demo1.tsx | 112 ++-- packages/client/src/schemas/table/index.tsx | 18 +- 23 files changed, 1110 insertions(+), 1916 deletions(-) create mode 100644 packages/client/src/components/icon-picker/index.tsx delete mode 100644 packages/client/src/schemas/action/demos/demo1.tsx delete mode 100644 packages/client/src/schemas/action/demos/demo2.tsx delete mode 100644 packages/client/src/schemas/action/demos/demo3.tsx delete mode 100644 packages/client/src/schemas/action/demos/demo4.tsx delete mode 100644 packages/client/src/schemas/action/designableBar.tsx create mode 100644 packages/client/src/schemas/menu/demos/demo1.tsx create mode 100644 packages/client/src/schemas/menu/demos/demo2.tsx create mode 100644 packages/client/src/schemas/menu/demos/demo3.tsx create mode 100644 packages/client/src/schemas/menu/demos/demo4.tsx diff --git a/packages/client/src/components/icon-picker/index.tsx b/packages/client/src/components/icon-picker/index.tsx new file mode 100644 index 000000000..f4805c8b8 --- /dev/null +++ b/packages/client/src/components/icon-picker/index.tsx @@ -0,0 +1,54 @@ +import React, { useState } from 'react'; +import { connect, mapProps, mapReadPretty } from '@formily/react'; +import { Input, Popover, Button } from 'antd'; +import { LoadingOutlined, CloseOutlined } from '@ant-design/icons'; +import { createFromIconfontCN } from '@ant-design/icons'; +import * as antIcons from '@ant-design/icons'; + +export const IconFont = createFromIconfontCN({ + scriptUrl: ['//at.alicdn.com/t/font_2261954_u9jzwc44ug.js'], +}); + +export const icons = new Map(); + +export function registerIcon(type: string, icon: any = IconFont) { + icons.set(type.toLowerCase(), icon); +} + +export function hasIcon(type: string) { + if (!type) { + return false; + } + return icons.has(type.toLowerCase()); +} + +export function registerIcons(components) { + Object.keys(components).forEach((type) => { + registerIcon(type, components[type]); + }); +} + +Object.keys(antIcons).forEach((name) => { + if (name.endsWith('Outlined')) { + registerIcon(name, antIcons[name]); + } +}); + +interface IconProps { + type: string; + [key: string]: any; +} + +export function IconPicker(props: IconProps) { + const { type = '', ...restProps } = props; + if (type && icons.has(type.toLowerCase())) { + const IconComponent = icons.get(type.toLowerCase()); + if (IconComponent === IconFont) { + return ; + } + return ; + } + return null; +} + +export default IconPicker; diff --git a/packages/client/src/components/route-schema-renderer/index.tsx b/packages/client/src/components/route-schema-renderer/index.tsx index 9b40888e1..d0911b37f 100644 --- a/packages/client/src/components/route-schema-renderer/index.tsx +++ b/packages/client/src/components/route-schema-renderer/index.tsx @@ -3,6 +3,30 @@ import { Spin } from 'antd'; import { Helmet } from 'react-helmet'; import { useRequest } from 'ahooks'; import { SchemaRenderer } from '../../schemas'; +import { useForm } from '@formily/react'; +import { useHistory } from 'react-router-dom'; + +export function useLogin() { + const form = useForm(); + const history = useHistory(); + return { + async run() { + await form.submit(); + history.push('/admin'); + console.log(form.values); + }, + }; +} + +export function useRegister() { + const form = useForm(); + return { + async run() { + await form.submit(); + console.log(form.values); + }, + }; +} export function RouteSchemaRenderer({ route }) { const { data = {}, loading } = useRequest( @@ -17,7 +41,7 @@ export function RouteSchemaRenderer({ route }) { } return (
- +
); } diff --git a/packages/client/src/components/schema-renderer/index.tsx b/packages/client/src/components/schema-renderer/index.tsx index ecc2b092e..692d884c5 100644 --- a/packages/client/src/components/schema-renderer/index.tsx +++ b/packages/client/src/components/schema-renderer/index.tsx @@ -22,13 +22,7 @@ import Editor from '@monaco-editor/react'; import { ArrayCollapse, ArrayTable, FormLayout } from '@formily/antd'; import { Space, Card, Modal, Spin } from 'antd'; -import { - Action, - useLogin, - useRegister, - useSubmit, - useDesignableValues, -} from '../../schemas/action'; +import { Action } from '../../schemas/action'; import { AddNew } from '../../schemas/add-new'; import { Cascader } from '../../schemas/cascader'; import { Checkbox } from '../../schemas/checkbox'; @@ -46,14 +40,7 @@ import { Menu } from '../../schemas/menu'; import { Password } from '../../schemas/password'; import { Radio } from '../../schemas/radio'; import { Select } from '../../schemas/select'; -import { - Table, - useTableRow, - useTableCreateAction, - useTableUpdateAction, - useTableDestroyAction, - useTableFilterAction, -} from '../../schemas/table'; +import { Table } from '../../schemas/table'; import { Tabs } from '../../schemas/tabs'; import { TimePicker } from '../../schemas/time-picker'; import { Upload } from '../../schemas/upload'; @@ -71,17 +58,7 @@ interface DesignableContextProps { } export const SchemaField = createSchemaField({ - scope: { - useLogin, - useRegister, - useSubmit, - useTableCreateAction, - useTableDestroyAction, - useTableFilterAction, - useTableRow, - useTableUpdateAction, - useDesignableValues, - }, + scope: {}, components: { Card, Div, @@ -180,10 +157,12 @@ export function addPropertyAfter(target: Schema, data: ISchema) { export function useDesignable(path?: any) { const { schema, refresh } = useContext(DesignableContext); const schemaPath = path || useSchemaPath(); + console.log({ schemaPath }); const fieldSchema = useFieldSchema(); const currentSchema = findPropertyByPath(schema, schemaPath) || ({} as Schema); - // console.log('useDesignable', { schema, schemaPath, currentSchema }); + console.log({ currentSchema }) + // console.log('useDesignable', { schema, schemaPath, currentSchema }); const options = useContext(SchemaOptionsContext); const DesignableBar = get(options.components, currentSchema['x-designable-bar']) || (() => null); @@ -317,13 +296,17 @@ export function useDesignable(path?: any) { } export function getSchemaPath(schema: Schema) { - const path = [schema.name]; + const path = schema['x-path'] || [schema.name]; let parent = schema.parent; while (parent) { if (!parent.name) { break; } - path.unshift(parent.name); + if (parent['x-path']) { + path.unshift(...parent['x-path']); + } else { + path.unshift(parent.name); + } parent = parent.parent; } // console.log('getSchemaPath', path, schema); diff --git a/packages/client/src/schemas/action/demos/demo1.tsx b/packages/client/src/schemas/action/demos/demo1.tsx deleted file mode 100644 index c8d9b3350..000000000 --- a/packages/client/src/schemas/action/demos/demo1.tsx +++ /dev/null @@ -1,30 +0,0 @@ -/** - * title: 按钮操作 - * desc: 可以通过配置 `useAction` 来处理操作逻辑 - */ -import React from 'react'; -// @ts-ignore -import { SchemaRenderer } from '@nocobase/client'; - -function useAction() { - return { - run() { - alert('这是自定义的操作逻辑'); - }, - }; -} - -const schema = { - type: 'void', - name: 'action1', - title: '按钮', - 'x-component': 'Action', - 'x-designable-bar': 'Action.DesignableBar', - 'x-component-props': { - useAction: '{{ useAction }}', - }, -}; - -export default () => { - return ; -}; diff --git a/packages/client/src/schemas/action/demos/demo2.tsx b/packages/client/src/schemas/action/demos/demo2.tsx deleted file mode 100644 index 8af2ed35e..000000000 --- a/packages/client/src/schemas/action/demos/demo2.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react'; -import { SchemaRenderer } from '@nocobase/client'; - -const schema = { - type: 'void', - name: 'action1', - title: '按钮', - 'x-component': 'Action.Link', - 'x-component-props': { - to: 'abc', - }, -}; - -export default () => { - return ; -}; diff --git a/packages/client/src/schemas/action/demos/demo3.tsx b/packages/client/src/schemas/action/demos/demo3.tsx deleted file mode 100644 index b7f12cab4..000000000 --- a/packages/client/src/schemas/action/demos/demo3.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react'; -import { SchemaRenderer } from '@nocobase/client'; - -const schema = { - type: 'void', - name: 'action1', - title: '按钮', - 'x-component': 'Action.URL', - 'x-component-props': { - url: 'https://www.nocobase.com/', - }, -}; - -export default () => { - return ; -}; diff --git a/packages/client/src/schemas/action/demos/demo4.tsx b/packages/client/src/schemas/action/demos/demo4.tsx deleted file mode 100644 index b25bfa283..000000000 --- a/packages/client/src/schemas/action/demos/demo4.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import React from 'react'; -import { SchemaRenderer } from '@nocobase/client'; - -function useAction() { - return { - run() { - alert('这是自定义的操作逻辑'); - }, - }; -} - -const schema = { - type: 'void', - name: 'action1', - title: '下拉菜单', - 'x-component': 'Action.Dropdown', - properties: { - action1: { - type: 'void', - name: 'action1', - title: '按钮', - 'x-component': 'Action', - 'x-component-props': { - useAction, - }, - }, - action2: { - type: 'void', - title: 'Drawer 按钮', - 'x-component': 'Action', - properties: { - drawer1: { - type: 'void', - title: '抽屉标题', - 'x-component': 'Action.Drawer', - 'x-component-props': {}, - properties: { - input: { - type: 'string', - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - action2: { - type: 'void', - title: '打开二级抽屉', - // 'x-decorator': 'FormItem', - 'x-component': 'Action', - properties: { - drawer1: { - type: 'void', - title: '二级抽屉标题', - 'x-component': 'Action.Drawer', - 'x-component-props': {}, - properties: { - input: { - type: 'string', - 'x-component': 'Input', - }, - }, - }, - }, - }, - }, - }, - }, - }, - action3: { - type: 'void', - name: 'action1', - title: 'Popover 按钮', - 'x-component': 'Action', - properties: { - popover1: { - type: 'void', - title: '弹窗标题', - 'x-component': 'Action.Popover', - 'x-component-props': {}, - properties: { - input: { - type: 'string', - 'x-component': 'Input', - }, - }, - }, - }, - }, - }, -}; - -export default () => { - return ; -}; diff --git a/packages/client/src/schemas/action/designableBar.tsx b/packages/client/src/schemas/action/designableBar.tsx deleted file mode 100644 index 2acd79eaa..000000000 --- a/packages/client/src/schemas/action/designableBar.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import { ISchema } from '@formily/react'; -import { - useDesignableValues, - useDesignableUpdate, - useDesignableSchemaRemove, -} from '.'; - -export const DesignableBar: { [key: string]: ISchema } = {}; - -DesignableBar.Action = { - name: 'bar', - type: 'void', - // title: '操作栏2', - 'x-component': 'Action.Dropdown', - 'x-component-props': { - icon: 'MenuOutlined', - }, - properties: { - edit: { - type: 'void', - title: '编辑按钮', - 'x-component': 'Action', - 'x-component-props': { - // icon, - }, - properties: { - modal: { - type: 'void', - title: '修改按钮配置', - 'x-decorator': 'Form', - 'x-decorator-props': { - useValues: useDesignableValues, - }, - 'x-component': 'Action.Modal', - 'x-component-props': { - width: '500px', - useAction: useDesignableUpdate, - }, - properties: { - title: { - type: 'string', - title: '按钮标题', - required: true, - 'x-component': 'Input', - 'x-decorator': 'FormItem', - }, - }, - }, - }, - }, - remove: { - type: 'void', - title: '删除按钮', - 'x-component': 'Action', - 'x-component-props': { - useAction: useDesignableSchemaRemove, - // icon, - }, - }, - }, -}; diff --git a/packages/client/src/schemas/action/index.md b/packages/client/src/schemas/action/index.md index 103a6e604..861b4fe2a 100644 --- a/packages/client/src/schemas/action/index.md +++ b/packages/client/src/schemas/action/index.md @@ -75,208 +75,75 @@ group: ## Examples -### Action - 常规操作 - - - -### Action.Link - 内链跳转 - - - -### Action.URL - 外链跳转 - - - -### Action.Dropdown - 下拉操作 - - - -### Action.Popover - 打开气泡 +### Action ```tsx +/** + * title: 按钮操作 + * desc: 可以通过配置 `useAction` 来处理操作逻辑 + */ import React from 'react'; -import { SchemaRenderer } from '../'; +// @ts-ignore +import { SchemaRenderer } from '@nocobase/client'; + +function useAction() { + return { + run() { + alert('这是自定义的操作逻辑'); + }, + }; +} const schema = { type: 'void', name: 'action1', title: '按钮', 'x-component': 'Action', - properties: { - popover1: { - type: 'void', - title: '弹窗标题', - 'x-component': 'Action.Popover', - 'x-component-props': {}, - properties: { - input: { - type: 'string', - 'x-component': 'Input', - } - }, - }, + 'x-designable-bar': 'Action.DesignableBar', + 'x-component-props': { + useAction: '{{ useAction }}', }, }; export default () => { - return -} + return ( + + ); +}; ``` -### Action.Drawer - 打开抽屉 +### Action.Modal ```tsx import React from 'react'; +import { SchemaRenderer } from '@nocobase/client'; import { Space } from 'antd'; -import { SchemaRenderer } from '../'; -const schema1 = { +const schema = { type: 'void', name: 'action1', title: '按钮', 'x-component': 'Action', - properties: { - drawer1: { - type: 'void', - title: '抽屉标题', - 'x-component': 'Action.Drawer', - 'x-component-props': {}, - properties: { - input: { - type: 'string', - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - action2: { - type: 'void', - title: '打开二级抽屉', - // 'x-decorator': 'FormItem', - 'x-component': 'Action', - properties: { - drawer1: { - type: 'void', - title: '二级抽屉标题', - 'x-component': 'Action.Drawer', - 'x-component-props': {}, - properties: { - input: { - type: 'string', - 'x-component': 'Input', - }, - }, - }, - }, - } - }, - }, + 'x-designable-bar': 'Action.DesignableBar', + 'x-component-props': { }, -}; - -const schema2 = { - type: 'void', - name: 'action1', - title: 'x-decorator=Form', - 'x-component': 'Action', properties: { - drawer1: { + modal1: { type: 'void', - title: '弹窗标题', - 'x-component': 'Action.Drawer', - 'x-component-props': { - // footer: null, - }, - 'x-decorator': 'Form', + title: '对话框标题', + 'x-component': 'Action.Modal', properties: { input: { type: 'string', title: '输入框', - 'x-decorator': 'FormItem', - 'x-component': 'Input', required: true, - }, - }, - }, - }, -}; - -export default () => { - return ( - - - - - ) -} -``` - -### Action.Modal - 打开对话框 - -`x-decorator='Form'` 时,Model 为 Form,并自带按钮 - -```tsx -import React from 'react'; -import { Space } from 'antd'; -import { SchemaRenderer } from '../'; -import { useVisibleContext } from './'; - -function useAction() { - const { visible, setVisible } = useVisibleContext(); - return { - async run() { - console.log({ visible }) - setVisible(false); - } - } -} - -const schema = { - type: 'void', - name: 'action1', - title: '按钮', - 'x-component': 'Action', - properties: { - drawer1: { - type: 'void', - title: '弹窗标题', - 'x-component': 'Action.Modal', - 'x-component-props': { - // footer: null, - }, - properties: { - input: { - type: 'string', 'x-decorator': 'FormItem', 'x-component': 'Input', }, - close: { - type: 'void', - name: 'action1', - title: '关闭', - 'x-component': 'Action', - 'x-component-props': { - useAction, - }, - }, - action2: { - type: 'void', - title: '打开二级抽屉', - // 'x-decorator': 'FormItem', - 'x-component': 'Action', - properties: { - drawer1: { - type: 'void', - title: '二级抽屉标题', - 'x-component': 'Action.Modal', - 'x-component-props': {}, - properties: { - input: { - type: 'string', - 'x-component': 'Input', - }, - }, - }, - }, - } }, }, }, @@ -285,20 +152,22 @@ const schema = { const schema2 = { type: 'void', name: 'action1', - title: 'x-decorator=Form', + title: 'ModalForm', 'x-component': 'Action', + 'x-designable-bar': 'Action.DesignableBar', + 'x-component-props': { + }, properties: { - drawer1: { + modal1: { type: 'void', - title: '弹窗标题', - 'x-component': 'Action.Modal', - 'x-component-props': { - // footer: null, - }, + title: '对话框标题', 'x-decorator': 'Form', + 'x-component': 'Action.Modal', properties: { input: { type: 'string', + title: '输入框', + required: true, 'x-decorator': 'FormItem', 'x-component': 'Input', }, @@ -310,51 +179,226 @@ const schema2 = { export default () => { return ( - - + + - ) -} + ); +}; ``` -### Action.Container - 指定容器内打开 +### Action.Drawer ```tsx -import React, { useRef } from 'react'; -import { SchemaRenderer } from '../'; -import { ActionContext } from './'; +import React from 'react'; +import { SchemaRenderer } from '@nocobase/client'; +import { Space } from 'antd'; -export default () => { - const containerRef = useRef(); - const schema = { - type: 'void', - name: 'action1', - title: '按钮', - 'x-component': 'Action', - 'x-component-props': { - containerRef - }, - properties: { - container1: { - type: 'void', - title: '页面标题', - 'x-component': 'Action.Container', - properties: { - input: { - type: 'string', - title: '字段', - 'x-designable-bar': 'FormItem.DesignableBar', - 'x-decorator': 'FormItem', - 'x-component': 'Input', - } +const schema = { + type: 'void', + name: 'action1', + title: '按钮', + 'x-component': 'Action', + 'x-designable-bar': 'Action.DesignableBar', + 'x-component-props': { + }, + properties: { + modal1: { + type: 'void', + title: '抽屉标题', + 'x-component': 'Action.Drawer', + properties: { + input: { + type: 'string', + title: '输入框', + required: true, + 'x-decorator': 'FormItem', + 'x-component': 'Input', }, }, }, - }; + }, +}; + +const schema2 = { + type: 'void', + name: 'action1', + title: 'DrawerForm', + 'x-component': 'Action', + 'x-designable-bar': 'Action.DesignableBar', + 'x-component-props': { + }, + properties: { + modal1: { + type: 'void', + title: '抽屉标题', + 'x-decorator': 'Form', + 'x-component': 'Action.Drawer', + properties: { + input: { + type: 'string', + title: '输入框', + required: true, + 'x-decorator': 'FormItem', + 'x-component': 'Input', + }, + }, + }, + }, +}; + +export default () => { return ( -
- -
- ) -} + + + + + ); +}; +``` + +### Action.Dropdown + +```tsx +import React from 'react'; +import { SchemaRenderer } from '@nocobase/client'; + +const schema = { + type: 'void', + name: 'dropdown1', + title: '下拉菜单', + 'x-component': 'Action.Dropdown', + 'x-designable-bar': 'Action.DesignableBar', + 'x-component-props': {}, + properties: { + item1: { + type: 'void', + title: `操作1`, + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.Action', + properties: { + modal1: { + type: 'void', + title: '对话框标题', + 'x-component': 'Action.Modal', + properties: { + input: { + type: 'string', + 'x-component': 'Input', + }, + }, + }, + }, + }, + item2: { + type: 'void', + title: `操作2`, + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.Action', + properties: { + modal2: { + type: 'void', + title: '对话框标题', + 'x-component': 'Action.Modal', + properties: { + input: { + type: 'string', + 'x-component': 'Input', + }, + }, + }, + }, + }, + }, +}; + +export default () => { + return ( + + ); +}; +``` + +### Action.Popover + +```tsx +import React from 'react'; +import { SchemaRenderer } from '@nocobase/client'; +import { Space } from 'antd'; + +const schema = { + type: 'void', + name: 'action1', + title: '按钮', + 'x-component': 'Action', + 'x-designable-bar': 'Action.DesignableBar', + 'x-component-props': { + }, + properties: { + modal1: { + type: 'void', + title: '抽屉标题', + 'x-component': 'Action.Popover', + properties: { + input: { + type: 'string', + title: '输入框', + required: true, + 'x-decorator': 'FormItem', + 'x-component': 'Input', + }, + }, + }, + }, +}; + +const schema2 = { + type: 'void', + name: 'action1', + title: 'PopoverForm', + 'x-component': 'Action', + 'x-designable-bar': 'Action.DesignableBar', + 'x-component-props': { + }, + properties: { + modal1: { + type: 'void', + title: '抽屉标题', + 'x-decorator': 'Form', + 'x-component': 'Action.Popover', + properties: { + input: { + type: 'string', + title: '输入框', + required: true, + 'x-decorator': 'FormItem', + 'x-component': 'Input', + }, + }, + }, + }, +}; + +export default () => { + return ( + + + + + ); +}; ``` diff --git a/packages/client/src/schemas/action/index.tsx b/packages/client/src/schemas/action/index.tsx index 4339bfd9d..2c79f889d 100644 --- a/packages/client/src/schemas/action/index.tsx +++ b/packages/client/src/schemas/action/index.tsx @@ -13,266 +13,132 @@ import { } from '@formily/react'; import { Button, Dropdown, Menu, Popover, Space, Drawer, Modal } from 'antd'; import { Link, useHistory, LinkProps } from 'react-router-dom'; -import { SchemaRenderer, useDesignable } from '..'; -import ReactDOM from 'react-dom'; -import get from 'lodash/get'; -import { MenuOutlined, DownOutlined } from '@ant-design/icons'; -import classNames from 'classnames'; -import { useMount } from 'ahooks'; -import { uid } from '@formily/shared'; - +import { useDesignable, VisibleContext, useDefaultAction } from '..'; import './style.less'; -import constate from 'constate'; -import { Icon } from '../icon-picker'; -import { useMemo } from 'react'; -import { createForm } from '@formily/core'; +import { uid } from '@formily/shared'; +import cls from 'classnames'; +import { MenuOutlined } from '@ant-design/icons'; -export function useDefaultAction() { - return { - run() {}, - }; -} - -export function useSubmit() { - const form = useForm(); - const run = async () => { - await form.submit(); - console.log(form.values); - }; - return { - run, - }; -} - -export function useLogin() { - const form = useForm(); - const history = useHistory(); - const run = async () => { - await form.submit(); - history.push('/admin'); - console.log(form.values); - }; - return { - run, - }; -} - -export function useRegister() { - const form = useForm(); - const run = async () => { - await form.submit(); - console.log(form.values); - }; - return { - run, - }; -} - -export interface ActionProps { - useAction?: any; - [key: string]: any; -} - -export type ActionType = React.FC & { - Link?: React.FC; - URL?: React.FC; - Page?: React.FC; - Container?: React.FC; - Popover?: React.FC; - Drawer?: React.FC; - Modal?: React.FC; - Dropdown?: React.FC; - Group?: React.FC; - DesignableBar?: React.FC; -}; - -function useDesignableBar() { - const schema = useFieldSchema(); - const options = useContext(SchemaOptionsContext); - const DesignableBar = get(options.components, schema['x-designable-bar']); - return { - DesignableBar: DesignableBar || (() => null), - }; -} - -const [VisibleProvider, useVisibleContext] = constate((props: any = {}) => { - const { initialVisible = false, containerRef = null } = props; - const [visible, setVisible] = useState(initialVisible); - return { containerRef, visible, setVisible }; -}); - -export { VisibleProvider, useVisibleContext }; - -const BaseAction = observer((props: any) => { - const { - ButtonComponent = Button, - className, - icon, - useAction = useDefaultAction, - ...others - } = props; - const field = useField(); +export const Action: any = observer((props: any) => { + const { useAction = useDefaultAction, ...others } = props; const { run } = useAction(); - const { DesignableBar } = useDesignableBar(); - const { setVisible } = useVisibleContext(); - const fieldSchema = useFieldSchema(); + const { schema, DesignableBar } = useDesignable(); + const [visible, setVisible] = useState(false); + const child = Object.values(schema.properties || {}).shift(); + const isDropdownOrPopover = + child && + ['Action.Dropdown', 'Action.Popover'].includes(child['x-component']); + console.log({ DesignableBar, schema }) + return ( + + {!isDropdownOrPopover && ( + + )} + + + ); +}); + +Action.Modal = observer((props: any) => { const { schema } = useDesignable(); - - useEffect(() => { - field.componentProps.setVisible = setVisible; - }, []); - - const renderButton = () => ( - : null} - className={classNames(className, `name-${schema.name}`)} - onClick={async (e) => { - e.stopPropagation && e.stopPropagation(); - setVisible && setVisible(true); - await run(); - }} - > - {schema.title} - - - ); - - const popover = schema.reduceProperties((items, current) => { - if (current['x-component'] === 'Action.Popover') { - return current; - } - return null; - }, null); - - if (popover) { - return ( - - ); - } - + const [visible, setVisible] = useContext(VisibleContext); + const form = useForm(); + const isFormDecorator = schema['x-decorator'] === 'Form'; return ( - <> - {renderButton()} - {props.children} - - ); -}); - -export const Action: ActionType = observer((props: any) => { - const schema = useFieldSchema(); - if (schema.properties) { - return ( - - - - ); - } - return ; -}); - -Action.Link = observer((props) => { - const schema = useFieldSchema(); - return {schema.title}; -}); - -Action.URL = observer((props) => { - const { url, ...others } = props; - const schema = useFieldSchema(); - return ( - - {schema.title} - - ); -}); - -Action.Container = observer((props) => { - const { visible, setVisible } = useVisibleContext(); - return visible &&
{props.children}
; -}); - -Action.Popover = observer((props) => { - const { visible, setVisible } = useVisibleContext(); - const schema = useFieldSchema(); - return ( - { - setVisible(visible); - }} + { + if (isFormDecorator) { + form.clearErrors(); + } + setVisible(false); + }} + > + Cancel + , + , + ] + : null + } {...props} - content={props.children} + onCancel={() => { + if (isFormDecorator) { + form.clearErrors(); + } + setVisible(false); + }} + visible={visible} > - {schema['x-button']} - + {props.children} + ); }); -Action.Drawer = observer((props) => { - const field = useField(); - // const { visible, setVisible } = useVisibleContext(); - const { useAction = () => ({ async run() {} }), ...others } = props; +Action.Drawer = observer((props: any) => { const { schema } = useDesignable(); - const { visible, setVisible } = useVisibleContext(); - const { run } = useAction(); + const [visible, setVisible] = useContext(VisibleContext); const form = useForm(); - console.log(`schema['x-decorator']`, schema['x-decorator']); - if (schema['x-decorator'] === 'Form.Decorator') { - Object.assign(others, { - footer: ( - - - - - ), - }); - } - + const isFormDecorator = schema['x-decorator'] === 'Form'; return ( { - e.stopPropagation(); - }} - title={field.title} width={'50%'} - {...others} - visible={visible} + title={schema.title} + maskClosable destroyOnClose - onClose={(e) => { - e.stopPropagation(); - form.clearErrors(); + footer={ + isFormDecorator && ( + + + + + ) + } + {...props} + visible={visible} + onClose={async (e) => { + props.onClose && (await props.onClose(e)); setVisible(false); }} > @@ -281,145 +147,121 @@ Action.Drawer = observer((props) => { ); }); -const [DesignableContextProvider, useDesignableContext] = constate(() => { - return useDesignable(); -}); - -import { DesignableBar } from './designableBar'; - -export function useDesignableValues() { - const { schema } = useDesignableContext(); - return schema - ? { - title: schema.title, - } - : {}; -} - -export function useDesignableUpdate() { - const { schema, refresh } = useDesignableContext(); - const form = useForm(); - return { - async run() { - schema.title = form.values.title; - refresh(); - console.log('useDesignableUpdate', schema, form.values); - }, - }; -} - -export function useDesignableSchemaRemove() { - const { schema, refresh, remove } = useDesignableContext(); - return { - async run() { - remove(); - }, - }; -} - -Action.Modal = observer((props) => { - const { useAction = () => ({ async run() {} }), ...others } = props; +Action.Dropdown = observer((props: any) => { const { schema } = useDesignable(); - const { setVisible: setDropdownVisible } = useDropdownVisibleContext(); - const { visible, setVisible } = useVisibleContext(); - const { run } = useAction(); - const form = useForm(); - // console.log('Action.Modal', schema['x-component-props'], Object.keys(others).includes('footer')); - if ( - !Object.keys(others).includes('footer') && - schema['x-decorator'] !== 'Form.Decorator' - ) { - Object.assign(others, { footer: null }); - } + const componentProps = schema.parent['x-component-props'] || {}; return ( - { - e.stopPropagation(); - setVisible(false); - // await form.reset(); - setDropdownVisible && setDropdownVisible(false); - }} - onOk={async (e) => { - console.log('onOk', form.values); - // await form.submit(); - await run(); - setVisible(false); - setDropdownVisible && setDropdownVisible(false); - }} + + + + } > -
e.stopPropagation()} - > - {props.children} -
-
+ + ); }); -const [DropdownVisibleProvider, useDropdownVisibleContext] = constate( - (props: any = {}) => { - const { initialVisible = false } = props; - const [visible, setVisible] = useState(initialVisible); - return { visible, setVisible }; - }, -); - -const ActionDropdown = observer((props: any) => { - const { icon, ...others } = props; - const schema = useFieldSchema(); - const { visible, setVisible } = useDropdownVisibleContext(); +Action.Popover = observer((props) => { + const fieldSchema = useFieldSchema(); + const { schema } = useDesignable(); + const form = useForm(); + const isFormDecorator = schema['x-decorator'] === 'Form'; + const [visible, setVisible] = useContext(VisibleContext); + console.log('Action.Popover', schema, fieldSchema); + const componentProps = + (schema.parent && schema.parent['x-component-props']) || {}; return ( { - setVisible(visible); - }} - // {...props} - overlayClassName={'nb-action-group'} - // trigger={'click'} - content={props.children} - placement={'bottomLeft'} + trigger={['click']} + onVisibleChange={setVisible} + {...props} + title={schema.title} + content={ +
+ {props.children} + {isFormDecorator && ( +
+ + + + +
+ )} +
+ } > - +
); }); -Action.Dropdown = observer((props) => { - return ( - - -
{props.children}
-
- ); -}); - Action.DesignableBar = () => { const field = useField(); // const schema = useFieldSchema(); const { schema, insertAfter, refresh } = useDesignable(); const [visible, setVisible] = useState(false); return ( - -
- { - e.stopPropagation(); +
+ { + e.stopPropagation(); + }} + className={cls('designable-bar-actions', { active: visible })} + > + { + setVisible(visible); }} - className={classNames('designable-bar-actions', { active: visible })} + overlay={ + + { + // console.log({ field, schema }); + schema.title = '按钮文案被修改了'; + // field.setTitle('按钮文案被修改了'); + // setVisible(false); + refresh(); + }} + > + 点击修改按钮文案 + + { + insertAfter({ + name: uid(), + 'x-component': 'Input', + }); + }} + > + insertAfter + + + } > - - -
- + + +
+
); -}; +}; \ No newline at end of file diff --git a/packages/client/src/schemas/form-item/index.tsx b/packages/client/src/schemas/form-item/index.tsx index 755fee630..e1f4de4e8 100644 --- a/packages/client/src/schemas/form-item/index.tsx +++ b/packages/client/src/schemas/form-item/index.tsx @@ -56,13 +56,13 @@ FormItem.DesignableBar = () => { { const title = uid(); - schema.title = title; + // schema.title = title; field.title = title; setVisible(false); - refresh(); + // refresh(); }} > - 点击修改按钮文案 + 修改文案 } diff --git a/packages/client/src/schemas/form/index.md b/packages/client/src/schemas/form/index.md index f0eab79d4..918f80273 100644 --- a/packages/client/src/schemas/form/index.md +++ b/packages/client/src/schemas/form/index.md @@ -20,6 +20,7 @@ group: // 添加其他节点 +// Form 用作 decorator 时只用于创建独立的作用域 @@ -36,15 +37,19 @@ import React from 'react'; import { SchemaRenderer } from '../'; const schema = { - name: 'form', type: 'object', + name: 'form', 'x-component': 'Form', + 'x-component-props': { + layout: 'horizontal', + }, properties: { username: { type: 'string', title: '用户名', required: true, 'x-decorator': 'FormItem', + 'x-designable-bar': 'FormItem.DesignableBar', 'x-component': 'Input', }, password: { @@ -59,7 +64,7 @@ const schema = { export default () => { return ( - + ); }; ``` @@ -124,25 +129,14 @@ const schema = { 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%', - }, - }, + 'x-component-props': {}, title: '重置', }, }, @@ -220,12 +214,7 @@ const schema = { type: 'void', 'x-component': 'Action', 'x-component-props': { - // block: true, type: 'primary', - useAction: '{{ useLogin }}', - style: { - // width: '100%', - }, }, title: '提交', }, @@ -233,11 +222,6 @@ const schema = { type: 'void', 'x-component': 'Action', 'x-component-props': { - // block: true, - useAction: '{{ useLogin }}', - style: { - // width: '100%', - }, }, title: '重置', }, diff --git a/packages/client/src/schemas/form/index.tsx b/packages/client/src/schemas/form/index.tsx index bd89d4d88..03b8d672e 100644 --- a/packages/client/src/schemas/form/index.tsx +++ b/packages/client/src/schemas/form/index.tsx @@ -9,77 +9,53 @@ import { FormProvider, ISchema, } from '@formily/react'; -import { SchemaRenderer, useDesignable } from '../'; +import { useSchemaPath, SchemaField, useDesignable } from '../'; 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 { MenuOutlined } from '@ant-design/icons'; import cls from 'classnames'; - +import { FormLayout } from '@formily/antd'; import './style.less'; -import { clone } from '@formily/shared'; - -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, - }; -} - -function useDefaultValues() { - return {}; -} export const Form: any = observer((props: any) => { - const scope = useContext(SchemaExpressionScopeContext); - const { useValues = useDefaultValues } = props; - const values = useValues(); + const { useValues = () => ({}), ...others } = props; + const initialValues = useValues(); const form = useMemo(() => { - console.log('Form.useMemo', values); - return createForm({ - values, - // values: clone(values), - }); - }, [values]); - const schema = useFieldSchema(); - const { schema: designableSchema, refresh } = useDesignable(); - const formSchema: ISchema = schema['x-decorator'] === 'Form' ? { - type: 'object', - properties: { - [schema.name]: { - ...schema.toJSON(), - "x-decorator": 'Form.Decorator', - } - } - } : schema.toJSON(); + console.log('Form.useMemo', initialValues); + return createForm({ initialValues }); + }, []); + const { schema } = useDesignable(); + const path = useSchemaPath(); return ( - { - designableSchema.properties = subSchema.properties; - refresh(); - }} - form={form} - schema={formSchema} - onlyRenderProperties - /> + + {schema['x-decorator'] === 'Form' ? ( + + ) : ( + + + + )} + ); }); -Form.Decorator = ({children}) => children; +Form.__Decorator = ({ children }) => children; Form.DesignableBar = (props) => { const { active } = props; diff --git a/packages/client/src/schemas/icon-picker/index.tsx b/packages/client/src/schemas/icon-picker/index.tsx index c4871f534..e16a58cb3 100644 --- a/packages/client/src/schemas/icon-picker/index.tsx +++ b/packages/client/src/schemas/icon-picker/index.tsx @@ -3,77 +3,10 @@ import { connect, mapProps, mapReadPretty } from '@formily/react'; import { Input, Popover, Button } from 'antd'; import { LoadingOutlined, CloseOutlined } from '@ant-design/icons'; import { - createFromIconfontCN, - UserOutlined, - TeamOutlined, - DatabaseOutlined, - DashboardOutlined, - SettingOutlined, - TableOutlined, - MenuOutlined, - HistoryOutlined, - NotificationOutlined, -} from '@ant-design/icons'; - -import * as antIcons from '@ant-design/icons'; - -export const IconFont = createFromIconfontCN({ - scriptUrl: ['//at.alicdn.com/t/font_2261954_u9jzwc44ug.js'], -}); - -export const icons = new Map(); - -export function registerIcon(type: string, icon: any = IconFont) { - icons.set(type.toLowerCase(), icon); -} - -export function hasIcon(type: string) { - if (!type) { - return false; - } - return icons.has(type.toLowerCase()); -} - -export function registerIcons(components) { - Object.keys(components).forEach((type) => { - registerIcon(type, components[type]); - }); -} - -Object.keys(antIcons).forEach((name) => { - if (name.endsWith('Outlined')) { - registerIcon(name, antIcons[name]); - } -}); - -registerIcons({ - // HistoryOutlined, - // MenuOutlined, - // TableOutlined, - // SettingOutlined, - // TeamOutlined, - // UserOutlined, - // DatabaseOutlined, - // DashboardOutlined, - // NotificationOutlined, -}); - -interface IconProps { - type: string; - [key: string]: any; -} - -export function Icon(props: IconProps) { - const { type = '', ...restProps } = props; - if (type && icons.has(type.toLowerCase())) { - const IconComponent = icons.get(type.toLowerCase()); - if (IconComponent === IconFont) { - return ; - } - return ; - } - return ; -} + icons, + hasIcon, + IconPicker as Icon, +} from '../../components/icon-picker'; function IconField(props: any) { const { value, onChange } = props; diff --git a/packages/client/src/schemas/index.tsx b/packages/client/src/schemas/index.tsx index 4a55d35ce..24af1041d 100644 --- a/packages/client/src/schemas/index.tsx +++ b/packages/client/src/schemas/index.tsx @@ -1,2 +1,11 @@ -// export * from './DesignableSchemaField'; +import { createContext } from 'react'; + export * from '../components/schema-renderer'; +export const VisibleContext = createContext(null); +export const DesignableBarContext = createContext(null); + +export function useDefaultAction() { + return { + async run () {} + } +} diff --git a/packages/client/src/schemas/menu/demos/demo1.tsx b/packages/client/src/schemas/menu/demos/demo1.tsx new file mode 100644 index 000000000..69b4b20a8 --- /dev/null +++ b/packages/client/src/schemas/menu/demos/demo1.tsx @@ -0,0 +1,86 @@ +/** + * title: 横向菜单 + */ +import React from 'react'; +import { SchemaRenderer } from '@nocobase/client'; + +const schema = { + type: 'object', + properties: { + menu1: { + type: 'void', + 'x-component': 'Menu', + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component-props': { + mode: 'horizontal', + theme: 'dark', + }, + properties: { + item1: { + type: 'void', + title: `菜单1`, + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.Item', + }, + item2: { + type: 'void', + title: `菜单2`, + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.Item', + }, + item3: { + type: 'void', + title: '菜单组3', + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.SubMenu', + properties: { + item5: { + type: 'void', + title: `子菜单5`, + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.SubMenu', + properties: { + item8: { + type: 'void', + title: `子菜单8`, + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.Item', + }, + item9: { + type: 'void', + title: `子菜单9`, + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.Item', + }, + }, + }, + }, + }, + item4: { + type: 'void', + title: '菜单组4', + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.SubMenu', + properties: { + item6: { + type: 'void', + title: `子菜单6`, + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.Item', + }, + item7: { + type: 'void', + title: `子菜单7`, + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.Item', + }, + }, + }, + }, + }, + }, +}; + +export default () => { + return ; +}; diff --git a/packages/client/src/schemas/menu/demos/demo2.tsx b/packages/client/src/schemas/menu/demos/demo2.tsx new file mode 100644 index 000000000..9345ba900 --- /dev/null +++ b/packages/client/src/schemas/menu/demos/demo2.tsx @@ -0,0 +1,90 @@ +/** + * title: 横向菜单 + */ +import React from 'react'; +import { SchemaRenderer } from '@nocobase/client'; + +const schema = { + type: 'object', + properties: { + menu1: { + type: 'void', + 'x-component': 'Menu', + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component-props': { + mode: 'inline', + // theme: 'dark', + }, + properties: { + item1: { + type: 'void', + title: `菜单1`, + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.Item', + }, + item2: { + type: 'void', + title: `菜单2`, + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.Item', + }, + item3: { + type: 'void', + title: '菜单组3', + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.SubMenu', + properties: { + item5: { + type: 'void', + title: `子菜单5`, + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.SubMenu', + properties: { + item8: { + type: 'void', + title: `子菜单8`, + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.Item', + }, + item9: { + type: 'void', + title: `子菜单9`, + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.Item', + }, + }, + }, + }, + }, + item4: { + type: 'void', + title: '菜单组4', + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.SubMenu', + properties: { + item6: { + type: 'void', + title: `子菜单6`, + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.Item', + }, + item7: { + type: 'void', + title: `子菜单7`, + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.Item', + }, + }, + }, + }, + }, + }, +}; + +export default () => { + return ( +
+ +
+ ); +}; diff --git a/packages/client/src/schemas/menu/demos/demo3.tsx b/packages/client/src/schemas/menu/demos/demo3.tsx new file mode 100644 index 000000000..135f30bfd --- /dev/null +++ b/packages/client/src/schemas/menu/demos/demo3.tsx @@ -0,0 +1,68 @@ +/** + * title: 横向菜单 + */ +import React from 'react'; +import { SchemaRenderer } from '@nocobase/client'; +import { ISchema } from '@formily/react'; + +const schema: ISchema = { + type: 'object', + properties: { + menu1: { + type: 'void', + 'x-component': 'Menu', + 'x-component-props': { + mode: 'horizontal', + // theme: 'dark', + }, + properties: { + item1: { + type: 'void', + title: `菜单1`, + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.Action', + properties: { + modal1: { + type: 'void', + title: '对话框标题', + 'x-component': 'Action.Modal', + properties: { + input: { + type: 'string', + 'x-component': 'Input', + }, + }, + }, + }, + }, + item2: { + type: 'void', + title: `菜单2`, + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.Action', + properties: { + modal2: { + type: 'void', + title: '对话框标题', + 'x-component': 'Action.Modal', + properties: { + input: { + type: 'string', + 'x-component': 'Input', + }, + }, + }, + }, + }, + }, + }, + }, +}; + +export default () => { + return ( +
+ +
+ ); +}; diff --git a/packages/client/src/schemas/menu/demos/demo4.tsx b/packages/client/src/schemas/menu/demos/demo4.tsx new file mode 100644 index 000000000..c9c2e0483 --- /dev/null +++ b/packages/client/src/schemas/menu/demos/demo4.tsx @@ -0,0 +1,98 @@ +import React, { useRef } from 'react'; +import { SchemaRenderer } from '@nocobase/client'; +import { Layout } from 'antd'; + +const schema = { + type: 'object', + properties: { + menu1: { + type: 'void', + 'x-component': 'Menu', + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component-props': { + sideMenuRef: '{{ sideMenuRef }}', + mode: 'mix', + theme: 'dark', + }, + properties: { + item1: { + type: 'void', + title: `菜单1`, + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.Item', + }, + item2: { + type: 'void', + title: `菜单2`, + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.Item', + }, + item3: { + type: 'void', + title: '菜单组3', + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.SubMenu', + properties: { + item5: { + type: 'void', + title: `子菜单5`, + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.SubMenu', + properties: { + item8: { + type: 'void', + title: `子菜单8`, + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.Item', + }, + item9: { + type: 'void', + title: `子菜单9`, + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.Item', + }, + }, + }, + }, + }, + item4: { + type: 'void', + title: '菜单组4', + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.SubMenu', + properties: { + item6: { + type: 'void', + title: `子菜单6`, + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.Item', + }, + item7: { + type: 'void', + title: `子菜单7`, + 'x-designable-bar': 'Menu.DesignableBar', + 'x-component': 'Menu.Item', + }, + }, + }, + }, + }, + }, +}; + +export default () => { + const sideMenuRef = useRef(); + return ( + + + + + + + + + ); +}; diff --git a/packages/client/src/schemas/menu/index.md b/packages/client/src/schemas/menu/index.md index 6be070d5c..b3d6f2646 100644 --- a/packages/client/src/schemas/menu/index.md +++ b/packages/client/src/schemas/menu/index.md @@ -51,539 +51,16 @@ group: ### 横向菜单 -```tsx -/** - * title: 横向菜单 - */ -import React from 'react'; -import { SchemaRenderer } from '../'; - -const schema = { - type: 'object', - properties: { - menu1: { - type: 'void', - 'x-component': 'Menu', - 'x-designable-bar': 'Menu.DesignableBar', - 'x-component-props': { - mode: 'horizontal', - theme: 'dark', - }, - properties: { - item1: { - type: 'void', - title: `菜单1`, - 'x-component': 'Menu.Item', - }, - item2: { - type: 'void', - title: `菜单2`, - 'x-component': 'Menu.Item', - }, - item3: { - type: 'void', - title: '菜单组3', - 'x-component': 'Menu.SubMenu', - properties: { - item5: { - type: 'void', - title: `子菜单5`, - 'x-component': 'Menu.SubMenu', - properties: { - item8: { - type: 'void', - title: `子菜单8`, - 'x-component': 'Menu.Item', - }, - item9: { - type: 'void', - title: `子菜单9`, - 'x-component': 'Menu.Item', - }, - }, - }, - } - }, - item4: { - type: 'void', - title: '菜单组4', - 'x-component': 'Menu.SubMenu', - properties: { - item6: { - type: 'void', - title: `子菜单6`, - 'x-component': 'Menu.Item', - }, - item7: { - type: 'void', - title: `子菜单7`, - 'x-component': 'Menu.Item', - }, - } - }, - }, - }, - }, -} - -export default () => { - return ( - - ); -}; -``` + ### 竖向菜单 -```tsx -/** - * title: 竖向菜单 - */ -import React from 'react'; -import { SchemaRenderer } from '../'; - -const schema = { - type: 'object', - properties: { - menu1: { - type: 'void', - name: 'name1', - 'x-component': 'Menu', - // 'x-decorator': 'Menu.Designable', - 'x-component-props': { - mode: 'inline', - }, - properties: { - - item1: { - type: 'void', - title: `菜单1`, - 'x-component': 'Menu.Item', - }, - item2: { - type: 'void', - title: `菜单2`, - 'x-component': 'Menu.Item', - }, - item3: { - type: 'void', - title: '菜单组3', - 'x-component': 'Menu.SubMenu', - properties: { - item4: { - type: 'void', - title: `子菜单4`, - 'x-component': 'Menu.Item', - }, - item5: { - type: 'void', - title: `子菜单5`, - 'x-component': 'Menu.Item', - }, - } - }, - item4: { - type: 'void', - title: '菜单组4', - 'x-component': 'Menu.SubMenu', - properties: { - item6: { - type: 'void', - title: `子菜单6`, - 'x-component': 'Menu.Item', - }, - item7: { - type: 'void', - title: `子菜单7`, - 'x-component': 'Menu.Item', - }, - } - }, - }, - }, - }, -} - -export default () => { - return ( -
- ); -}; -``` + ### 混合菜单 -```tsx -import React, { useRef, useState } from 'react'; -import { SchemaRenderer } from '../'; -import { MenuContainerContext } from './'; -import { Layout } from 'antd'; - -export default () => { - const sideMenuRef = useRef(); - - const [activeKey, setActiveKey] = useState('item3'); - - const onSelect = (info) => { - setActiveKey(info.key); - console.log({ info }) - } - - const schema = { - type: 'object', - properties: { - menu1: { - type: 'void', - 'x-component': 'Menu', - 'x-component-props': { - sideMenuRef: '{{ sideMenuRef }}', - defaultSelectedKeys: [activeKey], - mode: 'mix', - theme: 'dark', - onSelect: '{{ onSelect }}', - }, - properties: { - item1: { - type: 'void', - title: `菜单1`, - 'x-component': 'Menu.Item', - }, - item2: { - type: 'void', - title: `菜单2`, - 'x-component': 'Menu.Item', - }, - item3: { - type: 'void', - title: '菜单组3', - 'x-component': 'Menu.SubMenu', - properties: { - item4: { - type: 'void', - title: `子菜单4`, - 'x-component': 'Menu.Item', - }, - item5: { - type: 'void', - title: `子菜单5`, - 'x-component': 'Menu.SubMenu', - properties: { - item8: { - type: 'void', - title: `子菜单8`, - 'x-component': 'Menu.Item', - }, - item9: { - type: 'void', - title: `子菜单9`, - 'x-component': 'Menu.Item', - }, - }, - }, - } - }, - item4: { - type: 'void', - title: '菜单组4', - 'x-component': 'Menu.SubMenu', - properties: { - item6: { - type: 'void', - title: `子菜单6`, - 'x-component': 'Menu.Item', - }, - item7: { - type: 'void', - title: `子菜单7`, - 'x-component': 'Menu.Item', - }, - } - }, - }, - }, - }, - } - - return ( -
- - - - - - - - - {activeKey} - - - -
- ) -} -``` - -### 设计器模式 - -```tsx -import React, { useRef, useState } from 'react'; -import { SchemaRenderer } from '../'; -import { MenuContainerContext } from './'; -import { Layout } from 'antd'; - -export default () => { - const sideMenuRef = useRef(); - - const [activeKey, setActiveKey] = useState('item3'); - - const onSelect = (info) => { - setActiveKey(info.key); - console.log({ info }) - } - - const schema = { - type: 'object', - properties: { - menu1: { - type: 'void', - 'x-component': 'Menu', - 'x-designable-bar': 'Menu.DesignableBar', - 'x-component-props': { - defaultSelectedKeys: [activeKey], - mode: 'mix', - theme: 'dark', - sideMenuRef: '{{ sideMenuRef }}', - onSelect: '{{ onSelect }}', - }, - properties: { - item1: { - type: 'void', - title: `菜单1`, - 'x-component': 'Menu.Item', - }, - item2: { - type: 'void', - title: `菜单2`, - 'x-component': 'Menu.Item', - }, - item3: { - type: 'void', - title: '菜单组3', - 'x-component': 'Menu.SubMenu', - properties: { - item34: { - type: 'void', - title: `子菜单4`, - 'x-component': 'Menu.Item', - }, - item5: { - type: 'void', - title: `子菜单5`, - 'x-component': 'Menu.SubMenu', - properties: { - item8: { - type: 'void', - title: `子菜单8`, - 'x-component': 'Menu.Item', - }, - item9: { - type: 'void', - title: `子菜单9`, - 'x-component': 'Menu.Item', - }, - }, - }, - } - }, - item4: { - type: 'void', - title: '菜单组4', - 'x-component': 'Menu.SubMenu', - properties: { - item6: { - type: 'void', - title: `子菜单6`, - 'x-component': 'Menu.Item', - }, - item7: { - type: 'void', - title: `子菜单7`, - 'x-component': 'Menu.Item', - }, - } - }, - }, - }, - }, - } - - return ( -
- - - - - - - - - {activeKey} - - - -
- ) -} -``` - -### 设计器模式 - 菜单项为空时 - -```tsx -import React, { useRef, useState } from 'react'; -import { SchemaRenderer } from '../'; -import { MenuContainerContext } from './'; -import { Layout } from 'antd'; - -export default () => { - const sideMenuRef = useRef(); - - const [activeKey, setActiveKey] = useState('item3'); - - const onSelect = (info) => { - setActiveKey(info.key); - console.log({ info }) - } - - const schema = { - type: 'object', - properties: { - menu1: { - type: 'void', - 'x-component': 'Menu', - 'x-designable-bar': 'Menu.DesignableBar', - 'x-component-props': { - defaultSelectedKeys: [activeKey], - mode: 'mix', - theme: 'dark', - sideMenuRef: '{{ sideMenuRef }}', - onSelect: '{{ onSelect }}', - }, - }, - }, - } - - return ( -
- - - - - - - - - {activeKey} - - - -
- ) -} -``` + ### Menu.Action - -```tsx -/** - * title: 横向菜单 - */ -import React from 'react'; -import { SchemaRenderer } from '../'; - -const schema = { - type: 'object', - properties: { - menu1: { - type: 'void', - 'x-component': 'Menu', - 'x-designable-bar': 'Menu.DesignableBar', - 'x-component-props': { - mode: 'horizontal', - theme: 'dark', - }, - properties: { - item1: { - type: 'void', - title: `菜单1`, - 'x-component': 'Menu.Item', - }, - item2: { - type: 'void', - title: `菜单1`, - 'x-component': 'Menu.Action', - properties: { - drawer1: { - type: 'void', - title: '抽屉标题', - 'x-component': 'Action.Drawer', - 'x-component-props': {}, - properties: { - input: { - type: 'string', - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - action2: { - type: 'void', - title: '打开二级抽屉', - // 'x-decorator': 'FormItem', - 'x-component': 'Action', - properties: { - drawer1: { - type: 'void', - title: '二级抽屉标题', - 'x-component': 'Action.Drawer', - 'x-component-props': {}, - properties: { - input: { - type: 'string', - 'x-component': 'Input', - }, - }, - }, - }, - } - }, - }, - }, - }, - }, - }, - }, -} - -export default () => { - return ( - - ); -}; -``` + diff --git a/packages/client/src/schemas/menu/index.tsx b/packages/client/src/schemas/menu/index.tsx index 87d7be5c7..07738cc4c 100644 --- a/packages/client/src/schemas/menu/index.tsx +++ b/packages/client/src/schemas/menu/index.tsx @@ -5,6 +5,7 @@ import React, { useEffect, useRef, useState, + forwardRef, } from 'react'; import { connect, @@ -29,311 +30,94 @@ import { Modal, Button, } from 'antd'; -import get from 'lodash/get'; import { uid } from '@formily/shared'; -import { - MenuOutlined, - GroupOutlined, - PlusOutlined, - LinkOutlined, - AppstoreAddOutlined, - EditOutlined, - DeleteOutlined, - ArrowRightOutlined, - SettingOutlined, - ArrowUpOutlined, - ArrowDownOutlined, -} from '@ant-design/icons'; -import './style.less'; -import { Icon } from '../icon-picker'; -import { useHistory } from 'react-router-dom'; import cls from 'classnames'; -import ReactDOM from 'react-dom'; +import { useDesignable } from '../../components/schema-renderer'; +import { MenuOutlined } from '@ant-design/icons'; +import { IconPicker } from '../../components/icon-picker'; +import { VisibleContext } from '..'; import { useMount } from 'ahooks'; -import { useDesignable, SchemaRenderer } from '..'; -import { Router } from 'react-router'; -import { Action, useDefaultAction } from '../action'; +import './style.less'; -export type MenuType = React.FC & { - Item?: React.FC; - SubMenu?: React.FC; - Divider?: React.FC; - DesignableBar?: React.FC; - AddNew?: React.FC; - Link?: React.FC; - Action?: React.FC; - Url?: React.FC; +export const MenuModeContext = createContext(null); + +const SideMenu = (props: any) => { + const { visible, selectedKey, onSelect } = props; + const { schema } = useDesignable(); + if (!selectedKey || !visible) { + return null; + } + const child = schema.properties && schema.properties[selectedKey]; + if (!child || child['x-component'] !== 'Menu.SubMenu') { + return null; + } + + return ( + + + {selectedKey} + + ); }; -export const MenuContext = createContext({ - mode: null, - designableBar: null, -}); +export const Menu: any = observer((props: any) => { + const { mode, onSelect, sideMenuRef, ...others } = props; + const { schema } = useDesignable(); + const [selectedKey, setSelectedKey] = useState(null); + const ref = useRef(); -function useDesignableBar() { - const { designableBar } = useContext(MenuContext); - const options = useContext(SchemaOptionsContext); - const DesignableBar = designableBar - ? get(options.components, designableBar) - : null; - return DesignableBar || (() => null); -} - -export const Menu: MenuType = observer((props: any) => { - const { - children, - sideMenuRef, - onSelect, - mode, - defaultSelectedKeys, - ...others - } = props; - let defaultSelectedKey = defaultSelectedKeys ? defaultSelectedKeys[0] : null; - const { schema, schema: designableSchema, refresh } = useDesignable(); - const designableBar = schema['x-designable-bar']; - const history = useHistory(); - const renderSideMenu = (selectedKey) => { - if ((mode as any) !== 'mix') { - return; - } - if (!sideMenuRef || !sideMenuRef.current) { - return; - } - if (!selectedKey || !schema.properties) { - sideMenuRef.current.style.display = 'none'; - return; - } - const subSchema = schema.properties[selectedKey]; - if (!subSchema) { - sideMenuRef.current.style.display = 'none'; - ReactDOM.render(null, sideMenuRef.current); - return; - } - if (subSchema['x-component'] !== 'Menu.SubMenu') { - sideMenuRef.current.style.display = 'none'; - return; - } - const properties = subSchema.properties || {}; - sideMenuRef.current.style.display = 'block'; - const newProps = {}; - Object.keys(properties || {}).forEach((name) => { - newProps[name] = properties[name].toJSON(); - }); - ReactDOM.render( - - { - const selected = designableSchema.properties[selectedKey]; - const diff = subSchema.properties[`${schema.name}.${selectedKey}`]; - Object.keys(selected.properties || {}).forEach((name) => { - selected.properties[name].parent.removeProperty(name); - }); - Object.keys(diff.properties).forEach((name) => { - if (name.endsWith('-add-new')) { - return; - } - console.log('diff', name); - const current = diff.properties[name]; - selected.addProperty(current.name, current.toJSON()); - }); - console.log({ selected }); - refresh(); - }} - schema={{ - type: 'void', - name: `${schema.name}.${selectedKey}`, - 'x-component': 'Menu', - 'x-designable-bar': designableBar, - 'x-component-props': { - mode: 'inline', - onSelect, - }, - properties: { - ...newProps, - [`${uid()}-add-new`]: { - type: 'void', - parentKey: subSchema['key'], - 'x-component': 'Menu.AddNew', - }, - }, - }} - /> - , - sideMenuRef.current, - ); - }; useMount(() => { - console.log({ defaultSelectedKey }, schema.properties); - renderSideMenu(defaultSelectedKey); + if (mode !== 'mix') { + return; + } + const sideMenuElement = sideMenuRef && (sideMenuRef.current as HTMLElement); + if (sideMenuElement && ref.current) { + sideMenuElement.querySelector(':scope > div').appendChild(ref.current); + } }); - const isEmpty = !Object.keys(designableSchema.properties || {}).length; - console.log({ designableSchema }); + return ( - + { - console.log('info.key', info.key); - renderSideMenu(info.key); + if (mode === 'mix') { + setSelectedKey(info.key); + } onSelect && onSelect(info); }} - mode={(mode as any) === 'mix' ? 'horizontal' : mode} > - {!isEmpty ? ( - - ) : ( - { - Object.keys(subSchema.properties).forEach((name) => { - if (name === 'add-new') { - return; - } - designableSchema.addProperty( - name, - subSchema.properties[name].toJSON(), - ); - }); - refresh(); - }} - schema={{ - type: 'object', - properties: { - 'add-new': { - parentKey: schema['key'], - type: 'void', - 'x-component': 'Menu.AddNew', - }, - }, - }} - /> - )} + + 新增 + }> - + {mode === 'mix' && ( +
+ +
+ )} + ); }); -const AddNewAction = () => { - const { schema, insertBefore } = useDesignable(); - return ( - - { - const s = insertBefore({ - type: 'void', - title: uid(), - key: uid(), - 'x-component': 'Menu.Item', - }); - console.log('s.s.s.s.s.s', s); - }} - style={{ minWidth: 150 }} - > - 新建菜单 - - { - const s = insertBefore({ - type: 'void', - key: uid(), - title: uid(), - 'x-component': 'Menu.SubMenu', - }); - }} - > - 新建分组 - - - 添加链接 - - - } - > - - - ); -}; - -Menu.AddNew = observer((props) => { - const { designableBar } = useContext(MenuContext); - return designableBar ? ( - } - > - ) : null; -}); - -Menu.Url = observer((props) => { - const DesignableBar = useDesignableBar(); - const { schema } = useDesignable(); - return ( - { - window.open(props.url); - }} - icon={props.icon ? : undefined} - > - {schema.title} - - - ); -}); - -Menu.Link = observer((props) => { - const history = useHistory(); - const DesignableBar = useDesignableBar(); - const { schema } = useDesignable(); - return ( - { - history.push(schema.name as string); - }} - icon={props.icon ? : undefined} - > - {schema.title} - - - ); -}); +Menu.Divider = observer(AntdMenu.Divider); Menu.Item = observer((props: any) => { - const { useAction = useDefaultAction, ...others } = props; - const { run } = useAction(); - const DesignableBar = useDesignableBar(); - const { schema } = useDesignable(); + const { icon } = props; + const { schema, DesignableBar } = useDesignable(); return ( { - await run(); - }} - schema={schema} - // @ts-ignore + {...props} + icon={} eventKey={schema.name} key={schema.name} - icon={props.icon ? : undefined} > {schema.title} @@ -342,32 +126,39 @@ Menu.Item = observer((props: any) => { }); Menu.Action = observer((props: any) => { - const { icon, ...others } = props; - // const DesignableBar = useDesignableBar(); - const { schema } = useDesignable(); + const { icon } = props; + const { schema, DesignableBar } = useDesignable(); + const [visible, setVisible] = useState(false); return ( - : undefined} - ButtonComponent={AntdMenu.Item} - {...others} - /> + + } + onClick={() => { + setVisible(true); + }} + > + {schema.title} + + + {props.children} + {/* */} + ); }); -Menu.SubMenu = observer((props) => { - const DesignableBar = useDesignableBar(); - const { schema } = useDesignable(); - const { mode } = useContext(MenuContext); +Menu.SubMenu = observer((props: any) => { + const { icon } = props; + const { schema, DesignableBar } = useDesignable(); + const mode = useContext(MenuModeContext); return mode === 'mix' ? ( ) : ( } title={ <> {schema.title} @@ -375,28 +166,12 @@ Menu.SubMenu = observer((props) => { } eventKey={schema.name} key={schema.name} - icon={ - props.icon ? ( - - ) : undefined - } - /> + > + + ); }); -Menu.Divider = observer(AntdMenu.Divider); - Menu.DesignableBar = (props) => { const field = useField(); const [visible, setVisible] = useState(false); @@ -481,10 +256,7 @@ Menu.DesignableBar = (props) => { }); }} > - 删除菜单 - - - + 删除菜单 } @@ -496,27 +268,4 @@ Menu.DesignableBar = (props) => { ); }; -function ModalButton() { - const [visible, setVisible] = useState(false); - return ( - <> -
{ - setVisible(true); - }} - > - 按钮 -
- { - setVisible(false); - }} - > - aaa - - - ); -} - export default Menu; diff --git a/packages/client/src/schemas/table/demos/demo1.tsx b/packages/client/src/schemas/table/demos/demo1.tsx index c69f6ef7c..89411b5a6 100644 --- a/packages/client/src/schemas/table/demos/demo1.tsx +++ b/packages/client/src/schemas/table/demos/demo1.tsx @@ -1,9 +1,9 @@ import React from 'react'; import { SchemaRenderer } from '../..'; +import { Table } from '../'; import { uid } from '@formily/shared'; -import Editor from '@monaco-editor/react'; import { createForm } from '@formily/core'; -import { observer } from '@formily/react'; +import { ISchema, observer } from '@formily/react'; function useAction() { return { @@ -13,7 +13,7 @@ function useAction() { } } -const schema = { +const schema: ISchema = { name: `table_${uid()}`, type: 'array', 'x-component': 'Table', @@ -49,66 +49,52 @@ const schema = { popover1: { type: 'void', title: '弹窗标题', + 'x-decorator': 'Form', 'x-component': 'Action.Popover', 'x-component-props': {}, properties: { - [uid()]: { - name: 'form', + filter: { + name: 'filter', type: 'object', - 'x-component': 'Form', + 'x-component': 'Filter', properties: { - filter: { - name: 'filter', - type: 'object', - 'x-component': 'Filter', - properties: { - column1: { - type: 'void', - title: '字段1', - 'x-component': 'Filter.Column', - 'x-component-props': { - operations: [ - { label: '等于', value: 'eq' }, - { label: '不等于', value: 'ne' }, - ], - }, - properties: { - field1: { - type: 'string', - 'x-component': 'Input', - }, - }, - }, - column2: { - type: 'void', - title: '字段2', - 'x-component': 'Filter.Column', - 'x-component-props': { - operations: [ - { label: '大于', value: 'gt' }, - { label: '小于', value: 'lt' }, - { label: '非空', value: 'notNull', noValue: true }, - ], - }, - properties: { - field1: { - type: 'number', - 'x-component': 'InputNumber', - }, - }, - }, - } - }, - action: { + column1: { type: 'void', - title: '提交', - 'x-component': 'Action', + title: '字段1', + 'x-component': 'Filter.Column', 'x-component-props': { - useAction: '{{ useTableFilterAction }}', + operations: [ + { label: '等于', value: 'eq' }, + { label: '不等于', value: 'ne' }, + ], + }, + properties: { + field1: { + type: 'string', + 'x-component': 'Input', + }, }, }, - }, - }, + column2: { + type: 'void', + title: '字段2', + 'x-component': 'Filter.Column', + 'x-component-props': { + operations: [ + { label: '大于', value: 'gt' }, + { label: '小于', value: 'lt' }, + { label: '非空', value: 'notNull', noValue: true }, + ], + }, + properties: { + field1: { + type: 'number', + 'x-component': 'InputNumber', + }, + }, + }, + } + } }, }, }, @@ -148,7 +134,7 @@ const schema = { title: '提交', 'x-component': 'Action', 'x-component-props': { - useAction: '{{ useTableCreateAction }}', + useAction: '{{ Table.useTableCreateAction }}', }, }, }, @@ -163,7 +149,7 @@ const schema = { title: '删除', 'x-component': 'Action', 'x-component-props': { - useAction: '{{ useTableDestroyAction }}', + useAction: '{{ Table.useTableDestroyAction }}', }, }, }, @@ -340,7 +326,7 @@ const schema = { type: 'void', 'x-component': 'Form', 'x-component-props': { - useValues: '{{ useTableRow }}', + useValues: '{{ Table.useTableRow }}', }, properties: { field1: { @@ -360,7 +346,7 @@ const schema = { title: '提交', 'x-component': 'Action', 'x-component-props': { - useAction: '{{ useTableUpdateAction }}', + useAction: '{{ Table.useTableUpdateAction }}', }, }, }, @@ -374,7 +360,7 @@ const schema = { title: '删除', 'x-component': 'Action', 'x-component-props': { - useAction: '{{ useTableDestroyAction }}', + useAction: '{{ Table.useTableDestroyAction }}', }, }, [uid()]: { @@ -474,7 +460,7 @@ const schema = { type: 'void', 'x-component': 'Form', 'x-component-props': { - useValues: '{{ useTableRow }}', + useValues: '{{ Table.useTableRow }}', }, properties: { field1: { @@ -494,7 +480,7 @@ const schema = { title: '提交', 'x-component': 'Action', 'x-component-props': { - useAction: '{{ useTableUpdateAction }}', + useAction: '{{ Table.useTableUpdateAction }}', }, }, }, @@ -508,7 +494,7 @@ const schema = { title: '删除', 'x-component': 'Action', 'x-component-props': { - useAction: '{{ useTableDestroyAction }}', + useAction: '{{ Table.useTableDestroyAction }}', }, }, }, @@ -525,7 +511,7 @@ const form = createForm({ export default observer(() => { return (
- +
); }); diff --git a/packages/client/src/schemas/table/index.tsx b/packages/client/src/schemas/table/index.tsx index a2968a470..398018e4a 100644 --- a/packages/client/src/schemas/table/index.tsx +++ b/packages/client/src/schemas/table/index.tsx @@ -26,14 +26,13 @@ import useRequest from '@ahooksjs/use-request'; import { BaseResult } from '@ahooksjs/use-request/lib/types'; import { uid, clone } from '@formily/shared'; import { MenuOutlined } from '@ant-design/icons'; -import { useVisibleContext } from '../action'; import { SortableHandle, SortableContainer, SortableElement, } from 'react-sortable-hoc'; import cls from 'classnames'; -import { getSchemaPath, useDesignable, useSchemaPath } from '../'; +import { getSchemaPath, useDesignable, useSchemaPath, VisibleContext } from '../'; import './style.less'; interface TableRowProps { @@ -198,7 +197,7 @@ export function useTableDestroyAction() { export function useTableFilterAction() { const { field, refresh, params } = useTableContext(); - const { setVisible } = useVisibleContext(); + const [,setVisible] = useContext(VisibleContext); const form = useForm(); return { async run() { @@ -210,7 +209,7 @@ export function useTableFilterAction() { export function useTableCreateAction() { const { field, run: exec, params } = useTableContext(); - const { setVisible } = useVisibleContext(); + const [,setVisible] = useContext(VisibleContext); const form = useForm(); return { async run() { @@ -227,7 +226,7 @@ export function useTableCreateAction() { export function useTableUpdateAction() { const { field, refresh, params } = useTableContext(); - const { setVisible } = useVisibleContext(); + const [,setVisible] = useContext(VisibleContext); const form = useForm(); return { async run() { @@ -317,7 +316,7 @@ const TableContainer = observer((props) => { {actionBars.top.map((actionBarSchema) => { return ( { ); }); +Table.useTableRow = useTableRow; +Table.useTableIndex = useTableIndex; +Table.useTableDestroyAction = useTableDestroyAction; +Table.useTableFilterAction = useTableFilterAction; +Table.useTableCreateAction = useTableCreateAction; +Table.useTableUpdateAction = useTableUpdateAction; + function Blank() { return null; }