diff --git a/packages/client/src/api.md b/packages/client/src/api.md deleted file mode 100644 index 2aa71b8c2..000000000 --- a/packages/client/src/api.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -title: API - 接口 -nav: - title: 组件 - path: /client -order: 99 -group: - order: 3 - title: 其他 - path: /client/others ---- - -# API - 接口 - -## setGlobalState - -## setGlobalActionState - -## useGlobalState - -## useGlobalAction - -## refreshGlobalAction - -## useAction - -## doAction diff --git a/packages/client/src/components/Drawer/index.md b/packages/client/src/components/Drawer/index.md deleted file mode 100644 index 84ca6a335..000000000 --- a/packages/client/src/components/Drawer/index.md +++ /dev/null @@ -1,110 +0,0 @@ ---- -title: Drawer - 抽屉 -nav: - title: 组件 - path: /client -group: - order: 3 - title: 其他 - path: /client/others ---- - -# Drawer - 抽屉 - -通过 `Drawer.open(props)` 方法打开抽屉,无需预渲染,可在触发事件中使用。 - -### 基础抽屉 - -```tsx -/** - * title: 基础抽屉 - */ -import React from 'react'; -import { Button } from 'antd'; -import Drawer from './index.tsx'; - -export default () => ( - -); -``` - -### 多层抽屉 - -```tsx -/** - * title: 多层抽屉 - * desc: 有多少层就执行多少个 `Drawer.open(props)` - */ -import React from 'react'; -import { Button } from 'antd'; -import Drawer from './index.tsx'; - -export default () => ( - - - ) - }, - }); - }}>Open drawer -); -``` - -### 关闭时提示 - -```tsx -/** - * title: 关闭时提示 - * desc: 通过 `closeWithConfirm(props)` 方法触发,更多参数请参考 `Modal.confirm` - */ -import React from 'react'; -import { Button } from 'antd'; -import Drawer from './index.tsx'; - -export default () => ( - -); -``` diff --git a/packages/client/src/components/Drawer/index.tsx b/packages/client/src/components/Drawer/index.tsx deleted file mode 100644 index f78c32401..000000000 --- a/packages/client/src/components/Drawer/index.tsx +++ /dev/null @@ -1,206 +0,0 @@ -import React, { Fragment, useLayoutEffect, useRef, useState } from 'react'; -import ReactDOM, { createPortal } from 'react-dom'; -import { Modal, Drawer as AntdDrawer } from 'antd'; -import { DrawerProps } from 'antd/lib/drawer'; -import { useContext } from 'react'; -import { ConfigProvider } from 'antd'; -import zhCN from 'antd/lib/locale/zh_CN'; -import { ModalFuncProps } from 'antd/lib/modal/Modal' -import isNum from 'lodash/isNumber'; -import isBool from 'lodash/isBoolean'; -import isStr from 'lodash/isString'; -import './style.less'; - -export const usePrefixCls = ( - tag?: string, - props?: { - prefixCls?: string; - }, -) => { - const { getPrefixCls } = useContext(ConfigProvider.ConfigContext); - return getPrefixCls(tag, props?.prefixCls); -}; - -type DrawerTitle = string | number | React.ReactElement; - -const isDrawerTitle = (props: any): props is DrawerTitle => { - return ( - isNum(props) || isStr(props) || isBool(props) || React.isValidElement(props) - ); -}; - -const getDrawerProps = (props: any): DrawerProps => { - if (isDrawerTitle(props)) { - return { - title: props, - }; - } else { - return props; - } -}; - -const createElement = (content, props?: any) => { - if (!content) { - return null; - } - if (typeof content === 'string') { - return content; - } - if (React.isValidElement(content)) { - return content; - } - return React.createElement(content, props); -}; - -export interface IDrawer { - open(props?: any): void; - close(): void; -} - -export function Drawer(title: DrawerProps, content: any): IDrawer; -export function Drawer(title: DrawerTitle, content: any): IDrawer; -export function Drawer(title: any, content: any): IDrawer { - document.querySelectorAll('.env-root').forEach((el) => { - el.className = 'env-root env-root-push'; - }); - const env = { - root: document.createElement('div'), - promise: null, - }; - env.root.className = 'env-root'; - const props = getDrawerProps(title); - const drawerProps = { - width: '75%', - ...props, - onClose: (e: any) => { - props?.onClose?.(e); - drawer.close(); - }, - afterVisibleChange: (visible: boolean) => { - props?.afterVisibleChange?.(visible); - if (visible) return; - ReactDOM.unmountComponentAtNode(env.root); - env.root?.parentNode?.removeChild(env.root); - env.root = undefined; - }, - }; - - const drawer: any = { - open: (props: any) => { - render( - false, - () => { - drawer.closeWithConfirm = null; - drawer.close(); - }, - () => { - drawer.close(); - }, - ); - setTimeout(() => { - render( - true, - () => { - drawer.closeWithConfirm = null; - drawer.close(); - }, - () => { - drawer.close(); - }, - ); - }); - }, - close: () => { - if (!env.root) return; - if (drawer.closeWithConfirm) { - Modal.confirm({ - okText: '确定', - cancelText: '取消', - ...drawer.closeWithConfirm, - onOk() { - drawer.closeWithConfirm = null; - const els = document.querySelectorAll('.env-root-push'); - if (els.length) { - const last = els[els.length - 1]; - last.className = 'env-root'; - } - render(false); - }, - }); - } else { - const els = document.querySelectorAll('.env-root-push'); - if (els.length) { - const last = els[els.length - 1]; - last.className = 'env-root'; - } - render(false); - } - }, - closeWithConfirm: null, - }; - - const closeWithConfirm = (props) => { - drawer.closeWithConfirm = props; - }; - - const render = (visible = true, resolve?: () => any, reject?: () => any) => { - ReactDOM.render( - - - {createElement(content, { - resolve, - reject, - closeWithConfirm, - })} - - , - env.root, - ); - }; - document.body.appendChild(env.root); - - return drawer; -} - -const DrawerFooter: React.FC = (props) => { - const ref = useRef(); - const [footer, setFooter] = useState(); - const footerRef = useRef(); - const prefixCls = usePrefixCls('drawer'); - useLayoutEffect(() => { - const content = ref.current?.closest(`.${prefixCls}-wrapper-body`); - if (content) { - if (!footerRef.current) { - footerRef.current = content.querySelector(`.${prefixCls}-footer`); - if (!footerRef.current) { - footerRef.current = document.createElement('div'); - footerRef.current.classList.add(`${prefixCls}-footer`); - content.appendChild(footerRef.current); - } - } - setFooter(footerRef.current); - } - }); - - footerRef.current = footer; - - return ( -
- {footer && createPortal(props.children, footer)} -
- ); -}; - -interface ContentPorps { - resolve?: () => any; - closeWithConfirm?: (props: ModalFuncProps) => any; -} - -Drawer.open = (props: DrawerProps & { content: (contentPorps?: ContentPorps) => any }) => { - const { content, visible, ...others } = props; - return Drawer(others, content).open({ visible }); -}; - -Drawer.Footer = DrawerFooter; - -export default Drawer; diff --git a/packages/client/src/components/Drawer/style.less b/packages/client/src/components/Drawer/style.less deleted file mode 100644 index 5c3c9f867..000000000 --- a/packages/client/src/components/Drawer/style.less +++ /dev/null @@ -1,18 +0,0 @@ -.env-root-push + style + div > div { - transform: translateX(-10%); -} -.env-root-push + div > div { - transform: translateX(-10%); -} -.ant-drawer.nb-drawer .ant-drawer-content-wrapper { - width: 75%; - max-width: 1000px; -} -@media only screen and (max-width: 800px) { - .ant-drawer.nb-drawer .ant-drawer-content-wrapper { - width: 100% !important; - } - .ant-drawer.noco-drawer .ant-drawer-content-wrapper { - width: 100% !important; - } -} diff --git a/packages/client/src/components/admin-layout/index.md b/packages/client/src/components/admin-layout/index.md deleted file mode 100644 index 276c9f236..000000000 --- a/packages/client/src/components/admin-layout/index.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: AdminLayout - 后台布局 -nav: - title: 组件 - path: /client -group: - order: 2 - title: Templates - path: /client/templates ---- - -# AdminLayout - 后台布局 - -内置的后台布局模板,提供了基础的菜单和路由切换。 diff --git a/packages/client/src/components/auth-layout/index.md b/packages/client/src/components/auth-layout/index.md deleted file mode 100644 index 7cc91617f..000000000 --- a/packages/client/src/components/auth-layout/index.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: AuthLayout - 登录布局 -nav: - title: 组件 - path: /client -group: - order: 2 - title: Templates - path: /client/templates ---- - -# AuthLayout - 登录布局 - -内置的登录、注册页布局 \ No newline at end of file diff --git a/packages/client/src/demo.md b/packages/client/src/demo.md new file mode 100644 index 000000000..3ef08f2d9 --- /dev/null +++ b/packages/client/src/demo.md @@ -0,0 +1,14 @@ +--- +title: 全站演示 +nav: + title: 组件 + path: /client +toc: menu +group: + order: 0 + title: 概念 + path: /client +--- + + + diff --git a/packages/client/src/index.md b/packages/client/src/index.md index 75384bf31..e9f1065f6 100644 --- a/packages/client/src/index.md +++ b/packages/client/src/index.md @@ -1,14 +1,14 @@ --- -title: 全站演示 +title: 介绍 nav: title: 组件 path: /client toc: menu group: order: 0 - title: 全站演示 + title: 概念 path: /client --- - +# 介绍 diff --git a/packages/client/src/schemas/DesignableSchemaField/index.tsx b/packages/client/src/schemas/DesignableSchemaField/index.tsx index 0236d9c11..c8daa40d9 100644 --- a/packages/client/src/schemas/DesignableSchemaField/index.tsx +++ b/packages/client/src/schemas/DesignableSchemaField/index.tsx @@ -23,7 +23,7 @@ import { uid, clone } from '@formily/shared'; import { ArrayCollapse, ArrayTable, FormLayout } from '@formily/antd'; import { Space, Card, Modal, Spin } from 'antd'; -import { Action, useLogin, useRegister, useSubmit } from '../action'; +import { Action, useLogin, useRegister, useSubmit, useDesignableValues } from '../action'; import { AddNew } from '../add-new'; import { Cascader } from '../cascader'; import { Checkbox } from '../checkbox'; @@ -73,6 +73,7 @@ export const scope = { useTableFilterAction, useTableRow, useTableUpdateAction, + useDesignableValues, }; export const components = { @@ -363,8 +364,8 @@ export const createDesignableSchemaField = (options) => { }} > - - + {props.debug && } + {props.debug && } ); }; @@ -435,6 +436,7 @@ export interface SchemaRendererProps { onlyRenderProperties?: boolean; scope?: any; components?: any; + debug?: boolean; } export const SchemaRenderer = (props: SchemaRendererProps) => { @@ -463,6 +465,7 @@ export const SchemaRenderer = (props: SchemaRendererProps) => { return ( ////////// 单节点 ////////// @@ -67,17 +66,16 @@ group: -操作有三类: +## Designable Bar -- 常规操作:Action -- 弹出层操作,弹出层可以是 Action.Drawer、Action.Modal、Action.Popover -- 指定容器内打开: Action.Container -- 下拉菜单:Action.Dropdown,用于收纳多种操作 -- 跳转操作:Action.Link、Action.URL +- Action.DesignableBar +- Action.Modal.DesignableBar +- Action.Drawer.DesignableBar +- Action.Popover.DesignableBar -Action.Drawer、Action.Modal、Action.Popover 和 Action.Container 需要和 Action 搭配使用 +## Examples -## Action - 常规操作 +### Action - 常规操作 ```tsx /** @@ -100,17 +98,18 @@ const schema = { name: 'action1', title: '按钮', 'x-component': 'Action', + 'x-designable-bar': 'Action.DesignableBar', 'x-component-props': { - useAction, + useAction: '{{ useAction }}', }, }; export default () => { - return + return } ``` -## Action.Link - 内链跳转 +### Action.Link - 内链跳转 ```tsx import React from 'react'; @@ -131,7 +130,7 @@ export default () => { } ``` -## Action.URL - 外链跳转 +### Action.URL - 外链跳转 ```tsx import React from 'react'; @@ -152,7 +151,7 @@ export default () => { } ``` -## Action.Dropdown - 下拉操作 +### Action.Dropdown - 下拉操作 ```tsx import React from 'react'; @@ -253,7 +252,7 @@ export default () => { } ``` -## Action.Popover - 打开气泡 +### Action.Popover - 打开气泡 ```tsx import React from 'react'; @@ -285,7 +284,7 @@ export default () => { } ``` -## Action.Drawer - 打开抽屉 +### Action.Drawer - 打开抽屉 ```tsx import React from 'react'; @@ -338,10 +337,13 @@ export default () => { } ``` -## Action.Modal - 打开对话框 +### Action.Modal - 打开对话框 + +`x-decorator='Form'` 时,Model 为 Form,并自带按钮 ```tsx import React from 'react'; +import { Space } from 'antd'; import { SchemaRenderer } from '../'; import { useVisibleContext } from './'; @@ -406,12 +408,40 @@ const schema = { }, }; +const schema2 = { + type: 'void', + name: 'action1', + title: 'x-decorator=Form', + 'x-component': 'Action', + properties: { + drawer1: { + type: 'void', + title: '弹窗标题', + 'x-component': 'Action.Modal', + 'x-component-props': {}, + 'x-decorator': 'Form', + properties: { + input: { + type: 'string', + 'x-decorator': 'FormItem', + 'x-component': 'Input', + }, + }, + }, + }, +}; + export default () => { - return + return ( + + + + + ) } ``` -## Action.Container - 指定容器内打开 +### Action.Container - 指定容器内打开 ```tsx import React, { useRef } from 'react'; diff --git a/packages/client/src/schemas/action/index.tsx b/packages/client/src/schemas/action/index.tsx index d249397f2..3799b53de 100644 --- a/packages/client/src/schemas/action/index.tsx +++ b/packages/client/src/schemas/action/index.tsx @@ -9,6 +9,7 @@ import { SchemaOptionsContext, Schema, useField, + SchemaExpressionScopeContext, } from '@formily/react'; import { Button, Dropdown, Menu, Popover, Space, Drawer, Modal } from 'antd'; import { Link, useHistory, LinkProps } from 'react-router-dom'; @@ -22,6 +23,9 @@ import { uid } from '@formily/shared'; import './style.less'; import constate from 'constate'; +import { Icon } from '../icon-picker'; +import { useMemo } from 'react'; +import { createForm } from '@formily/core'; export function useDefaultAction() { return { @@ -109,6 +113,7 @@ const BaseAction = observer((props: any) => { const { ButtonComponent = Button, className, + icon, useAction = useDefaultAction, ...others } = props; @@ -122,11 +127,10 @@ const BaseAction = observer((props: any) => { field.componentProps.setVisible = setVisible; }, []); - console.log('BaseAction', { field, schema, fieldSchema }, field.title); - const renderButton = () => ( } className={classNames(className, `name-${schema.name}`)} onClick={async (e) => { e.stopPropagation && e.stopPropagation(); @@ -227,7 +231,24 @@ Action.Popover = observer((props) => { Action.Drawer = observer((props) => { const field = useField(); + // const { visible, setVisible } = useVisibleContext(); + const { useAction = () => ({ async run() {} }), ...others } = props; + const { schema } = useDesignable(); const { visible, setVisible } = useVisibleContext(); + const { run } = useAction(); + const form = useForm(); + console.log(`schema['x-decorator']`, schema['x-decorator']) + if (schema['x-decorator'] === 'Form.Decorator') { + Object.assign(others, { + footer: ( + + + + + ), + }); + } + return ( { @@ -235,7 +256,7 @@ Action.Drawer = observer((props) => { }} title={field.title} width={'50%'} - {...props} + {...others} visible={visible} onClose={(e) => { e.stopPropagation(); @@ -247,103 +268,142 @@ Action.Drawer = observer((props) => { ); }); +const [DesignableContextProvider, useDesignableContext] = constate(() => { + return useDesignable(); +}); + +import { DesignableBar } from './designableBar'; +import { cloneDeep } from 'lodash'; +import { clone } from '@formily/shared'; + +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 field = useField(); + const { useAction = () => ({ async run() {} }), ...others } = props; + const { schema } = useDesignable(); + const { setVisible: setDropdownVisible } = useDropdownVisibleContext(); const { visible, setVisible } = useVisibleContext(); + const { run } = useAction(); + const form = useForm(); + if (schema['x-decorator'] !== 'Form.Decorator') { + Object.assign(others, { footer: null }); + } return ( { - // e.stopPropagation(); - // }} - title={field.title} + title={schema.title} width={'50%'} - {...props} + {...others} visible={visible} closable maskClosable - onCancel={(e) => { + destroyOnClose + onCancel={async (e) => { e.stopPropagation(); setVisible(false); + setDropdownVisible && setDropdownVisible(false); + }} + onOk={async (e) => { + console.log('onOk', form.values); + // await form.submit(); + await run(); + // e.stopPropagation(); + setVisible(false); + setDropdownVisible && setDropdownVisible(false); }} - footer={null} > -
e.stopPropagation()}>{props.children}
+
e.stopPropagation()} + > + {props.children} +
); }); -Action.Dropdown = observer((props) => { - // const { visible, setVisible } = useVisibleContext(); +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(); return ( - <> { - // setVisible(visible); - // }} - {...props} + visible={visible} + onVisibleChange={(visible) => { + setVisible(visible); + }} + // {...props} overlayClassName={'nb-action-group'} // trigger={'click'} content={props.children} placement={'bottomLeft'} > - + - {/* popover 的按钮初始化时并未渲染,暂时先这么处理 */} -
{props.children}
- + ); +}); + +Action.Dropdown = observer((props) => { + return ( + + +
{props.children}
+
); }); Action.DesignableBar = () => { const field = useField(); // const schema = useFieldSchema(); - const { schema, insertAfter } = useDesignable(); + const { schema, insertAfter, refresh } = useDesignable(); const [visible, setVisible] = useState(false); return ( -
- { - e.stopPropagation(); - }} - className={classNames('designable-bar-actions', { active: visible })} - > - { - setVisible(visible); + +
+ { + e.stopPropagation(); }} - overlay={ - - { - console.log({ field, schema }); - schema.title = '按钮文案被修改了'; - field.setTitle('按钮文案被修改了'); - schema.properties.drawer1.title = '抽屉标题文案被修改了'; - setVisible(false); - }} - > - 点击修改按钮文案 - - { - insertAfter({ - name: uid(), - 'x-component': 'Input', - }); - }} - > - insertAfter - - - } + className={classNames('designable-bar-actions', { active: visible })} > - - - -
+ +
+
+ ); }; diff --git a/packages/client/src/schemas/action/style.less b/packages/client/src/schemas/action/style.less index 518755856..1c686150c 100644 --- a/packages/client/src/schemas/action/style.less +++ b/packages/client/src/schemas/action/style.less @@ -80,3 +80,16 @@ } } } + + +.designable-bar-actions { + .ant-btn { + border: 0; + padding: 0; + background: none; + height: auto; + line-height: 1em; + width: auto; + color: #fff; + } +} \ No newline at end of file diff --git a/packages/client/src/schemas/add-new/index.md b/packages/client/src/schemas/add-new/index.md index 47af7df69..cb51b80e0 100644 --- a/packages/client/src/schemas/add-new/index.md +++ b/packages/client/src/schemas/add-new/index.md @@ -11,7 +11,7 @@ group: # AddNew - 新增 -## 组件节点树 +## Node Tree
 // 简单场景,只支持上下拖拽布局
@@ -24,7 +24,7 @@ group:
 
 // 栅格布局,支持行列等复杂的拖拽操作
 
-  
+  
     
       // 常规区块
       
@@ -35,7 +35,11 @@ group:
 
 
-## 代码演示 +## Designable Bar + +暂无 + +## Examples ### AddNew.BlockItem diff --git a/packages/client/src/schemas/block-item/index.md b/packages/client/src/schemas/block-item/index.md new file mode 100644 index 000000000..02850fad0 --- /dev/null +++ b/packages/client/src/schemas/block-item/index.md @@ -0,0 +1,26 @@ +--- +title: BlockItem - 区块项 +nav: + title: 组件 + path: /client +group: + order: 1 + title: Schemas + path: /client/schemas +--- + +# BlockItem - 区块项 + +## Node Tree + +通常 BlockItem 并不单独占用一个节点,而是节点的 x-decorator + +
+
+
+
+BlockItem 的作用主要用于处理 DesignableBar,如:
+
+
+
+ \ No newline at end of file diff --git a/packages/client/src/schemas/cascader/index.md b/packages/client/src/schemas/cascader/index.md index d9a07d863..9e494d40c 100644 --- a/packages/client/src/schemas/cascader/index.md +++ b/packages/client/src/schemas/cascader/index.md @@ -11,13 +11,17 @@ group: # Cascader - 级联选择 -## 组件节点树 +## Node Tree
   
 
-## 代码演示 +## Designable Bar + +- Cascader.DesignableBar + +## Examples ### 省市区级联 diff --git a/packages/client/src/schemas/checkbox/index.md b/packages/client/src/schemas/checkbox/index.md index d4969e556..61cc42bc6 100644 --- a/packages/client/src/schemas/checkbox/index.md +++ b/packages/client/src/schemas/checkbox/index.md @@ -11,7 +11,7 @@ group: # Checkbox - 多选框 -## 组件节点树 +## Node Tree
 // 勾选
@@ -20,7 +20,11 @@ group:
 
 
-## 代码演示 +## Designable Bar + +- Checkbox.DesignableBar + +## Examples ### 勾选 diff --git a/packages/client/src/schemas/color-select/index.md b/packages/client/src/schemas/color-select/index.md index 472bbaf5e..9c368164c 100644 --- a/packages/client/src/schemas/color-select/index.md +++ b/packages/client/src/schemas/color-select/index.md @@ -11,13 +11,17 @@ group: # ColorSelect - 颜色选择器 -## 组件节点树 +## Node Tree
 
 
-## 代码演示 +## Designable Bar + +- ColorSelect.DesignableBar + +## Examples ### 颜色选择器 diff --git a/packages/client/src/schemas/database-field/index.md b/packages/client/src/schemas/database-field/index.md index 8bf5d06b7..67a2db759 100644 --- a/packages/client/src/schemas/database-field/index.md +++ b/packages/client/src/schemas/database-field/index.md @@ -11,20 +11,23 @@ group: # DatabaseField - 数据表字段 -## 组件节点树 +## Node Tree
 
 
-## 代码演示 +## Designable Bar + +暂无 + +## Examples ```tsx import React from 'react'; import { createForm } from '@formily/core'; import { SchemaRenderer } from '../'; import { observer, connect, useField } from '@formily/react'; -import Editor from '@monaco-editor/react'; const schema = { type: 'object', @@ -66,11 +69,6 @@ export default observer(() => { return (
-
) }) diff --git a/packages/client/src/schemas/date-picker/index.md b/packages/client/src/schemas/date-picker/index.md index 17215d016..dd460e507 100644 --- a/packages/client/src/schemas/date-picker/index.md +++ b/packages/client/src/schemas/date-picker/index.md @@ -11,13 +11,17 @@ group: # DatePicker - 日期选择器 -## 组件节点树 +## Node Tree
 
 
-## 代码演示 +## Designable Bar + +- DatePicker.DesignableBar + +## Examples ### 日期选择器 diff --git a/packages/client/src/schemas/designable-bar/index.md b/packages/client/src/schemas/designable-bar/index.md new file mode 100644 index 000000000..a81c23872 --- /dev/null +++ b/packages/client/src/schemas/designable-bar/index.md @@ -0,0 +1,25 @@ +--- +title: DesignableBar - 配置操作栏 +nav: + title: 组件 + path: /client +group: + order: 1 + title: Schemas + path: /client/schemas +--- + +# DesignableBar - 配置操作栏 + +用于修改节点的参数配置,DesignableBar 是所有配置操作栏的统称,不是固定的,可以根据不同节点定义不同的 `**.DesignableBar`。 + +## Node Tree + +通常 DesignableBar 并不单独占用一个节点,而是节点的 x-designable-bar + +
+
+ + + +数据组件的 DesignableBar 通常与 FormItem 搭配使用,非数据组件的 DesignableBar 通常与 BlockItem 搭配使用,也有少量如 Action、Menu 无需 BlockItem \ No newline at end of file diff --git a/packages/client/src/schemas/filter/index.md b/packages/client/src/schemas/filter/index.md index 682f3efce..bfc0202f0 100644 --- a/packages/client/src/schemas/filter/index.md +++ b/packages/client/src/schemas/filter/index.md @@ -11,7 +11,7 @@ group: # Filter - 筛选器 -## 组件节点树 +## Node Tree
 
