From fef3600dd80751fb113d066f26401345a3c15966 Mon Sep 17 00:00:00 2001 From: janrywang Date: Wed, 4 Aug 2021 12:21:27 +0800 Subject: [PATCH] docs(designable): add designable form docs --- .umirc.js | 8 + .../src/components/DesignableField/index.tsx | 6 +- .../src/components/DesignableField/types.ts | 2 +- .../src/components/DesignableForm/index.tsx | 6 +- docs/guide/form-builder.md | 236 ++++++++++++++++++ docs/guide/form-builder.zh-CN.md | 236 ++++++++++++++++++ 6 files changed, 488 insertions(+), 6 deletions(-) create mode 100644 docs/guide/form-builder.md create mode 100644 docs/guide/form-builder.zh-CN.md diff --git a/.umirc.js b/.umirc.js index 692230f089d..744363d4ad9 100644 --- a/.umirc.js +++ b/.umirc.js @@ -235,6 +235,10 @@ export default { title: 'Contribution Guide', path: '/guide/contribution', }, + { + title: 'Form Builder Guide', + path: '/guide/form-builder', + }, { title: 'Issue Helper', path: '/guide/issue-helper', @@ -340,6 +344,10 @@ export default { title: '贡献指南', path: '/zh-CN/guide/contribution', }, + { + title: '表单设计器开发指南', + path: '/zh-CN/guide/form-builder', + }, { title: '问题反馈', path: '/zh-CN/guide/issue-helper', diff --git a/designable/antd/src/components/DesignableField/index.tsx b/designable/antd/src/components/DesignableField/index.tsx index 66f30366921..9bfd31e241c 100644 --- a/designable/antd/src/components/DesignableField/index.tsx +++ b/designable/antd/src/components/DesignableField/index.tsx @@ -21,13 +21,15 @@ import { clone } from '@formily/shared' import { FormItemSwitcher } from '../FormItemSwitcher' import { DesignableObject } from '../DesignableObject' import { createOptions } from './options' -import { IDesignableFieldProps } from './types' +import { IDesignableFieldFactoryProps } from './types' import { includesComponent } from '../../shared' import * as defaultSchemas from '../../schemas' Schema.silent() -export const createDesignableField = (options: IDesignableFieldProps) => { +export const createDesignableField = ( + options: IDesignableFieldFactoryProps +) => { const realOptions = createOptions(options) const tabs = {} diff --git a/designable/antd/src/components/DesignableField/types.ts b/designable/antd/src/components/DesignableField/types.ts index b591d6a52d1..1b733631b47 100644 --- a/designable/antd/src/components/DesignableField/types.ts +++ b/designable/antd/src/components/DesignableField/types.ts @@ -1,6 +1,6 @@ import { ISchema } from '@formily/react' import { ComponentNameMatcher } from '../../shared' -export interface IDesignableFieldProps { +export interface IDesignableFieldFactoryProps { registryName: string components?: Record> componentsPropsSchema?: Record diff --git a/designable/antd/src/components/DesignableForm/index.tsx b/designable/antd/src/components/DesignableForm/index.tsx index 4dc3f31cbb4..9c9fb13d7d4 100644 --- a/designable/antd/src/components/DesignableForm/index.tsx +++ b/designable/antd/src/components/DesignableForm/index.tsx @@ -7,13 +7,13 @@ import { usePrefix } from '@designable/react' import { Form as FormPropsSchema } from '../../schemas' import './styles.less' -export interface IDesignableFormProps extends IDesignerProps { +export interface IDesignableFormFactoryProps extends IDesignerProps { registryName: string component?: React.JSXElementConstructor } -export const createDesignableForm = (options: IDesignableFormProps) => { - const realOptions: IDesignableFormProps = { +export const createDesignableForm = (options: IDesignableFormFactoryProps) => { + const realOptions: IDesignableFormFactoryProps = { component: Form, droppable: true, draggable: false, diff --git a/docs/guide/form-builder.md b/docs/guide/form-builder.md new file mode 100644 index 00000000000..c8faf6695f0 --- /dev/null +++ b/docs/guide/form-builder.md @@ -0,0 +1,236 @@ +# Form designer development guide + +## Introduction + +![](http://img.alicdn.com/imgextra/i2/O1CN01eI9FLz22tZek2jv7E_!!6000000007178-2-tps-3683-2272.png) + +Formily Form Designer is an extension package based on [designable](https://github.com/alibaba/designable). It inherits the basic capabilities of designable, and provides Formily basic form building and configuration capabilities. + +## Core Concept + +The core concept of Designable is to turn the designer into a modular combination, everything can be replaced. Designable itself provides a series of out-of-the-box components for users to use, but if users are not satisfied with the components, they can directly replace the components. To achieve maximum flexible customization, that is, Designable itself does not provide any plug-in related APIs + +## Install + +> Status: Unpublished + +Ant Design users + +```bash +npm install --save @formily/designable-antd +``` + +Alibaba Fusion users + +```bash +npm install --save @formily/designable-next +``` + +## Get started quickly + +[Source Code](https://github.com/alibaba/formily/tree/formily_next/designable/antd/playground/widgets) + +In the following example, we will help you understand the usage of each component line by line through code comments. + +```tsx pure +import React, { useMemo } from 'react' +import ReactDOM from 'react-dom' +import { + Designer, //Designer root component, used to deliver context + IconWidget, //Icon widget, used to obtain various system built-in icons + DesignerToolsWidget, //Drawing board tool pendant + ViewToolsWidget, //View switching tool pendant + Workspace, //Workspace components, core components, used to manage drag and drop behavior in the workspace, tree node data, etc... + OutlineTreeWidget, //Outline tree component, it will automatically identify the current workspace and display the tree nodes in the workspace + DragSourceWidget, //Drag and drop the source component + MainPanel, //Main layout panel + CompositePanel, //Left combined layout panel + WorkspacePanel, //Workspace layout panel + ToolbarPanel, //Toolbar layout panel + ViewportPanel, //Viewport layout panel + ViewPanel, //View layout panel + SettingsPanel, //Configure the form layout panel on the right + ComponentTreeWidget, //Component tree renderer +} from '@designable/react' +import { SettingsForm } from '@designable/react-settings-form' +import { createDesigner, GlobalRegistry } from '@designable/core' +import { + createDesignableField, + createDesignableForm, +} from '@formily/designable-antd' +import { + transformToSchema, //Convert the component tree structure into Formily JSON Schema + transformToTreeNode, //Convert Formily JSON Schema into a component tree +} from '@designable/formily' +import { + LogoWidget, //Business custom Logo rendering component + PreviewWidget, //Business custom preview component + SchemaEditorWidget, //Business custom Schema editor + MarkupSchemaWidget, //Business custom source code previewer +} from './widgets' +import { Button } from 'antd' +import 'antd/dist/antd.less' + +GlobalRegistry.registerDesignerLocales({ + 'zh-CN': { + sources: { + Inputs: 'Input controls', + Layouts: 'Layout components', + Arrays: 'Self-incrementing components', + }, + }, + 'en-US': { + sources: { + Inputs: 'Inputs', + Layouts: 'Layouts', + Arrays: 'Arrays', + }, + }, +}) + +const Root = createDesignableForm({ + registryName: 'Root', +}) + +const DesignableField = createDesignableField({ + registryName: 'DesignableField', +}) + +const App = () => { + const engine = useMemo(() => createDesigner(), []) + + useEffect(() => { + //The business layer gets the schema to echo the data + fetchSchema().then((schema) => { + engine.setCurrentTree(transformToTreeNode(schema)) + }) + }, []) + + return ( + + } + actions={ + + } + > + + } + > + + + + + } + > + + + + + + + + + + + + {() => ( + + )} + + + {(tree, onChange) => ( + + )} + + + {(tree) => } + + + {(tree) => } + + + + + + + + + + ) +} + +ReactDOM.render(, document.getElementById('root')) +``` + +## API + +> The Designable API document is currently unavailable, Yes, stay tuned~ + +### createDesignableField + +#### Description + +Create DesignableField and consume it for ComponentTreeWidget to build + +#### Signature + +```ts +interface IDesignableFieldFactoryProps { + registryName: string //Required, registered name, componentName that identifies DesignableField in the component tree + components?: Record> //Custom canvas components, used to pass in x-component/x-decorator + componentsPropsSchema?: Record //Custom canvas component property schema configuration + dropFormItemComponents?: ComponentNameMatcher[] //Identify which components do not need to support FormItem + dropReactionComponents?: ComponentNameMatcher[] //Identify which components do not need to support responder configuration + selfRenderChildrenComponents?: ComponentNameMatcher[] //Identify which canvas components are rendered by the component itself, and currently internal components such as ArrayTable/FormTab are identified by default + inlineChildrenLayoutComponents?: ComponentNameMatcher[] //Identify which canvas component's child component layout mode is inline mode + inlineLayoutComponents?: ComponentNameMatcher[] //Identify which canvas components are in inline mode + restrictChildrenComponents?: Record //Node constraints, identify the upper and lower constraints between canvas components, for example, the child nodes of A component can only be B/C components +} + +interface createDesignableField { + (props: IDesignableFieldFactoryProps): React.FC +} +``` + +### createDesignableForm + +#### Description + +Create DesignableForm and consume it for ComponentTreeWidget + +It should be noted here that if it is a pure form designer, we need to specify the registryName as Root, so that the Form component cannot be dragged. If it is specified as DesignableForm or other names, it can be dragged. This scenario is suitable for Page-level construction, you can embed the entire form into other modules + +#### Signature + +```ts +import { IDesignerProps } from '@designable/core' + +interface IDesignableFormFactoryProps extends IDesignerProps { + registryName: string //Required, registered name, componentName that identifies DesignableForm in the component tree + component?: React.JSXElementConstructor //The canvas component of the Form, no need to specify by default +} + +interface createDesignableForm { + (props: IDesignableFormFactoryProps): React.FC +} +``` diff --git a/docs/guide/form-builder.zh-CN.md b/docs/guide/form-builder.zh-CN.md new file mode 100644 index 00000000000..a775364ef62 --- /dev/null +++ b/docs/guide/form-builder.zh-CN.md @@ -0,0 +1,236 @@ +# 表单设计器开发指南 + +## 介绍 + +![](http://img.alicdn.com/imgextra/i2/O1CN01eI9FLz22tZek2jv7E_!!6000000007178-2-tps-3683-2272.png) + +Formily 表单设计器是基于[designable](https://github.com/alibaba/designable)而扩展出来的扩展包,它在继承了 designable 的基础能力上,提供了 Formily 基础表单的搭建和配置能力。 + +## 核心理念 + +Designable 的核心理念是将设计器搭建变成模块化组合,一切可替换,Designable 本身提供了一系列开箱即用的组件给用户使用,但是如果用户对组件不满意,是可以直接替换组件,从而实现最大化灵活定制,也就是 Designable 本身是不会提供任何插槽 Plugin 相关的 API + +## 安装 + +> 状态:未发布 + +Ant Design 用户 + +```bash +npm install --save @formily/designable-antd +``` + +Alibaba Fusion 用户 + +```bash +npm install --save @formily/designable-next +``` + +## 快速上手 + +[源代码](https://github.com/alibaba/formily/tree/formily_next/designable/antd/playground/widgets) + +以下示例,我们将通过代码注释的方式帮助大家一行一行理解每个组件的使用方式 + +```tsx pure +import React, { useMemo } from 'react' +import ReactDOM from 'react-dom' +import { + Designer, //设计器根组件,用于下发上下文 + IconWidget, //图标挂件,用于获取各种系统内置图标 + DesignerToolsWidget, //画板工具挂件 + ViewToolsWidget, //视图切换工具挂件 + Workspace, //工作区组件,核心组件,用于管理工作区内的拖拽行为,树节点数据等等... + OutlineTreeWidget, //大纲树组件,它会自动识别当前工作区,展示出工作区内树节点 + DragSourceWidget, //拖拽源组件 + MainPanel, //主布局面板 + CompositePanel, //左侧组合布局面板 + WorkspacePanel, //工作区布局面板 + ToolbarPanel, //工具栏布局面板 + ViewportPanel, //视口布局面板 + ViewPanel, //视图布局面板 + SettingsPanel, //右侧配置表单布局面板 + ComponentTreeWidget, //组件树渲染器 +} from '@designable/react' +import { SettingsForm } from '@designable/react-settings-form' +import { createDesigner, GlobalRegistry } from '@designable/core' +import { + createDesignableField, + createDesignableForm, +} from '@formily/designable-antd' +import { + transformToSchema, //将组件树结构转换成Formily JSON Schema + transformToTreeNode, //将Formily JSON Schema转换成组件树 +} from '@designable/formily' +import { + LogoWidget, //业务自定义Logo渲染组件 + PreviewWidget, //业务自定义预览组件 + SchemaEditorWidget, //业务自定义Schema编辑器 + MarkupSchemaWidget, //业务自定义源码预览器器 +} from './widgets' +import { Button } from 'antd' +import 'antd/dist/antd.less' + +GlobalRegistry.registerDesignerLocales({ + 'zh-CN': { + sources: { + Inputs: '输入控件', + Layouts: '布局组件', + Arrays: '自增组件', + }, + }, + 'en-US': { + sources: { + Inputs: 'Inputs', + Layouts: 'Layouts', + Arrays: 'Arrays', + }, + }, +}) + +const Root = createDesignableForm({ + registryName: 'Root', +}) + +const DesignableField = createDesignableField({ + registryName: 'DesignableField', +}) + +const App = () => { + const engine = useMemo(() => createDesigner(), []) + + useEffect(() => { + //业务层拿到schema用于回显数据 + fetchSchema().then((schema) => { + engine.setCurrentTree(transformToTreeNode(schema)) + }) + }, []) + + return ( + + } + actions={ + + } + > + + } + > + + + + + } + > + + + + + + + + + + + + {() => ( + + )} + + + {(tree, onChange) => ( + + )} + + + {(tree) => } + + + {(tree) => } + + + + + + + + + + ) +} + +ReactDOM.render(, document.getElementById('root')) +``` + +## API + +> Designable API 文档目前暂时没有,敬请期待~ + +### createDesignableField + +#### 描述 + +创建 DesignableField,给 ComponentTreeWidget 消费,用于搭建 + +#### 签名 + +```ts +interface IDesignableFieldFactoryProps { + registryName: string //必填项,注册名称,标识DesignableField在组件树中的componentName + components?: Record> //自定义画布组件,用于传入x-component/x-decorator + componentsPropsSchema?: Record //自定义画布组件属性schema配置 + dropFormItemComponents?: ComponentNameMatcher[] //标识哪些组件不需要支持FormItem + dropReactionComponents?: ComponentNameMatcher[] //标识哪些组件不需要支持响应器配置 + selfRenderChildrenComponents?: ComponentNameMatcher[] //标识哪些画布组件是由组件自身渲染子树,目前内部ArrayTable/FormTab这类组件是默认标识了 + inlineChildrenLayoutComponents?: ComponentNameMatcher[] //标识哪些画布组件的子组件布局模式是内联模式 + inlineLayoutComponents?: ComponentNameMatcher[] //标识哪些画布组件本身是内联模式 + restrictChildrenComponents?: Record //节点约束,标识画布组件之间的上下级约束关系,比如A组件的子节点只能是B/C组件 +} + +interface createDesignableField { + (props: IDesignableFieldFactoryProps): React.FC +} +``` + +### createDesignableForm + +#### 描述 + +创建 DesignableForm,给 ComponentTreeWidget 消费 + +这里需要注意的是,如果是作为纯表单设计器,我们需要指定 registryName 为 Root,这样 Form 组件是无法拖拽的,如果指定为 DesignableForm 或者其它名称,那就是可以拖拽的,这种场景适用于页面级搭建,可以将整个表单嵌入到其他模块中 + +#### 签名 + +```ts +import { IDesignerProps } from '@designable/core' + +interface IDesignableFormFactoryProps extends IDesignerProps { + registryName: string //必填项,注册名称,标识DesignableForm在组件树中的componentName + component?: React.JSXElementConstructor //Form的画布组件,默认不需要指定 +} + +interface createDesignableForm { + (props: IDesignableFormFactoryProps): React.FC +} +```