@@ -24,16 +24,11 @@ group:
 
 
-## 代码演示 +## Designable Bar - +- Filter.DesignableBar + +## Examples ```tsx import React from 'react'; diff --git a/packages/client/src/schemas/form-item/index.md b/packages/client/src/schemas/form-item/index.md new file mode 100644 index 000000000..afe751185 --- /dev/null +++ b/packages/client/src/schemas/form-item/index.md @@ -0,0 +1,26 @@ +--- +title: FormItem - 表单项 +nav: + title: 组件 + path: /client +group: + order: 1 + title: Schemas + path: /client/schemas +--- + +# FormItem - 表单项 + +## Node Tree + +通常 FormItem 并不单独占用一个节点,而是节点的 x-decorator + +
+
+
+ +FormItem 的作用主要用于处理表单项(控件)的校验、布局等 + +
+
+
diff --git a/packages/client/src/schemas/form/index.md b/packages/client/src/schemas/form/index.md index 5f886d5e0..f0eab79d4 100644 --- a/packages/client/src/schemas/form/index.md +++ b/packages/client/src/schemas/form/index.md @@ -11,7 +11,7 @@ group: # Form - 表单 -## 组件节点树 +## Node Tree
 
@@ -19,9 +19,15 @@ group:
-## 代码演示 +## Designable Bar + +- Form.DesignableBar + +## Examples ### 常规表单 @@ -161,7 +167,7 @@ import { uid } from '@formily/shared'; const schema = { type: 'void', name: uid(), - 'x-decorator': 'Card', + 'x-decorator': 'BlockItem', 'x-component': 'Form', 'x-designable-bar': 'Form.DesignableBar', properties: { diff --git a/packages/client/src/schemas/form/index.tsx b/packages/client/src/schemas/form/index.tsx index 9fa68ca19..28631e70c 100644 --- a/packages/client/src/schemas/form/index.tsx +++ b/packages/client/src/schemas/form/index.tsx @@ -6,6 +6,8 @@ import { useFieldSchema, observer, SchemaExpressionScopeContext, + FormProvider, + ISchema, } from '@formily/react'; import { SchemaRenderer, useDesignable } from '../DesignableSchemaField'; import get from 'lodash/get'; @@ -42,7 +44,6 @@ function useDefaultValues() { export const Form: any = observer((props: any) => { const scope = useContext(SchemaExpressionScopeContext); - const { useValues = useDefaultValues } = props; const values = useValues(); const form = useMemo(() => { @@ -54,37 +55,37 @@ export const Form: any = observer((props: any) => { }, [values]); const schema = useFieldSchema(); const { schema: designableSchema, refresh } = useDesignable(); - const { DesignableBar } = useDesignableBar(); - const ref = useRef(); - const [active, setActive] = useState(false); - const { onMouseEnter, onMouseLeave, onMouseMove } = useMouseEvents(ref); - onMouseEnter((e: React.MouseEvent) => { - setActive(true); - }); - - onMouseLeave((e: React.MouseEvent) => { - setActive(false); - }); - - onMouseMove((e: React.MouseEvent) => {}); + const formSchema: ISchema = schema['x-decorator'] === 'Form' ? { + type: 'void', + "x-component": 'Blank', + properties: { + [schema.name]: { + ...schema.toJSON(), + "x-decorator": 'Form.Decorator', + } + } + } : { + ...schema.toJSON(), + 'x-component': 'Form.Blank', + 'x-component-props': {}, + }; return ( -
- { - designableSchema.properties = subSchema.properties; - refresh(); - }} - form={form} - schema={schema.toJSON()} - onlyRenderProperties - /> - -
+ { + designableSchema.properties = subSchema.properties; + refresh(); + }} + form={form} + schema={formSchema} + onlyRenderProperties + /> ); }); +Form.Decorator = ({children}) => children; + Form.DesignableBar = (props) => { const { active } = props; return ( diff --git a/packages/client/src/schemas/grid/index.md b/packages/client/src/schemas/grid/index.md index 270eb5a90..14fdb2e3a 100644 --- a/packages/client/src/schemas/grid/index.md +++ b/packages/client/src/schemas/grid/index.md @@ -13,21 +13,6 @@ group: 基于行(Row)和列(Col)来定义区块(Block)的外部框架。 -## 组件节点树 - -
-
-  
-    
-      // 添加其他节点
-    
-    
-      // 添加其他节点
-    
-  
-
-
- ## 列宽说明 最大支持四列,如果要支持越多列,需要处理的比例也越多。 @@ -88,4 +73,26 @@ group: - 100% + +## Node Tree + +
+
+  
+    
+      // 添加其他节点
+    
+    
+      // 添加其他节点
+    
+  
+
+
+ +## Designable Bar + +暂无 + +## Examples + diff --git a/packages/client/src/schemas/icon-picker/index.md b/packages/client/src/schemas/icon-picker/index.md index 489538465..07688fb89 100644 --- a/packages/client/src/schemas/icon-picker/index.md +++ b/packages/client/src/schemas/icon-picker/index.md @@ -11,13 +11,17 @@ group: # IconPicker - 图标选择器 -## 节点树 +## Node Tree
 
 
-## 代码演示 +## Designable Bar + +- IconPicker.DesignableBar + +## Examples ```tsx /** diff --git a/packages/client/src/schemas/input-number/index.md b/packages/client/src/schemas/input-number/index.md index 992eaa3d0..c97b861b4 100644 --- a/packages/client/src/schemas/input-number/index.md +++ b/packages/client/src/schemas/input-number/index.md @@ -11,13 +11,17 @@ group: # InputNumber - 数字框 -## 节点树 +## Node Tree
 
 
-## 代码演示 +## Designable Bar + +- InputNumber.DesignableBar + +## Examples ### 数字框 diff --git a/packages/client/src/schemas/input/index.md b/packages/client/src/schemas/input/index.md index 010542afc..557ae18a0 100644 --- a/packages/client/src/schemas/input/index.md +++ b/packages/client/src/schemas/input/index.md @@ -13,14 +13,19 @@ group: 输入框是非常常用的控件,参数可以组合成许多字段,如单行文本、多行文本、手机号、邮箱、网址等。 -## 节点树 +## Node Tree
 
 
 
-## 代码演示 +## Designable Bar + +- Input.DesignableBar +- Input.TextArea.DesignableBar + +## Examples ### 单行文本 diff --git a/packages/client/src/schemas/markdown/index.md b/packages/client/src/schemas/markdown/index.md index 3fcdead11..e1272d22c 100644 --- a/packages/client/src/schemas/markdown/index.md +++ b/packages/client/src/schemas/markdown/index.md @@ -11,13 +11,17 @@ group: # Markdown 编辑器 -## 节点树 +## Node Tree
 
 
-## 代码演示 +## Designable Bar + +- Markdown.DesignableBar + +## Examples ### Markdown 编辑器 diff --git a/packages/client/src/schemas/menu/index.md b/packages/client/src/schemas/menu/index.md index 0c47627cc..feccb8efe 100644 --- a/packages/client/src/schemas/menu/index.md +++ b/packages/client/src/schemas/menu/index.md @@ -13,7 +13,7 @@ group: 需要 antd v4.16+ 支持,在此之前的 Menu.Item 不支持 Fragment 包裹。 -## 组件树 +## Node Tree
 
@@ -43,7 +43,11 @@ group:
 
 
-## 代码演示 +## Designable Bar + +- Menu.DesignableBar + +## Examples ### 横向菜单 diff --git a/packages/client/src/schemas/password/index.md b/packages/client/src/schemas/password/index.md index e421627c9..879e780ed 100644 --- a/packages/client/src/schemas/password/index.md +++ b/packages/client/src/schemas/password/index.md @@ -11,14 +11,18 @@ group: # Password - 密码 -## 节点树 +## Node Tree
 // 单选框
 
 
-## 代码演示 +## Designable Bar + +- Password.DesignableBar + +## Examples ### 密码框 diff --git a/packages/client/src/schemas/radio/index.md b/packages/client/src/schemas/radio/index.md index 8bbeed00a..bc3704834 100644 --- a/packages/client/src/schemas/radio/index.md +++ b/packages/client/src/schemas/radio/index.md @@ -11,7 +11,7 @@ group: # Radio - 单选框 -## 节点树 +## Node Tree
 // 单选框
@@ -20,7 +20,11 @@ group:
 
 
-## 代码演示 +## Designable Bar + +- Radio.DesignableBar + +## Examples ### 单选框 diff --git a/packages/client/src/schemas/select/index.md b/packages/client/src/schemas/select/index.md index ebe788851..76a709ba2 100644 --- a/packages/client/src/schemas/select/index.md +++ b/packages/client/src/schemas/select/index.md @@ -11,7 +11,7 @@ group: # Select - 选择器 -## 节点树 +## Node Tree
 // 常规选择器
@@ -37,7 +37,14 @@ group:
 
 
-## Select +## Designable Bar + +- Select.DesignableBar +- Select.Drawer.DesignableBar +- Select.Options.DesignableBar +- Select.OptionTag.DesignableBar + +## Examples ### 单选 @@ -62,13 +69,11 @@ const schema = { type: 'object', properties: { input: { - interface: 'string', - type: 'string', + type: 'number', title: `编辑模式`, - name: 'name1', enum: options, 'x-decorator': 'FormItem', - 'x-component': 'Select', + 'x-component': 'Select.Object', 'x-reactions': { target: 'read', fulfill: { @@ -79,14 +84,12 @@ const schema = { }, }, read: { - interface: 'string', - type: 'string', + type: 'number', title: `阅读模式`, enum: options, - name: 'name2', - 'x-read-pretty': true, 'x-decorator': 'FormItem', - 'x-component': 'Select', + 'x-component': 'Select.Object', + 'x-read-pretty': true, }, } }; @@ -257,8 +260,7 @@ const schema = { type: 'object', properties: { input: { - interface: 'select', - type: 'string', + type: 'object', title: `编辑模式`, enum: dataSource, 'x-decorator': 'FormItem', @@ -281,8 +283,7 @@ const schema = { }, }, read: { - interface: 'select', - type: 'string', + type: 'object', title: `阅读模式`, enum: dataSource, 'x-read-pretty': true, @@ -332,8 +333,7 @@ const schema = { type: 'object', properties: { input: { - interface: 'select', - type: 'string', + type: 'array', title: `编辑模式`, enum: dataSource, 'x-decorator': 'FormItem', @@ -356,8 +356,7 @@ const schema = { }, }, read: { - interface: 'select', - type: 'string', + type: 'array', title: `阅读模式`, enum: dataSource, 'x-read-pretty': true, @@ -571,22 +570,44 @@ export default () => { }; ``` - +type 支持 string、number、object 和 array,array 元素可以是 string、number 或 object。如: + +```ts +{ + properties: { + select: { + type: 'string', // 也可以是 number、object、array + 'x-component': 'Select', + } + } +} +``` + +可以配置 dataSource(enum)的 fieldNames,如: + +```ts +{ + properties: { + select: { + type: 'string', // 也可以是 number、object、array + 'x-component': 'Select', + 'x-component-props': { + fieldNames: { + label: 'label', // 标签文案 + value: 'value', + color: 'color', // 标签颜色 + children: 'children', // 选项分组时,选项字段对应的 key + }, + }, + }, + } +} +``` + +### Select.Drawer + +type 支持 object 和 array,Select.Drawer 的可选项是以抽屉方式展开,提供了 Select.Options 和 Select.OptionTag 用于配置可选项界面和选中项详情界面。 diff --git a/packages/client/src/schemas/select/index.tsx b/packages/client/src/schemas/select/index.tsx index 374204c39..fe352d9a6 100644 --- a/packages/client/src/schemas/select/index.tsx +++ b/packages/client/src/schemas/select/index.tsx @@ -18,6 +18,8 @@ import { useDesignable } from '../DesignableSchemaField'; import { createContext } from 'react'; import { useContext } from 'react'; import { SelectedRowKeysContext, useTableContext } from '../table'; +import { isEmpty } from 'lodash'; +import { isField } from '@formily/core'; export const Select: any = connect( (props) => { @@ -189,10 +191,13 @@ Select.Object = connect( ), mapReadPretty( observer((props: any) => { - const { value, fieldNames = { label: 'label' }, ...others } = props; + const { value, fieldNames = { label: 'label', color: 'color' }, ...others } = props; if (!value) { return null; } + if (isEmpty(value)) { + return null; + } const values = toArr(value); return (
diff --git a/packages/client/src/schemas/table/index.md b/packages/client/src/schemas/table/index.md index c93aee5a3..5a6be619b 100644 --- a/packages/client/src/schemas/table/index.md +++ b/packages/client/src/schemas/table/index.md @@ -11,7 +11,7 @@ group: # Table - 表格 -## 组件节点树 +## Node Tree
 
@@ -53,6 +53,11 @@ group:
-## 代码演示 +## Designable Bar + +- Table.DesignableBar +- Table.Column.DesignableBar + +## Examples diff --git a/packages/client/src/schemas/tabs/index.md b/packages/client/src/schemas/tabs/index.md index 634bc8387..92dbfc4c2 100644 --- a/packages/client/src/schemas/tabs/index.md +++ b/packages/client/src/schemas/tabs/index.md @@ -11,7 +11,7 @@ group: # Tabs - 标签页 -## 组件节点树 +## Node
 
@@ -24,7 +24,11 @@ group:
 
 
-## 代码演示 +## Designable Bar + +- Tabs.DesignableBar + +## Examples ### 基本使用 diff --git a/packages/client/src/schemas/time-picker/index.md b/packages/client/src/schemas/time-picker/index.md index f1afef98c..1ce1439a1 100644 --- a/packages/client/src/schemas/time-picker/index.md +++ b/packages/client/src/schemas/time-picker/index.md @@ -11,13 +11,17 @@ group: # TimePicker - 时间选择器 -## 节点树 +## Node Tree
 
 
-## 代码演示 +## Designable Bar + +- TimePicker.DesignableBar + +## Examples ### 日期选择器 diff --git a/packages/client/src/schemas/upload/index.md b/packages/client/src/schemas/upload/index.md index 7b62a9c5b..697b5dc6c 100644 --- a/packages/client/src/schemas/upload/index.md +++ b/packages/client/src/schemas/upload/index.md @@ -11,13 +11,17 @@ group: # Upload - 上传 -## 节点树 +## Node Tree
 
 
-## 代码演示 +## Designable Bar + +- Upload.DesignableBar + +## Examples ### 上传 diff --git a/packages/client/src/templates/admin-layout/index.md b/packages/client/src/templates/admin-layout/index.md deleted file mode 100644 index 276c9f236..000000000 --- a/packages/client/src/templates/admin-layout/index.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: AdminLayout - 后台布局 -nav: - title: 组件 - path: /client -group: - order: 2 - title: Templates - path: /client/templates ---- - -# AdminLayout - 后台布局 - -内置的后台布局模板,提供了基础的菜单和路由切换。 diff --git a/packages/client/src/templates/admin-layout/index.tsx b/packages/client/src/templates/admin-layout/index.tsx deleted file mode 100644 index a3602ed02..000000000 --- a/packages/client/src/templates/admin-layout/index.tsx +++ /dev/null @@ -1,229 +0,0 @@ -import React, { useContext, useEffect, useRef, useState } from 'react'; -import { - Button, - Spin, - Layout, - PageHeader, - Modal, - Menu, - Collapse, - Dropdown, -} from 'antd'; -import isEmpty from 'lodash/isEmpty'; -import { - Link, - useLocation, - useRouteMatch, - useHistory, - Redirect, -} from 'react-router-dom'; -import { - useGlobalAction, - refreshGlobalAction, - RouteComponentContext, -} from '../../'; -import { SchemaRenderer } from '../../schemas'; -import { useRequest } from 'ahooks'; -import { - DatabaseOutlined, - PlusOutlined, - DownOutlined, -} from '@ant-design/icons'; -import { Tabs } from 'antd'; -import '@formily/antd/esm/array-collapse/style'; -import './style.less'; -import { MenuContainerContext } from '../../schemas/menu'; - -function LogoutButton() { - const history = useHistory(); - return ( - - ); -} - -function Database() { - const [visible, setVisible] = useState(false); - - const schema = { - type: 'object', - properties: { - layout: { - type: 'void', - 'x-component': 'FormLayout', - 'x-component-props': { - layout: 'vertical', - }, - properties: { - input: { - type: 'string', - title: '数据表名称', - required: true, - 'x-decorator': 'FormItem', - 'x-component': 'Input', - }, - array: { - type: 'array', - title: '数据表字段', - 'x-component': 'ArrayCollapse', - 'x-component-props': { - accordion: true, - }, - // maxItems: 3, - 'x-decorator': 'FormItem', - items: { - type: 'object', - 'x-component': 'ArrayCollapse.CollapsePanel', - 'x-component-props': { - header: '字段', - }, - properties: { - index: { - type: 'void', - 'x-component': 'ArrayCollapse.Index', - }, - input: { - type: 'string', - 'x-decorator': 'FormItem', - title: 'Input', - required: true, - 'x-component': 'Input', - }, - remove: { - type: 'void', - 'x-component': 'ArrayCollapse.Remove', - }, - moveUp: { - type: 'void', - 'x-component': 'ArrayCollapse.MoveUp', - }, - moveDown: { - type: 'void', - 'x-component': 'ArrayCollapse.MoveDown', - }, - }, - }, - properties: { - addition: { - type: 'void', - title: '添加字段', - 'x-component': 'ArrayCollapse.Addition', - }, - }, - }, - }, - }, - }, - }; - - return ( - <> - - 数据表1 - 数据表2 - 数据表3 - 数据表4 - - 新增数据表 - - } - > - - 数据表1 - - - } - // width={'800px'} - visible={visible} - onCancel={() => setVisible(false)} - onOk={() => setVisible(false)} - // bodyStyle={{ padding: 0 }} - // footer={null} - > - - - setVisible(true)} - style={{ color: '#fff', lineHeight: '48px', width: 48 }} - /> - - ); -} - -function LayoutWithMenu({ schema }) { - const match = useRouteMatch(); - const location = useLocation(); - const sideMenuRef = useRef(); - const [activeKey, setActiveKey] = useState(match.params.name); - const onSelect = (info) => { - console.log('LayoutWithMenu', schema); - setActiveKey(info.key); - }; - console.log({ match }); - return ( - - - - - - - - {location.pathname} - - - - - ); -} - -function Content({ activeKey }) { - const { data = {}, loading } = useRequest( - `/api/ui-schemas:getTree/${activeKey}?filter[parentId]=${activeKey}`, - { - refreshDeps: [activeKey], - formatResult: (result) => result?.data, - }, - ); - - if (loading) { - return ; - } - - return ; -} - -export function AdminLayout({ route, children }: any) { - - const { data = {}, loading } = useRequest( - `/api/ui-schemas:getTree/${route.schemaName}`, - { - refreshDeps: [route], - formatResult: (result) => result?.data, - }, - ); - - if (loading) { - return ; - } - - return ; -} - -export default AdminLayout; diff --git a/packages/client/src/templates/admin-layout/style.less b/packages/client/src/templates/admin-layout/style.less deleted file mode 100644 index 013400883..000000000 --- a/packages/client/src/templates/admin-layout/style.less +++ /dev/null @@ -1,49 +0,0 @@ -// .fields-collapse { -// border: 1px solid #f0f0f0; -// border-bottom: 0; -// > .ant-collapse-item { -// border-bottom: 1px solid #f0f0f0; -// } -// .ant-collapse-content { -// &.ant-collapse-content-active { -// border-top: 1px solid #f0f0f0; -// } -// } -// > .ant-collapse-item > .ant-collapse-content { -// background: #fff; -// } -// > .ant-collapse-item > .ant-collapse-content > .ant-collapse-content-box { -// padding: 16px; -// padding-bottom: 1px; -// } -// } - -.ant-collapse { - border: 1px solid #d9d9d9 !important; - border-bottom: 0 !important; - > .ant-collapse-item { - border-bottom: 1px solid #d9d9d9 !important; - } - .ant-collapse-content { - border-top: 1px solid #d9d9d9 !important; - } - .ant-collapse-content > .ant-collapse-content-box { - padding: 24px !important; - padding-bottom: 0 !important; - } -} - -.database-sider { - background: #fafafa; - padding-top: 16px; - .ant-menu { - background: #fafafa; - border-right: 0; - } - .ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected { - background: #fff; - &::after { - display: none; - } - } -} diff --git a/packages/client/src/templates/auth-layout/index.md b/packages/client/src/templates/auth-layout/index.md deleted file mode 100644 index 7cc91617f..000000000 --- a/packages/client/src/templates/auth-layout/index.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: AuthLayout - 登录布局 -nav: - title: 组件 - path: /client -group: - order: 2 - title: Templates - path: /client/templates ---- - -# AuthLayout - 登录布局 - -内置的登录、注册页布局 \ No newline at end of file diff --git a/packages/client/src/templates/auth-layout/index.tsx b/packages/client/src/templates/auth-layout/index.tsx deleted file mode 100644 index 578364a91..000000000 --- a/packages/client/src/templates/auth-layout/index.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react'; -import { useLocation, useHistory } from 'react-router-dom'; - -export function AuthLayout({ children, route }: any) { - const location = useLocation(); - const history = useHistory(); - return ( -
-

NocoBase

- {children} -
- ); -} - -export default AuthLayout; diff --git a/packages/client/src/templates/default-page/index.md b/packages/client/src/templates/default-page/index.md deleted file mode 100644 index 36b33510f..000000000 --- a/packages/client/src/templates/default-page/index.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: PageTemplate - 页面模板 -nav: - title: 组件 - path: /client -group: - order: 2 - title: Templates - path: /client/templates ---- - -# PageTemplate - 页面模板 - -常规的页面模板,支持区块配置。 diff --git a/packages/client/src/templates/default-page/index.tsx b/packages/client/src/templates/default-page/index.tsx deleted file mode 100644 index a03faf6f7..000000000 --- a/packages/client/src/templates/default-page/index.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React, { useContext, useEffect, useState } from 'react'; -import { Spin } from 'antd'; -import { Helmet } from 'react-helmet'; -import { useRequest } from 'ahooks'; -import { SchemaRenderer } from '../../schemas'; - -export function DefaultPage({ route }) { - const { data = {}, loading } = useRequest( - `/api/ui-schemas:getTree/${route.schemaName}`, - { - refreshDeps: [route], - formatResult: (result) => result?.data, - }, - ); - if (loading) { - return ; - } - return ( -
- -
- ); -} - -export default DefaultPage; diff --git a/packages/client/src/templates/index.tsx b/packages/client/src/templates/index.tsx deleted file mode 100644 index 854db676d..000000000 --- a/packages/client/src/templates/index.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export * from './auth-layout'; -export * from './admin-layout'; -export * from './default-page'; \ No newline at end of file