#
tokens: 47245/50000 13/1152 files (page 18/52)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 18 of 52. Use http://codebase.md/alibaba/formily?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .all-contributorsrc
├── .codecov.yml
├── .editorconfig
├── .eslintignore
├── .eslintrc
├── .github
│   ├── CONTRIBUTING.md
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE
│   │   └── config.yml
│   ├── PULL_REQUEST_TEMPLATE.md
│   └── workflows
│       ├── check-pr-title.yml
│       ├── ci.yml
│       ├── commitlint.yml
│       ├── issue-open-check.yml
│       ├── package-size.yml
│       └── pr-welcome.yml
├── .gitignore
├── .prettierrc.js
├── .umirc.js
├── .vscode
│   └── cspell.json
├── .yarnrc
├── CHANGELOG.md
├── commitlint.config.js
├── devtools
│   ├── .eslintrc
│   └── chrome-extension
│       ├── .npmignore
│       ├── assets
│       │   └── img
│       │       ├── loading.svg
│       │       └── logo
│       │           ├── 128x128.png
│       │           ├── 16x16.png
│       │           ├── 38x38.png
│       │           ├── 48x48.png
│       │           ├── error.png
│       │           ├── gray.png
│       │           └── scalable.png
│       ├── config
│       │   ├── webpack.base.ts
│       │   ├── webpack.dev.ts
│       │   └── webpack.prod.ts
│       ├── LICENSE.md
│       ├── package.json
│       ├── src
│       │   ├── app
│       │   │   ├── components
│       │   │   │   ├── FieldTree.tsx
│       │   │   │   ├── filter.ts
│       │   │   │   ├── LeftPanel.tsx
│       │   │   │   ├── RightPanel.tsx
│       │   │   │   ├── SearchBox.tsx
│       │   │   │   └── Tabs.tsx
│       │   │   ├── demo.tsx
│       │   │   └── index.tsx
│       │   └── extension
│       │       ├── backend.ts
│       │       ├── background.ts
│       │       ├── content.ts
│       │       ├── devpanel.tsx
│       │       ├── devtools.tsx
│       │       ├── inject.ts
│       │       ├── manifest.json
│       │       ├── popup.tsx
│       │       └── views
│       │           ├── devpanel.ejs
│       │           ├── devtools.ejs
│       │           └── popup.ejs
│       ├── tsconfig.build.json
│       └── tsconfig.json
├── docs
│   ├── functions
│   │   ├── contributors.ts
│   │   └── npm-search.ts
│   ├── guide
│   │   ├── advanced
│   │   │   ├── async.md
│   │   │   ├── async.zh-CN.md
│   │   │   ├── build.md
│   │   │   ├── build.zh-CN.md
│   │   │   ├── business-logic.md
│   │   │   ├── business-logic.zh-CN.md
│   │   │   ├── calculator.md
│   │   │   ├── calculator.zh-CN.md
│   │   │   ├── controlled.md
│   │   │   ├── controlled.zh-CN.md
│   │   │   ├── custom.md
│   │   │   ├── custom.zh-CN.md
│   │   │   ├── destructor.md
│   │   │   ├── destructor.zh-CN.md
│   │   │   ├── input.less
│   │   │   ├── layout.md
│   │   │   ├── layout.zh-CN.md
│   │   │   ├── linkages.md
│   │   │   ├── linkages.zh-CN.md
│   │   │   ├── validate.md
│   │   │   └── validate.zh-CN.md
│   │   ├── contribution.md
│   │   ├── contribution.zh-CN.md
│   │   ├── form-builder.md
│   │   ├── form-builder.zh-CN.md
│   │   ├── index.md
│   │   ├── index.zh-CN.md
│   │   ├── issue-helper.md
│   │   ├── issue-helper.zh-CN.md
│   │   ├── learn-formily.md
│   │   ├── learn-formily.zh-CN.md
│   │   ├── quick-start.md
│   │   ├── quick-start.zh-CN.md
│   │   ├── scenes
│   │   │   ├── dialog-drawer.md
│   │   │   ├── dialog-drawer.zh-CN.md
│   │   │   ├── edit-detail.md
│   │   │   ├── edit-detail.zh-CN.md
│   │   │   ├── index.less
│   │   │   ├── login-register.md
│   │   │   ├── login-register.zh-CN.md
│   │   │   ├── more.md
│   │   │   ├── more.zh-CN.md
│   │   │   ├── query-list.md
│   │   │   ├── query-list.zh-CN.md
│   │   │   ├── step-form.md
│   │   │   ├── step-form.zh-CN.md
│   │   │   ├── tab-form.md
│   │   │   ├── tab-form.zh-CN.md
│   │   │   └── VerifyCode.tsx
│   │   ├── upgrade.md
│   │   └── upgrade.zh-CN.md
│   ├── index.md
│   ├── index.zh-CN.md
│   └── site
│       ├── Contributors.less
│       ├── Contributors.tsx
│       ├── QrCode.less
│       ├── QrCode.tsx
│       ├── Section.less
│       ├── Section.tsx
│       └── styles.less
├── global.config.ts
├── jest.config.js
├── lerna.json
├── LICENSE.md
├── package.json
├── packages
│   ├── .eslintrc
│   ├── antd
│   │   ├── __tests__
│   │   │   ├── moment.spec.ts
│   │   │   └── sideEffects.spec.ts
│   │   ├── .npmignore
│   │   ├── .umirc.js
│   │   ├── build-style.ts
│   │   ├── create-style.ts
│   │   ├── docs
│   │   │   ├── components
│   │   │   │   ├── ArrayCards.md
│   │   │   │   ├── ArrayCards.zh-CN.md
│   │   │   │   ├── ArrayCollapse.md
│   │   │   │   ├── ArrayCollapse.zh-CN.md
│   │   │   │   ├── ArrayItems.md
│   │   │   │   ├── ArrayItems.zh-CN.md
│   │   │   │   ├── ArrayTable.md
│   │   │   │   ├── ArrayTable.zh-CN.md
│   │   │   │   ├── ArrayTabs.md
│   │   │   │   ├── ArrayTabs.zh-CN.md
│   │   │   │   ├── Cascader.md
│   │   │   │   ├── Cascader.zh-CN.md
│   │   │   │   ├── Checkbox.md
│   │   │   │   ├── Checkbox.zh-CN.md
│   │   │   │   ├── DatePicker.md
│   │   │   │   ├── DatePicker.zh-CN.md
│   │   │   │   ├── Editable.md
│   │   │   │   ├── Editable.zh-CN.md
│   │   │   │   ├── Form.md
│   │   │   │   ├── Form.zh-CN.md
│   │   │   │   ├── FormButtonGroup.md
│   │   │   │   ├── FormButtonGroup.zh-CN.md
│   │   │   │   ├── FormCollapse.md
│   │   │   │   ├── FormCollapse.zh-CN.md
│   │   │   │   ├── FormDialog.md
│   │   │   │   ├── FormDialog.zh-CN.md
│   │   │   │   ├── FormDrawer.md
│   │   │   │   ├── FormDrawer.zh-CN.md
│   │   │   │   ├── FormGrid.md
│   │   │   │   ├── FormGrid.zh-CN.md
│   │   │   │   ├── FormItem.md
│   │   │   │   ├── FormItem.zh-CN.md
│   │   │   │   ├── FormLayout.md
│   │   │   │   ├── FormLayout.zh-CN.md
│   │   │   │   ├── FormStep.md
│   │   │   │   ├── FormStep.zh-CN.md
│   │   │   │   ├── FormTab.md
│   │   │   │   ├── FormTab.zh-CN.md
│   │   │   │   ├── index.md
│   │   │   │   ├── index.zh-CN.md
│   │   │   │   ├── Input.md
│   │   │   │   ├── Input.zh-CN.md
│   │   │   │   ├── NumberPicker.md
│   │   │   │   ├── NumberPicker.zh-CN.md
│   │   │   │   ├── Password.md
│   │   │   │   ├── Password.zh-CN.md
│   │   │   │   ├── PreviewText.md
│   │   │   │   ├── PreviewText.zh-CN.md
│   │   │   │   ├── Radio.md
│   │   │   │   ├── Radio.zh-CN.md
│   │   │   │   ├── Reset.md
│   │   │   │   ├── Reset.zh-CN.md
│   │   │   │   ├── Select.md
│   │   │   │   ├── Select.zh-CN.md
│   │   │   │   ├── SelectTable.md
│   │   │   │   ├── SelectTable.zh-CN.md
│   │   │   │   ├── Space.md
│   │   │   │   ├── Space.zh-CN.md
│   │   │   │   ├── Submit.md
│   │   │   │   ├── Submit.zh-CN.md
│   │   │   │   ├── Switch.md
│   │   │   │   ├── Switch.zh-CN.md
│   │   │   │   ├── TimePicker.md
│   │   │   │   ├── TimePicker.zh-CN.md
│   │   │   │   ├── Transfer.md
│   │   │   │   ├── Transfer.zh-CN.md
│   │   │   │   ├── TreeSelect.md
│   │   │   │   ├── TreeSelect.zh-CN.md
│   │   │   │   ├── Upload.md
│   │   │   │   └── Upload.zh-CN.md
│   │   │   ├── index.md
│   │   │   └── index.zh-CN.md
│   │   ├── LICENSE.md
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── rollup.config.js
│   │   ├── src
│   │   │   ├── __builtins__
│   │   │   │   ├── hooks
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── useClickAway.ts
│   │   │   │   │   └── usePrefixCls.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── loading.ts
│   │   │   │   ├── moment.ts
│   │   │   │   ├── pickDataProps.ts
│   │   │   │   ├── portal.tsx
│   │   │   │   ├── render.ts
│   │   │   │   └── sort.tsx
│   │   │   ├── array-base
│   │   │   │   ├── index.tsx
│   │   │   │   ├── style.less
│   │   │   │   └── style.ts
│   │   │   ├── array-cards
│   │   │   │   ├── index.tsx
│   │   │   │   ├── style.less
│   │   │   │   └── style.ts
│   │   │   ├── array-collapse
│   │   │   │   ├── index.tsx
│   │   │   │   ├── style.less
│   │   │   │   └── style.ts
│   │   │   ├── array-items
│   │   │   │   ├── index.tsx
│   │   │   │   ├── style.less
│   │   │   │   └── style.ts
│   │   │   ├── array-table
│   │   │   │   ├── index.tsx
│   │   │   │   ├── style.less
│   │   │   │   └── style.ts
│   │   │   ├── array-tabs
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── cascader
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── checkbox
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── date-picker
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── editable
│   │   │   │   ├── index.tsx
│   │   │   │   ├── style.less
│   │   │   │   └── style.ts
│   │   │   ├── form
│   │   │   │   ├── index.tsx
│   │   │   │   ├── style.less
│   │   │   │   └── style.ts
│   │   │   ├── form-button-group
│   │   │   │   ├── index.tsx
│   │   │   │   ├── style.less
│   │   │   │   └── style.ts
│   │   │   ├── form-collapse
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── form-dialog
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── form-drawer
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── form-grid
│   │   │   │   ├── index.tsx
│   │   │   │   ├── style.less
│   │   │   │   └── style.ts
│   │   │   ├── form-item
│   │   │   │   ├── animation.less
│   │   │   │   ├── grid.less
│   │   │   │   ├── index.tsx
│   │   │   │   ├── style.less
│   │   │   │   └── style.ts
│   │   │   ├── form-layout
│   │   │   │   ├── index.tsx
│   │   │   │   ├── style.less
│   │   │   │   ├── style.ts
│   │   │   │   └── useResponsiveFormLayout.ts
│   │   │   ├── form-step
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── form-tab
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── index.ts
│   │   │   ├── input
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── number-picker
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── password
│   │   │   │   ├── index.tsx
│   │   │   │   ├── PasswordStrength.tsx
│   │   │   │   └── style.ts
│   │   │   ├── preview-text
│   │   │   │   ├── index.tsx
│   │   │   │   ├── style.less
│   │   │   │   └── style.ts
│   │   │   ├── radio
│   │   │   │   ├── index.tsx
│   │   │   │   ├── style.less
│   │   │   │   └── style.ts
│   │   │   ├── reset
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── select
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── select-table
│   │   │   │   ├── index.tsx
│   │   │   │   ├── style.less
│   │   │   │   ├── style.ts
│   │   │   │   ├── useCheckSlackly.tsx
│   │   │   │   ├── useFilterOptions.tsx
│   │   │   │   ├── useFlatOptions.tsx
│   │   │   │   ├── useSize.tsx
│   │   │   │   ├── useTitleAddon.tsx
│   │   │   │   └── utils.ts
│   │   │   ├── space
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── style.less
│   │   │   ├── style.ts
│   │   │   ├── submit
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── switch
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── time-picker
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── transfer
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── tree-select
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   └── upload
│   │   │       ├── index.tsx
│   │   │       ├── placeholder.ts
│   │   │       └── style.ts
│   │   ├── tsconfig.build.json
│   │   └── tsconfig.json
│   ├── benchmark
│   │   ├── .npmignore
│   │   ├── .umirc.js
│   │   ├── LICENSE.md
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── src
│   │   │   └── index.tsx
│   │   ├── template.ejs
│   │   ├── tsconfig.build.json
│   │   ├── tsconfig.json
│   │   ├── webpack.base.ts
│   │   ├── webpack.dev.ts
│   │   └── webpack.prod.ts
│   ├── core
│   │   ├── .npmignore
│   │   ├── .umirc.js
│   │   ├── docs
│   │   │   ├── api
│   │   │   │   ├── entry
│   │   │   │   │   ├── ActionResponse.less
│   │   │   │   │   ├── ActionResponse.tsx
│   │   │   │   │   ├── createForm.md
│   │   │   │   │   ├── createForm.zh-CN.md
│   │   │   │   │   ├── FieldEffectHooks.md
│   │   │   │   │   ├── FieldEffectHooks.zh-CN.md
│   │   │   │   │   ├── FormChecker.md
│   │   │   │   │   ├── FormChecker.zh-CN.md
│   │   │   │   │   ├── FormEffectHooks.md
│   │   │   │   │   ├── FormEffectHooks.zh-CN.md
│   │   │   │   │   ├── FormHooksAPI.md
│   │   │   │   │   ├── FormHooksAPI.zh-CN.md
│   │   │   │   │   ├── FormPath.md
│   │   │   │   │   ├── FormPath.zh-CN.md
│   │   │   │   │   ├── FormValidatorRegistry.md
│   │   │   │   │   └── FormValidatorRegistry.zh-CN.md
│   │   │   │   └── models
│   │   │   │       ├── ArrayField.md
│   │   │   │       ├── ArrayField.zh-CN.md
│   │   │   │       ├── Field.md
│   │   │   │       ├── Field.zh-CN.md
│   │   │   │       ├── Form.md
│   │   │   │       ├── Form.zh-CN.md
│   │   │   │       ├── ObjectField.md
│   │   │   │       ├── ObjectField.zh-CN.md
│   │   │   │       ├── Query.md
│   │   │   │       ├── Query.zh-CN.md
│   │   │   │       ├── VoidField.md
│   │   │   │       └── VoidField.zh-CN.md
│   │   │   ├── guide
│   │   │   │   ├── architecture.md
│   │   │   │   ├── architecture.zh-CN.md
│   │   │   │   ├── field.md
│   │   │   │   ├── field.zh-CN.md
│   │   │   │   ├── form.md
│   │   │   │   ├── form.zh-CN.md
│   │   │   │   ├── index.md
│   │   │   │   ├── index.zh-CN.md
│   │   │   │   ├── mvvm.md
│   │   │   │   ├── mvvm.zh-CN.md
│   │   │   │   ├── values.md
│   │   │   │   └── values.zh-CN.md
│   │   │   ├── index.md
│   │   │   └── index.zh-CN.md
│   │   ├── LICENSE.md
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── rollup.config.js
│   │   ├── src
│   │   │   ├── __tests__
│   │   │   │   ├── array.spec.ts
│   │   │   │   ├── effects.spec.ts
│   │   │   │   ├── externals.spec.ts
│   │   │   │   ├── field.spec.ts
│   │   │   │   ├── form.spec.ts
│   │   │   │   ├── graph.spec.ts
│   │   │   │   ├── heart.spec.ts
│   │   │   │   ├── internals.spec.ts
│   │   │   │   ├── lifecycle.spec.ts
│   │   │   │   ├── object.spec.ts
│   │   │   │   ├── shared.ts
│   │   │   │   └── void.spec.ts
│   │   │   ├── effects
│   │   │   │   ├── index.ts
│   │   │   │   ├── onFieldEffects.ts
│   │   │   │   └── onFormEffects.ts
│   │   │   ├── global.d.ts
│   │   │   ├── index.ts
│   │   │   ├── models
│   │   │   │   ├── ArrayField.ts
│   │   │   │   ├── BaseField.ts
│   │   │   │   ├── Field.ts
│   │   │   │   ├── Form.ts
│   │   │   │   ├── Graph.ts
│   │   │   │   ├── Heart.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── LifeCycle.ts
│   │   │   │   ├── ObjectField.ts
│   │   │   │   ├── Query.ts
│   │   │   │   ├── types.ts
│   │   │   │   └── VoidField.ts
│   │   │   ├── shared
│   │   │   │   ├── checkers.ts
│   │   │   │   ├── constants.ts
│   │   │   │   ├── effective.ts
│   │   │   │   ├── externals.ts
│   │   │   │   └── internals.ts
│   │   │   └── types.ts
│   │   ├── tsconfig.build.json
│   │   └── tsconfig.json
│   ├── element
│   │   ├── .npmignore
│   │   ├── build-style.ts
│   │   ├── create-style.ts
│   │   ├── docs
│   │   │   ├── .vuepress
│   │   │   │   ├── components
│   │   │   │   │   ├── createCodeSandBox.js
│   │   │   │   │   ├── dumi-previewer.vue
│   │   │   │   │   └── highlight.js
│   │   │   │   ├── config.js
│   │   │   │   ├── enhanceApp.js
│   │   │   │   ├── styles
│   │   │   │   │   └── index.styl
│   │   │   │   └── util.js
│   │   │   ├── demos
│   │   │   │   ├── guide
│   │   │   │   │   ├── array-cards
│   │   │   │   │   │   ├── effects-json-schema.vue
│   │   │   │   │   │   ├── effects-markup-schema.vue
│   │   │   │   │   │   ├── json-schema.vue
│   │   │   │   │   │   └── markup-schema.vue
│   │   │   │   │   ├── array-collapse
│   │   │   │   │   │   ├── effects-json-schema.vue
│   │   │   │   │   │   ├── effects-markup-schema.vue
│   │   │   │   │   │   ├── json-schema.vue
│   │   │   │   │   │   └── markup-schema.vue
│   │   │   │   │   ├── array-items
│   │   │   │   │   │   ├── json-schema.vue
│   │   │   │   │   │   └── markup-schema.vue
│   │   │   │   │   ├── array-table
│   │   │   │   │   │   ├── effects-json-schema.vue
│   │   │   │   │   │   ├── effects-markup-schema.vue
│   │   │   │   │   │   ├── json-schema.vue
│   │   │   │   │   │   └── markup-schema.vue
│   │   │   │   │   ├── array-tabs
│   │   │   │   │   │   ├── json-schema.vue
│   │   │   │   │   │   └── markup-schema.vue
│   │   │   │   │   ├── cascader
│   │   │   │   │   │   ├── json-schema.vue
│   │   │   │   │   │   ├── markup-schema.vue
│   │   │   │   │   │   └── template.vue
│   │   │   │   │   ├── checkbox
│   │   │   │   │   │   ├── json-schema.vue
│   │   │   │   │   │   ├── markup-schema.vue
│   │   │   │   │   │   └── template.vue
│   │   │   │   │   ├── date-picker
│   │   │   │   │   │   ├── json-schema.vue
│   │   │   │   │   │   ├── markup-schema.vue
│   │   │   │   │   │   └── template.vue
│   │   │   │   │   ├── editable
│   │   │   │   │   │   ├── json-schema.vue
│   │   │   │   │   │   ├── markup-schema.vue
│   │   │   │   │   │   └── template.vue
│   │   │   │   │   ├── form-button-group.vue
│   │   │   │   │   ├── form-collapse
│   │   │   │   │   │   ├── json-schema.vue
│   │   │   │   │   │   └── markup-schema.vue
│   │   │   │   │   ├── form-dialog
│   │   │   │   │   │   ├── json-schema.vue
│   │   │   │   │   │   ├── markup-schema.vue
│   │   │   │   │   │   └── template.vue
│   │   │   │   │   ├── form-drawer
│   │   │   │   │   │   ├── json-schema.vue
│   │   │   │   │   │   ├── markup-schema.vue
│   │   │   │   │   │   └── template.vue
│   │   │   │   │   ├── form-grid
│   │   │   │   │   │   ├── form.vue
│   │   │   │   │   │   ├── json-schema.vue
│   │   │   │   │   │   ├── markup-schema.vue
│   │   │   │   │   │   └── native.vue
│   │   │   │   │   ├── form-item
│   │   │   │   │   │   ├── bordered-none.vue
│   │   │   │   │   │   ├── common.vue
│   │   │   │   │   │   ├── feedback.vue
│   │   │   │   │   │   ├── inset.vue
│   │   │   │   │   │   ├── json-schema.vue
│   │   │   │   │   │   ├── markup-schema.vue
│   │   │   │   │   │   ├── size.vue
│   │   │   │   │   │   └── template.vue
│   │   │   │   │   ├── form-layout
│   │   │   │   │   │   ├── json-schema.vue
│   │   │   │   │   │   ├── markup-schema.vue
│   │   │   │   │   │   └── template.vue
│   │   │   │   │   ├── form-step
│   │   │   │   │   │   ├── json-schema.vue
│   │   │   │   │   │   └── markup-schema.vue
│   │   │   │   │   ├── form-tab
│   │   │   │   │   │   ├── json-schema.vue
│   │   │   │   │   │   └── markup-schema.vue
│   │   │   │   │   ├── form.vue
│   │   │   │   │   ├── input
│   │   │   │   │   │   ├── json-schema.vue
│   │   │   │   │   │   ├── markup-schema.vue
│   │   │   │   │   │   └── template.vue
│   │   │   │   │   ├── input-number
│   │   │   │   │   │   ├── json-schema.vue
│   │   │   │   │   │   ├── markup-schema.vue
│   │   │   │   │   │   └── template.vue
│   │   │   │   │   ├── password
│   │   │   │   │   │   ├── json-schema.vue
│   │   │   │   │   │   ├── markup-schema.vue
│   │   │   │   │   │   └── template.vue
│   │   │   │   │   ├── preview-text
│   │   │   │   │   │   ├── base.vue
│   │   │   │   │   │   └── extend.vue
│   │   │   │   │   ├── radio
│   │   │   │   │   │   ├── json-schema.vue
│   │   │   │   │   │   ├── markup-schema.vue
│   │   │   │   │   │   └── template.vue
│   │   │   │   │   ├── reset
│   │   │   │   │   │   ├── base.vue
│   │   │   │   │   │   ├── force.vue
│   │   │   │   │   │   └── validate.vue
│   │   │   │   │   ├── select
│   │   │   │   │   │   ├── json-schema-async.vue
│   │   │   │   │   │   ├── json-schema-sync.vue
│   │   │   │   │   │   ├── markup-schema-async-search.vue
│   │   │   │   │   │   ├── markup-schema-async.vue
│   │   │   │   │   │   ├── markup-schema-sync.vue
│   │   │   │   │   │   ├── template-async.vue
│   │   │   │   │   │   └── template-sync.vue
│   │   │   │   │   ├── space
│   │   │   │   │   │   ├── json-schema.vue
│   │   │   │   │   │   ├── markup-schema.vue
│   │   │   │   │   │   └── template.vue
│   │   │   │   │   ├── submit
│   │   │   │   │   │   ├── base.vue
│   │   │   │   │   │   └── loading.vue
│   │   │   │   │   ├── switch
│   │   │   │   │   │   ├── json-schema.vue
│   │   │   │   │   │   ├── markup-schema.vue
│   │   │   │   │   │   └── template.vue
│   │   │   │   │   ├── time-picker
│   │   │   │   │   │   ├── json-schema.vue
│   │   │   │   │   │   ├── markup-schema.vue
│   │   │   │   │   │   └── template.vue
│   │   │   │   │   ├── transfer
│   │   │   │   │   │   ├── json-schema.vue
│   │   │   │   │   │   ├── markup-schema.vue
│   │   │   │   │   │   └── template.vue
│   │   │   │   │   └── upload
│   │   │   │   │       ├── json-schema.vue
│   │   │   │   │       ├── markup-schema.vue
│   │   │   │   │       └── template.vue
│   │   │   │   └── index.vue
│   │   │   ├── guide
│   │   │   │   ├── array-cards.md
│   │   │   │   ├── array-collapse.md
│   │   │   │   ├── array-items.md
│   │   │   │   ├── array-table.md
│   │   │   │   ├── array-tabs.md
│   │   │   │   ├── cascader.md
│   │   │   │   ├── checkbox.md
│   │   │   │   ├── date-picker.md
│   │   │   │   ├── editable.md
│   │   │   │   ├── form-button-group.md
│   │   │   │   ├── form-collapse.md
│   │   │   │   ├── form-dialog.md
│   │   │   │   ├── form-drawer.md
│   │   │   │   ├── form-grid.md
│   │   │   │   ├── form-item.md
│   │   │   │   ├── form-layout.md
│   │   │   │   ├── form-step.md
│   │   │   │   ├── form-tab.md
│   │   │   │   ├── form.md
│   │   │   │   ├── index.md
│   │   │   │   ├── input-number.md
│   │   │   │   ├── input.md
│   │   │   │   ├── password.md
│   │   │   │   ├── preview-text.md
│   │   │   │   ├── radio.md
│   │   │   │   ├── reset.md
│   │   │   │   ├── select.md
│   │   │   │   ├── space.md
│   │   │   │   ├── submit.md
│   │   │   │   ├── switch.md
│   │   │   │   ├── time-picker.md
│   │   │   │   ├── transfer.md
│   │   │   │   └── upload.md
│   │   │   └── README.md
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── rollup.config.js
│   │   ├── src
│   │   │   ├── __builtins__
│   │   │   │   ├── configs
│   │   │   │   │   └── index.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── shared
│   │   │   │   │   ├── create-context.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── loading.ts
│   │   │   │   │   ├── portal.ts
│   │   │   │   │   ├── resolve-component.ts
│   │   │   │   │   ├── transform-component.ts
│   │   │   │   │   ├── types.ts
│   │   │   │   │   └── utils.ts
│   │   │   │   └── styles
│   │   │   │       └── common.scss
│   │   │   ├── array-base
│   │   │   │   ├── index.ts
│   │   │   │   ├── style.scss
│   │   │   │   └── style.ts
│   │   │   ├── array-cards
│   │   │   │   ├── index.ts
│   │   │   │   ├── style.scss
│   │   │   │   └── style.ts
│   │   │   ├── array-collapse
│   │   │   │   ├── index.ts
│   │   │   │   ├── style.scss
│   │   │   │   └── style.ts
│   │   │   ├── array-items
│   │   │   │   ├── index.ts
│   │   │   │   ├── style.scss
│   │   │   │   └── style.ts
│   │   │   ├── array-table
│   │   │   │   ├── index.ts
│   │   │   │   ├── style.scss
│   │   │   │   └── style.ts
│   │   │   ├── array-tabs
│   │   │   │   ├── index.ts
│   │   │   │   ├── style.scss
│   │   │   │   └── style.ts
│   │   │   ├── cascader
│   │   │   │   ├── index.ts
│   │   │   │   └── style.ts
│   │   │   ├── checkbox
│   │   │   │   ├── index.ts
│   │   │   │   └── style.ts
│   │   │   ├── date-picker
│   │   │   │   ├── index.ts
│   │   │   │   └── style.ts
│   │   │   ├── editable
│   │   │   │   ├── index.ts
│   │   │   │   ├── style.scss
│   │   │   │   └── style.ts
│   │   │   ├── el-form
│   │   │   │   ├── index.ts
│   │   │   │   └── style.ts
│   │   │   ├── el-form-item
│   │   │   │   ├── index.ts
│   │   │   │   └── style.ts
│   │   │   ├── form
│   │   │   │   ├── index.ts
│   │   │   │   ├── style.scss
│   │   │   │   └── style.ts
│   │   │   ├── form-button-group
│   │   │   │   ├── index.ts
│   │   │   │   ├── style.scss
│   │   │   │   └── style.ts
│   │   │   ├── form-collapse
│   │   │   │   ├── index.ts
│   │   │   │   ├── style.scss
│   │   │   │   └── style.ts
│   │   │   ├── form-dialog
│   │   │   │   ├── index.ts
│   │   │   │   └── style.ts
│   │   │   ├── form-drawer
│   │   │   │   ├── index.ts
│   │   │   │   ├── style.scss
│   │   │   │   └── style.ts
│   │   │   ├── form-grid
│   │   │   │   ├── index.ts
│   │   │   │   ├── style.scss
│   │   │   │   └── style.ts
│   │   │   ├── form-item
│   │   │   │   ├── animation.scss
│   │   │   │   ├── grid.scss
│   │   │   │   ├── index.ts
│   │   │   │   ├── style.scss
│   │   │   │   ├── style.ts
│   │   │   │   └── var.scss
│   │   │   ├── form-layout
│   │   │   │   ├── index.ts
│   │   │   │   ├── style.scss
│   │   │   │   ├── style.ts
│   │   │   │   └── useResponsiveFormLayout.ts
│   │   │   ├── form-step
│   │   │   │   ├── index.ts
│   │   │   │   └── style.ts
│   │   │   ├── form-tab
│   │   │   │   ├── index.ts
│   │   │   │   ├── style.scss
│   │   │   │   └── style.ts
│   │   │   ├── index.ts
│   │   │   ├── input
│   │   │   │   ├── index.ts
│   │   │   │   └── style.ts
│   │   │   ├── input-number
│   │   │   │   ├── index.ts
│   │   │   │   └── style.ts
│   │   │   ├── password
│   │   │   │   ├── index.ts
│   │   │   │   └── style.ts
│   │   │   ├── preview-text
│   │   │   │   ├── index.ts
│   │   │   │   └── style.ts
│   │   │   ├── radio
│   │   │   │   ├── index.ts
│   │   │   │   └── style.ts
│   │   │   ├── reset
│   │   │   │   ├── index.ts
│   │   │   │   └── style.ts
│   │   │   ├── select
│   │   │   │   ├── index.ts
│   │   │   │   └── style.ts
│   │   │   ├── space
│   │   │   │   ├── index.ts
│   │   │   │   ├── style.scss
│   │   │   │   └── style.ts
│   │   │   ├── style.ts
│   │   │   ├── submit
│   │   │   │   ├── index.ts
│   │   │   │   └── style.ts
│   │   │   ├── switch
│   │   │   │   ├── index.ts
│   │   │   │   └── style.ts
│   │   │   ├── time-picker
│   │   │   │   ├── index.ts
│   │   │   │   └── style.ts
│   │   │   ├── transfer
│   │   │   │   ├── index.ts
│   │   │   │   └── style.ts
│   │   │   └── upload
│   │   │       ├── index.ts
│   │   │       └── style.ts
│   │   ├── transformer.ts
│   │   ├── tsconfig.build.json
│   │   └── tsconfig.json
│   ├── grid
│   │   ├── .npmignore
│   │   ├── LICENSE.md
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── rollup.config.js
│   │   ├── src
│   │   │   ├── index.ts
│   │   │   └── observer.ts
│   │   ├── tsconfig.build.json
│   │   └── tsconfig.json
│   ├── json-schema
│   │   ├── .npmignore
│   │   ├── LICENSE.md
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── rollup.config.js
│   │   ├── src
│   │   │   ├── __tests__
│   │   │   │   ├── __snapshots__
│   │   │   │   │   └── schema.spec.ts.snap
│   │   │   │   ├── compiler.spec.ts
│   │   │   │   ├── patches.spec.ts
│   │   │   │   ├── schema.spec.ts
│   │   │   │   ├── server-validate.spec.ts
│   │   │   │   ├── shared.spec.ts
│   │   │   │   ├── transformer.spec.ts
│   │   │   │   └── traverse.spec.ts
│   │   │   ├── compiler.ts
│   │   │   ├── global.d.ts
│   │   │   ├── index.ts
│   │   │   ├── patches.ts
│   │   │   ├── polyfills
│   │   │   │   ├── index.ts
│   │   │   │   └── SPECIFICATION_1_0.ts
│   │   │   ├── schema.ts
│   │   │   ├── shared.ts
│   │   │   ├── transformer.ts
│   │   │   └── types.ts
│   │   ├── tsconfig.build.json
│   │   └── tsconfig.json
│   ├── next
│   │   ├── __tests__
│   │   │   ├── moment.spec.ts
│   │   │   └── sideEffects.spec.ts
│   │   ├── .npmignore
│   │   ├── .umirc.js
│   │   ├── build-style.ts
│   │   ├── create-style.ts
│   │   ├── docs
│   │   │   ├── components
│   │   │   │   ├── ArrayCards.md
│   │   │   │   ├── ArrayCards.zh-CN.md
│   │   │   │   ├── ArrayCollapse.md
│   │   │   │   ├── ArrayCollapse.zh-CN.md
│   │   │   │   ├── ArrayItems.md
│   │   │   │   ├── ArrayItems.zh-CN.md
│   │   │   │   ├── ArrayTable.md
│   │   │   │   ├── ArrayTable.zh-CN.md
│   │   │   │   ├── Cascader.md
│   │   │   │   ├── Cascader.zh-CN.md
│   │   │   │   ├── Checkbox.md
│   │   │   │   ├── Checkbox.zh-CN.md
│   │   │   │   ├── DatePicker.md
│   │   │   │   ├── DatePicker.zh-CN.md
│   │   │   │   ├── DatePicker2.md
│   │   │   │   ├── DatePicker2.zh-CN.md
│   │   │   │   ├── Editable.md
│   │   │   │   ├── Editable.zh-CN.md
│   │   │   │   ├── Form.md
│   │   │   │   ├── Form.zh-CN.md
│   │   │   │   ├── FormButtonGroup.md
│   │   │   │   ├── FormButtonGroup.zh-CN.md
│   │   │   │   ├── FormCollapse.md
│   │   │   │   ├── FormCollapse.zh-CN.md
│   │   │   │   ├── FormDialog.md
│   │   │   │   ├── FormDialog.zh-CN.md
│   │   │   │   ├── FormDrawer.md
│   │   │   │   ├── FormDrawer.zh-CN.md
│   │   │   │   ├── FormGrid.md
│   │   │   │   ├── FormGrid.zh-CN.md
│   │   │   │   ├── FormItem.md
│   │   │   │   ├── FormItem.zh-CN.md
│   │   │   │   ├── FormLayout.md
│   │   │   │   ├── FormLayout.zh-CN.md
│   │   │   │   ├── FormStep.md
│   │   │   │   ├── FormStep.zh-CN.md
│   │   │   │   ├── FormTab.md
│   │   │   │   ├── FormTab.zh-CN.md
│   │   │   │   ├── index.md
│   │   │   │   ├── index.zh-CN.md
│   │   │   │   ├── Input.md
│   │   │   │   ├── Input.zh-CN.md
│   │   │   │   ├── NumberPicker.md
│   │   │   │   ├── NumberPicker.zh-CN.md
│   │   │   │   ├── Password.md
│   │   │   │   ├── Password.zh-CN.md
│   │   │   │   ├── PreviewText.md
│   │   │   │   ├── PreviewText.zh-CN.md
│   │   │   │   ├── Radio.md
│   │   │   │   ├── Radio.zh-CN.md
│   │   │   │   ├── Reset.md
│   │   │   │   ├── Reset.zh-CN.md
│   │   │   │   ├── Select.md
│   │   │   │   ├── Select.zh-CN.md
│   │   │   │   ├── SelectTable.md
│   │   │   │   ├── SelectTable.zh-CN.md
│   │   │   │   ├── Space.md
│   │   │   │   ├── Space.zh-CN.md
│   │   │   │   ├── Submit.md
│   │   │   │   ├── Submit.zh-CN.md
│   │   │   │   ├── Switch.md
│   │   │   │   ├── Switch.zh-CN.md
│   │   │   │   ├── TimePicker.md
│   │   │   │   ├── TimePicker.zh-CN.md
│   │   │   │   ├── TimePicker2.md
│   │   │   │   ├── TimePicker2.zh-CN.md
│   │   │   │   ├── Transfer.md
│   │   │   │   ├── Transfer.zh-CN.md
│   │   │   │   ├── TreeSelect.md
│   │   │   │   ├── TreeSelect.zh-CN.md
│   │   │   │   ├── Upload.md
│   │   │   │   └── Upload.zh-CN.md
│   │   │   ├── index.md
│   │   │   └── index.zh-CN.md
│   │   ├── LESENCE.md
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── rollup.config.js
│   │   ├── src
│   │   │   ├── __builtins__
│   │   │   │   ├── empty.tsx
│   │   │   │   ├── hooks
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── useClickAway.ts
│   │   │   │   │   └── usePrefixCls.ts
│   │   │   │   ├── icons.tsx
│   │   │   │   ├── index.ts
│   │   │   │   ├── loading.ts
│   │   │   │   ├── mapSize.ts
│   │   │   │   ├── mapStatus.ts
│   │   │   │   ├── moment.ts
│   │   │   │   ├── pickDataProps.ts
│   │   │   │   ├── portal.tsx
│   │   │   │   ├── render.ts
│   │   │   │   └── toArray.ts
│   │   │   ├── array-base
│   │   │   │   ├── index.tsx
│   │   │   │   ├── main.scss
│   │   │   │   └── style.ts
│   │   │   ├── array-cards
│   │   │   │   ├── index.tsx
│   │   │   │   ├── main.scss
│   │   │   │   └── style.ts
│   │   │   ├── array-collapse
│   │   │   │   ├── index.tsx
│   │   │   │   ├── main.scss
│   │   │   │   └── style.ts
│   │   │   ├── array-items
│   │   │   │   ├── index.tsx
│   │   │   │   ├── main.scss
│   │   │   │   └── style.ts
│   │   │   ├── array-table
│   │   │   │   ├── index.tsx
│   │   │   │   ├── main.scss
│   │   │   │   └── style.ts
│   │   │   ├── cascader
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── checkbox
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── date-picker
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── date-picker2
│   │   │   │   ├── index.tsx
│   │   │   │   ├── main.scss
│   │   │   │   └── style.ts
│   │   │   ├── editable
│   │   │   │   ├── index.tsx
│   │   │   │   ├── main.scss
│   │   │   │   └── style.ts
│   │   │   ├── form
│   │   │   │   ├── index.tsx
│   │   │   │   ├── main.scss
│   │   │   │   └── style.ts
│   │   │   ├── form-button-group
│   │   │   │   ├── index.tsx
│   │   │   │   ├── main.scss
│   │   │   │   └── style.ts
│   │   │   ├── form-collapse
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── form-dialog
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── form-drawer
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── form-grid
│   │   │   │   ├── index.tsx
│   │   │   │   ├── main.scss
│   │   │   │   └── style.ts
│   │   │   ├── form-item
│   │   │   │   ├── animation.scss
│   │   │   │   ├── grid.scss
│   │   │   │   ├── index.tsx
│   │   │   │   ├── main.scss
│   │   │   │   ├── scss
│   │   │   │   │   └── variable.scss
│   │   │   │   └── style.ts
│   │   │   ├── form-layout
│   │   │   │   ├── index.tsx
│   │   │   │   ├── main.scss
│   │   │   │   ├── style.ts
│   │   │   │   └── useResponsiveFormLayout.ts
│   │   │   ├── form-step
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── form-tab
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── index.ts
│   │   │   ├── input
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── main.scss
│   │   │   ├── number-picker
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── password
│   │   │   │   ├── index.tsx
│   │   │   │   ├── PasswordStrength.tsx
│   │   │   │   └── style.ts
│   │   │   ├── preview-text
│   │   │   │   ├── index.tsx
│   │   │   │   ├── main.scss
│   │   │   │   └── style.ts
│   │   │   ├── radio
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── reset
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── select
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── select-table
│   │   │   │   ├── index.tsx
│   │   │   │   ├── main.scss
│   │   │   │   ├── style.ts
│   │   │   │   ├── useCheckSlackly.tsx
│   │   │   │   ├── useFilterOptions.tsx
│   │   │   │   ├── useFlatOptions.tsx
│   │   │   │   ├── useSize.tsx
│   │   │   │   ├── useTitleAddon.tsx
│   │   │   │   └── utils.ts
│   │   │   ├── space
│   │   │   │   ├── index.tsx
│   │   │   │   ├── main.scss
│   │   │   │   └── style.ts
│   │   │   ├── style.ts
│   │   │   ├── submit
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── switch
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── time-picker
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── time-picker2
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── transfer
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   ├── tree-select
│   │   │   │   ├── index.tsx
│   │   │   │   └── style.ts
│   │   │   └── upload
│   │   │       ├── index.tsx
│   │   │       ├── main.scss
│   │   │       ├── placeholder.ts
│   │   │       └── style.ts
│   │   ├── tsconfig.build.json
│   │   └── tsconfig.json
│   ├── path
│   │   ├── .npmignore
│   │   ├── benchmark.ts
│   │   ├── LICENSE.md
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── rollup.config.js
│   │   ├── src
│   │   │   ├── __tests__
│   │   │   │   ├── accessor.spec.ts
│   │   │   │   ├── basic.spec.ts
│   │   │   │   ├── match.spec.ts
│   │   │   │   ├── parser.spec.ts
│   │   │   │   └── share.spec.ts
│   │   │   ├── contexts.ts
│   │   │   ├── destructor.ts
│   │   │   ├── index.ts
│   │   │   ├── matcher.ts
│   │   │   ├── parser.ts
│   │   │   ├── shared.ts
│   │   │   ├── tokenizer.ts
│   │   │   ├── tokens.ts
│   │   │   └── types.ts
│   │   ├── tsconfig.build.json
│   │   └── tsconfig.json
│   ├── react
│   │   ├── .npmignore
│   │   ├── .umirc.js
│   │   ├── docs
│   │   │   ├── api
│   │   │   │   ├── components
│   │   │   │   │   ├── ArrayField.md
│   │   │   │   │   ├── ArrayField.zh-CN.md
│   │   │   │   │   ├── ExpressionScope.md
│   │   │   │   │   ├── ExpressionScope.zh-CN.md
│   │   │   │   │   ├── Field.md
│   │   │   │   │   ├── Field.zh-CN.md
│   │   │   │   │   ├── FormConsumer.md
│   │   │   │   │   ├── FormConsumer.zh-CN.md
│   │   │   │   │   ├── FormProvider.md
│   │   │   │   │   ├── FormProvider.zh-CN.md
│   │   │   │   │   ├── ObjectField.md
│   │   │   │   │   ├── ObjectField.zh-CN.md
│   │   │   │   │   ├── RecordScope.md
│   │   │   │   │   ├── RecordScope.zh-CN.md
│   │   │   │   │   ├── RecordsScope.md
│   │   │   │   │   ├── RecordsScope.zh-CN.md
│   │   │   │   │   ├── RecursionField.md
│   │   │   │   │   ├── RecursionField.zh-CN.md
│   │   │   │   │   ├── SchemaField.md
│   │   │   │   │   ├── SchemaField.zh-CN.md
│   │   │   │   │   ├── VoidField.md
│   │   │   │   │   └── VoidField.zh-CN.md
│   │   │   │   ├── hooks
│   │   │   │   │   ├── useExpressionScope.md
│   │   │   │   │   ├── useExpressionScope.zh-CN.md
│   │   │   │   │   ├── useField.md
│   │   │   │   │   ├── useField.zh-CN.md
│   │   │   │   │   ├── useFieldSchema.md
│   │   │   │   │   ├── useFieldSchema.zh-CN.md
│   │   │   │   │   ├── useForm.md
│   │   │   │   │   ├── useForm.zh-CN.md
│   │   │   │   │   ├── useFormEffects.md
│   │   │   │   │   ├── useFormEffects.zh-CN.md
│   │   │   │   │   ├── useParentForm.md
│   │   │   │   │   └── useParentForm.zh-CN.md
│   │   │   │   └── shared
│   │   │   │       ├── connect.md
│   │   │   │       ├── connect.zh-CN.md
│   │   │   │       ├── context.md
│   │   │   │       ├── context.zh-CN.md
│   │   │   │       ├── mapProps.md
│   │   │   │       ├── mapProps.zh-CN.md
│   │   │   │       ├── mapReadPretty.md
│   │   │   │       ├── mapReadPretty.zh-CN.md
│   │   │   │       ├── observer.md
│   │   │   │       ├── observer.zh-CN.md
│   │   │   │       ├── Schema.md
│   │   │   │       └── Schema.zh-CN.md
│   │   │   ├── guide
│   │   │   │   ├── architecture.md
│   │   │   │   ├── architecture.zh-CN.md
│   │   │   │   ├── concept.md
│   │   │   │   ├── concept.zh-CN.md
│   │   │   │   ├── index.md
│   │   │   │   └── index.zh-CN.md
│   │   │   ├── index.md
│   │   │   └── index.zh-CN.md
│   │   ├── LICENSE.md
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── rollup.config.js
│   │   ├── src
│   │   │   ├── __tests__
│   │   │   │   ├── expression.spec.tsx
│   │   │   │   ├── field.spec.tsx
│   │   │   │   ├── form.spec.tsx
│   │   │   │   ├── schema.json.spec.tsx
│   │   │   │   ├── schema.markup.spec.tsx
│   │   │   │   └── shared.tsx
│   │   │   ├── components
│   │   │   │   ├── ArrayField.tsx
│   │   │   │   ├── ExpressionScope.tsx
│   │   │   │   ├── Field.tsx
│   │   │   │   ├── FormConsumer.tsx
│   │   │   │   ├── FormProvider.tsx
│   │   │   │   ├── index.ts
│   │   │   │   ├── ObjectField.tsx
│   │   │   │   ├── ReactiveField.tsx
│   │   │   │   ├── RecordScope.tsx
│   │   │   │   ├── RecordsScope.tsx
│   │   │   │   ├── RecursionField.tsx
│   │   │   │   ├── SchemaField.tsx
│   │   │   │   └── VoidField.tsx
│   │   │   ├── global.d.ts
│   │   │   ├── hooks
│   │   │   │   ├── index.ts
│   │   │   │   ├── useAttach.ts
│   │   │   │   ├── useExpressionScope.ts
│   │   │   │   ├── useField.ts
│   │   │   │   ├── useFieldSchema.ts
│   │   │   │   ├── useForm.ts
│   │   │   │   ├── useFormEffects.ts
│   │   │   │   └── useParentForm.ts
│   │   │   ├── index.ts
│   │   │   ├── shared
│   │   │   │   ├── connect.ts
│   │   │   │   ├── context.ts
│   │   │   │   ├── index.ts
│   │   │   │   └── render.ts
│   │   │   └── types.ts
│   │   ├── tsconfig.build.json
│   │   └── tsconfig.json
│   ├── reactive
│   │   ├── .npmignore
│   │   ├── .umirc.js
│   │   ├── benchmark.ts
│   │   ├── docs
│   │   │   ├── api
│   │   │   │   ├── action.md
│   │   │   │   ├── action.zh-CN.md
│   │   │   │   ├── autorun.md
│   │   │   │   ├── autorun.zh-CN.md
│   │   │   │   ├── batch.md
│   │   │   │   ├── batch.zh-CN.md
│   │   │   │   ├── define.md
│   │   │   │   ├── define.zh-CN.md
│   │   │   │   ├── hasCollected.md
│   │   │   │   ├── hasCollected.zh-CN.md
│   │   │   │   ├── markObservable.md
│   │   │   │   ├── markObservable.zh-CN.md
│   │   │   │   ├── markRaw.md
│   │   │   │   ├── markRaw.zh-CN.md
│   │   │   │   ├── model.md
│   │   │   │   ├── model.zh-CN.md
│   │   │   │   ├── observable.md
│   │   │   │   ├── observable.zh-CN.md
│   │   │   │   ├── observe.md
│   │   │   │   ├── observe.zh-CN.md
│   │   │   │   ├── raw.md
│   │   │   │   ├── raw.zh-CN.md
│   │   │   │   ├── react
│   │   │   │   │   ├── observer.md
│   │   │   │   │   └── observer.zh-CN.md
│   │   │   │   ├── reaction.md
│   │   │   │   ├── reaction.zh-CN.md
│   │   │   │   ├── toJS.md
│   │   │   │   ├── toJS.zh-CN.md
│   │   │   │   ├── tracker.md
│   │   │   │   ├── tracker.zh-CN.md
│   │   │   │   ├── typeChecker.md
│   │   │   │   ├── typeChecker.zh-CN.md
│   │   │   │   ├── untracked.md
│   │   │   │   ├── untracked.zh-CN.md
│   │   │   │   └── vue
│   │   │   │       ├── observer.md
│   │   │   │       └── observer.zh-CN.md
│   │   │   ├── guide
│   │   │   │   ├── best-practice.md
│   │   │   │   ├── best-practice.zh-CN.md
│   │   │   │   ├── concept.md
│   │   │   │   ├── concept.zh-CN.md
│   │   │   │   ├── index.md
│   │   │   │   └── index.zh-CN.md
│   │   │   ├── index.md
│   │   │   └── index.zh-CN.md
│   │   ├── LICENSE.md
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── rollup.config.js
│   │   ├── src
│   │   │   ├── __tests__
│   │   │   │   ├── action.spec.ts
│   │   │   │   ├── annotations.spec.ts
│   │   │   │   ├── array.spec.ts
│   │   │   │   ├── autorun.spec.ts
│   │   │   │   ├── batch.spec.ts
│   │   │   │   ├── collections-map.spec.ts
│   │   │   │   ├── collections-set.spec.ts
│   │   │   │   ├── collections-weakmap.spec.ts
│   │   │   │   ├── collections-weakset.spec.ts
│   │   │   │   ├── define.spec.ts
│   │   │   │   ├── externals.spec.ts
│   │   │   │   ├── hasCollected.spec.ts
│   │   │   │   ├── observable.spec.ts
│   │   │   │   ├── observe.spec.ts
│   │   │   │   ├── tracker.spec.ts
│   │   │   │   └── untracked.spec.ts
│   │   │   ├── action.ts
│   │   │   ├── annotations
│   │   │   │   ├── box.ts
│   │   │   │   ├── computed.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── observable.ts
│   │   │   │   ├── ref.ts
│   │   │   │   └── shallow.ts
│   │   │   ├── array.ts
│   │   │   ├── autorun.ts
│   │   │   ├── batch.ts
│   │   │   ├── checkers.ts
│   │   │   ├── environment.ts
│   │   │   ├── externals.ts
│   │   │   ├── global.d.ts
│   │   │   ├── handlers.ts
│   │   │   ├── index.ts
│   │   │   ├── internals.ts
│   │   │   ├── model.ts
│   │   │   ├── observable.ts
│   │   │   ├── observe.ts
│   │   │   ├── reaction.ts
│   │   │   ├── tracker.ts
│   │   │   ├── tree.ts
│   │   │   ├── types.ts
│   │   │   └── untracked.ts
│   │   ├── tsconfig.build.json
│   │   └── tsconfig.json
│   ├── reactive-react
│   │   ├── .npmignore
│   │   ├── .umirc.js
│   │   ├── LICENSE.md
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── rollup.config.js
│   │   ├── src
│   │   │   ├── hooks
│   │   │   │   ├── index.ts
│   │   │   │   ├── useCompatEffect.ts
│   │   │   │   ├── useCompatFactory.ts
│   │   │   │   ├── useDidUpdate.ts
│   │   │   │   ├── useForceUpdate.ts
│   │   │   │   ├── useLayoutEffect.ts
│   │   │   │   └── useObserver.ts
│   │   │   ├── index.ts
│   │   │   ├── observer.ts
│   │   │   ├── shared
│   │   │   │   ├── gc.ts
│   │   │   │   ├── global.ts
│   │   │   │   ├── immediate.ts
│   │   │   │   └── index.ts
│   │   │   └── types.ts
│   │   ├── tsconfig.build.json
│   │   └── tsconfig.json
│   ├── reactive-test-cases-for-react18
│   │   ├── .npmignore
│   │   ├── .umirc.js
│   │   ├── LICENSE.md
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── index.js
│   │   │   └── MySlowList.js
│   │   ├── template.ejs
│   │   ├── tsconfig.build.json
│   │   ├── tsconfig.json
│   │   ├── webpack.base.ts
│   │   ├── webpack.dev.ts
│   │   └── webpack.prod.ts
│   ├── reactive-vue
│   │   ├── .npmignore
│   │   ├── LICENSE.md
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── rollup.config.js
│   │   ├── src
│   │   │   ├── __tests__
│   │   │   │   └── observer.spec.ts
│   │   │   ├── hooks
│   │   │   │   ├── index.ts
│   │   │   │   └── useObserver.ts
│   │   │   ├── index.ts
│   │   │   ├── observer
│   │   │   │   ├── collectData.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── observerInVue2.ts
│   │   │   │   └── observerInVue3.ts
│   │   │   └── types.ts
│   │   ├── tsconfig.build.json
│   │   └── tsconfig.json
│   ├── shared
│   │   ├── .npmignore
│   │   ├── LICENSE.md
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── rollup.config.js
│   │   ├── src
│   │   │   ├── __tests__
│   │   │   │   └── index.spec.ts
│   │   │   ├── array.ts
│   │   │   ├── case.ts
│   │   │   ├── checkers.ts
│   │   │   ├── clone.ts
│   │   │   ├── compare.ts
│   │   │   ├── defaults.ts
│   │   │   ├── deprecate.ts
│   │   │   ├── global.ts
│   │   │   ├── index.ts
│   │   │   ├── instanceof.ts
│   │   │   ├── isEmpty.ts
│   │   │   ├── merge.ts
│   │   │   ├── middleware.ts
│   │   │   ├── path.ts
│   │   │   ├── string.ts
│   │   │   ├── subscribable.ts
│   │   │   └── uid.ts
│   │   ├── tsconfig.build.json
│   │   └── tsconfig.json
│   ├── validator
│   │   ├── .npmignore
│   │   ├── LICENSE.md
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── rollup.config.js
│   │   ├── src
│   │   │   ├── __tests__
│   │   │   │   ├── parser.spec.ts
│   │   │   │   ├── registry.spec.ts
│   │   │   │   └── validator.spec.ts
│   │   │   ├── formats.ts
│   │   │   ├── index.ts
│   │   │   ├── locale.ts
│   │   │   ├── parser.ts
│   │   │   ├── registry.ts
│   │   │   ├── rules.ts
│   │   │   ├── template.ts
│   │   │   ├── types.ts
│   │   │   └── validator.ts
│   │   ├── tsconfig.build.json
│   │   └── tsconfig.json
│   └── vue
│       ├── .npmignore
│       ├── bin
│       │   ├── formily-vue-fix.js
│       │   └── formily-vue-switch.js
│       ├── docs
│       │   ├── .vuepress
│       │   │   ├── components
│       │   │   │   ├── createCodeSandBox.js
│       │   │   │   ├── dumi-previewer.vue
│       │   │   │   └── highlight.js
│       │   │   ├── config.js
│       │   │   ├── enhanceApp.js
│       │   │   └── styles
│       │   │       └── index.styl
│       │   ├── api
│       │   │   ├── components
│       │   │   │   ├── array-field.md
│       │   │   │   ├── expression-scope.md
│       │   │   │   ├── field.md
│       │   │   │   ├── form-consumer.md
│       │   │   │   ├── form-provider.md
│       │   │   │   ├── object-field.md
│       │   │   │   ├── recursion-field-with-component.md
│       │   │   │   ├── recursion-field.md
│       │   │   │   ├── schema-field-with-schema.md
│       │   │   │   ├── schema-field.md
│       │   │   │   └── void-field.md
│       │   │   ├── hooks
│       │   │   │   ├── use-field-schema.md
│       │   │   │   ├── use-field.md
│       │   │   │   ├── use-form-effects.md
│       │   │   │   ├── use-form.md
│       │   │   │   └── use-parent-form.md
│       │   │   └── shared
│       │   │       ├── connect.md
│       │   │       ├── injections.md
│       │   │       ├── map-props.md
│       │   │       ├── map-read-pretty.md
│       │   │       ├── observer.md
│       │   │       └── schema.md
│       │   ├── demos
│       │   │   ├── api
│       │   │   │   ├── components
│       │   │   │   │   ├── array-field.vue
│       │   │   │   │   ├── expression-scope.vue
│       │   │   │   │   ├── field.vue
│       │   │   │   │   ├── form-consumer.vue
│       │   │   │   │   ├── form-provider.vue
│       │   │   │   │   ├── object-field.vue
│       │   │   │   │   ├── recursion-field-with-component.vue
│       │   │   │   │   ├── recursion-field.vue
│       │   │   │   │   ├── schema-field-with-schema.vue
│       │   │   │   │   ├── schema-field.vue
│       │   │   │   │   └── void-field.vue
│       │   │   │   ├── hooks
│       │   │   │   │   ├── use-field-schema.vue
│       │   │   │   │   ├── use-field.vue
│       │   │   │   │   ├── use-form-effects.vue
│       │   │   │   │   ├── use-form.vue
│       │   │   │   │   └── use-parent-form.vue
│       │   │   │   └── shared
│       │   │   │       ├── connect.vue
│       │   │   │       ├── map-props.vue
│       │   │   │       ├── map-read-pretty.vue
│       │   │   │       └── observer.vue
│       │   │   ├── index.vue
│       │   │   └── questions
│       │   │       ├── default-slot.vue
│       │   │       ├── events.vue
│       │   │       ├── named-slot.vue
│       │   │       └── scoped-slot.vue
│       │   ├── guide
│       │   │   ├── architecture.md
│       │   │   ├── concept.md
│       │   │   └── README.md
│       │   ├── questions
│       │   │   └── README.md
│       │   └── README.md
│       ├── package.json
│       ├── README.md
│       ├── rollup.config.js
│       ├── scripts
│       │   ├── postinstall.js
│       │   ├── switch-cli.js
│       │   └── utils.js
│       ├── src
│       │   ├── __tests__
│       │   │   ├── expression.scope.spec.ts
│       │   │   ├── field.spec.ts
│       │   │   ├── form.spec.ts
│       │   │   ├── schema.json.spec.ts
│       │   │   ├── schema.markup.spec.ts
│       │   │   ├── shared.spec.ts
│       │   │   └── utils.spec.ts
│       │   ├── components
│       │   │   ├── ArrayField.ts
│       │   │   ├── ExpressionScope.ts
│       │   │   ├── Field.ts
│       │   │   ├── FormConsumer.ts
│       │   │   ├── FormProvider.ts
│       │   │   ├── index.ts
│       │   │   ├── ObjectField.ts
│       │   │   ├── ReactiveField.ts
│       │   │   ├── RecursionField.ts
│       │   │   ├── SchemaField.ts
│       │   │   └── VoidField.ts
│       │   ├── global.d.ts
│       │   ├── hooks
│       │   │   ├── index.ts
│       │   │   ├── useAttach.ts
│       │   │   ├── useField.ts
│       │   │   ├── useFieldSchema.ts
│       │   │   ├── useForm.ts
│       │   │   ├── useFormEffects.ts
│       │   │   ├── useInjectionCleaner.ts
│       │   │   └── useParentForm.ts
│       │   ├── index.ts
│       │   ├── shared
│       │   │   ├── connect.ts
│       │   │   ├── context.ts
│       │   │   ├── createForm.ts
│       │   │   ├── fragment.ts
│       │   │   ├── h.ts
│       │   │   └── index.ts
│       │   ├── types
│       │   │   └── index.ts
│       │   ├── utils
│       │   │   ├── formatVNodeData.ts
│       │   │   ├── getFieldProps.ts
│       │   │   ├── getRawComponent.ts
│       │   │   └── resolveSchemaProps.ts
│       │   └── vue2-components.ts
│       ├── tsconfig.build.json
│       ├── tsconfig.json
│       └── tsconfig.types.json
├── README.md
├── README.zh-cn.md
├── scripts
│   ├── build-style
│   │   ├── buildAllStyles.ts
│   │   ├── copy.ts
│   │   ├── helper.ts
│   │   └── index.ts
│   └── rollup.base.js
├── tsconfig.build.json
├── tsconfig.jest.json
├── tsconfig.json
└── yarn.lock
```

# Files

--------------------------------------------------------------------------------
/packages/core/docs/index.md:
--------------------------------------------------------------------------------

```markdown
  1 | ---
  2 | title: Formily-Alibaba unified front-end form solution
  3 | order: 10
  4 | hero:
  5 |   title: Core Library
  6 |   desc: Alibaba Unified Form Solution
  7 |   actions:
  8 |     - text: Home Site
  9 |       link: //formilyjs.org
 10 |     - text: Document
 11 |       link: /guide
 12 | features:
 13 |   - icon: https://img.alicdn.com/imgextra/i1/O1CN01bHdrZJ1rEOESvXEi5_!!6000000005599-55-tps-800-800.svg
 14 |     title: High Performance
 15 |     desc: Efficient update, Demand rendering
 16 |   - icon: https://img.alicdn.com/imgextra/i3/O1CN0194OqFF1ui6mMT4g7O_!!6000000006070-55-tps-800-800.svg
 17 |     title: Excellent Reusability
 18 |     desc: Independent side effects, Pluggable
 19 |   - icon: https://img.alicdn.com/imgextra/i2/O1CN01QnfYS71E44I1ZpxU9_!!6000000000297-55-tps-800-800.svg
 20 |     title: Elegant Linkage Writing
 21 |     desc: Flexible, Complete, Elegant
 22 |   - icon: https://img.alicdn.com/imgextra/i2/O1CN01YqmcpN1tDalwgyHBH_!!6000000005868-55-tps-800-800.svg
 23 |     title: Complete domain model
 24 |     desc: Pure Core, No UI, No Framework
 25 |   - icon: https://img.alicdn.com/imgextra/i4/O1CN018vDmpl2186xdLu6KI_!!6000000006939-55-tps-800-800.svg
 26 |     title: Friendly debugging
 27 |     desc: Natural docking with Formily DevTools
 28 |   - icon: https://img.alicdn.com/imgextra/i4/O1CN01u6jHgs1ZMwXpjAYnh_!!6000000003181-55-tps-800-800.svg
 29 |     title: Smart Tips
 30 |     desc: Embrace Typescript
 31 | footer: Open-source MIT Licensed | Copyright © 2019-present<br />Powered by self
 32 | ---
 33 | 
 34 | ## Installation
 35 | 
 36 | ```bash
 37 | $ npm install --save @formily/core
 38 | 
 39 | ```
 40 | 
 41 | ## Quick start
 42 | 
 43 | > The following case is to teach you step by step to implement a form from scratch
 44 | >
 45 | > @formily/core brings you the following capabilities:
 46 | >
 47 | > 1. Responsive computing capabilities
 48 | > 2. Verification capability, verification internationalization capability
 49 | > 3. Value Management Ability
 50 | > 4. Linkage management capabilities
 51 | > 5. Development tool debugging capabilities, [download Formily Devtools](https://chrome.google.com/webstore/detail/formily-devtools/kkocalmbfnplecdmbadaapgapdioecfm?hl=zh-CN)
 52 | 
 53 | ```tsx
 54 | /**
 55 |  * defaultShowCode: true
 56 |  */
 57 | import React, { createContext, useMemo, useContext, useEffect } from 'react'
 58 | import { createForm, setValidateLanguage } from '@formily/core'
 59 | import { observer } from '@formily/reactive-react'
 60 | 
 61 | //Create a context to facilitate Field consumption
 62 | const FormContext = createContext()
 63 | //Create a context to facilitate the consumption of FormItem
 64 | const FieldContext = createContext()
 65 | 
 66 | //State bridge component
 67 | const Field = observer((props) => {
 68 |   const form = useContext(FormContext)
 69 |   //Create a field
 70 |   const field = form.createField(props)
 71 |   useEffect(() => {
 72 |     //Mount field
 73 |     field.onMount()
 74 |     return () => {
 75 |       //Unload field
 76 |       field.onUnmount()
 77 |     }
 78 |   })
 79 |   if (!field.visible || field.hidden) return null
 80 |   //Render the field, associate the field state with the UI component
 81 |   const component = React.createElement(field.component[0], {
 82 |     ...field.component[1],
 83 |     value: field.value,
 84 |     onChange: field.onInput,
 85 |   })
 86 | 
 87 |   //Render field wrapper
 88 |   const decorator = React.createElement(
 89 |     field.decorator[0],
 90 |     field.decorator[1],
 91 |     component
 92 |   )
 93 | 
 94 |   return (
 95 |     <FieldContext.Provider value={field}>{decorator}</FieldContext.Provider>
 96 |   )
 97 | })
 98 | 
 99 | // FormItem UI component
100 | const FormItem = observer(({ children }) => {
101 |   const field = useContext(FieldContext)
102 |   return (
103 |     <div>
104 |       <div style={{ height: 20 }}>{field.title}:</div>
105 |       {children}
106 |       <div style={{ height: 20, fontSize: 12, color: 'red' }}>
107 |         {field.selfErrors.join(',')}
108 |       </div>
109 |     </div>
110 |   )
111 | })
112 | 
113 | // Input UI component
114 | const Input = (props) => {
115 |   return (
116 |     <input
117 |       {...props}
118 |       value={props.value || ''}
119 |       style={{
120 |         ...props.style,
121 |         border: '2px solid rgb(186 203 255)',
122 |         borderRadius: 6,
123 |         width: '100%',
124 |         height: 28,
125 |         padding: '0 5px',
126 |       }}
127 |     />
128 |   )
129 | }
130 | 
131 | //Form management entrance
132 | const FormProvider = (props) => {
133 |   useEffect(() => {
134 |     //Mount form
135 |     props.form?.onMount()
136 |     return () => {
137 |       //Uninstall the form
138 |       props.form?.onUnmount()
139 |     }
140 |   })
141 |   return (
142 |     <FormContext.Provider value={props.form}>
143 |       {props.children}
144 |     </FormContext.Provider>
145 |   )
146 | }
147 | 
148 | //Form response monitor
149 | const FormConsumer = observer((props) => {
150 |   const form = useContext(FormContext)
151 |   return <div>{props.children(form)}</div>
152 | })
153 | 
154 | /*
155 |  * The above logic has been implemented in @formily/react or @formily/vue, and there is no need to rewrite it in actual use
156 |  */
157 | 
158 | //Switch the built-in check internationalization copy to English
159 | setValidateLanguage('en')
160 | 
161 | export default () => {
162 |   const form = useMemo(() => createForm({ validateFirst: true }))
163 | 
164 |   const createPasswordEqualValidate = (equalName) => (field) => {
165 |     if (
166 |       form.values.confirm_password &&
167 |       field.value &&
168 |       form.values[equalName] !== field.value
169 |     ) {
170 |       field.selfErrors = ['Password does not match Confirm Password.']
171 |     } else {
172 |       field.selfErrors = []
173 |     }
174 |   }
175 | 
176 |   return (
177 |     <FormProvider form={form}>
178 |       <Field
179 |         name="name"
180 |         title="Name"
181 |         required
182 |         decorator={[FormItem]}
183 |         component={[Input, { placeholder: 'Please Input' }]}
184 |       />
185 |       <Field
186 |         name="password"
187 |         title="Password"
188 |         required
189 |         decorator={[FormItem]}
190 |         component={[Input, { type: 'password', placeholder: 'Please Input' }]}
191 |         reactions={createPasswordEqualValidate('confirm_password')}
192 |       />
193 |       <Field
194 |         name="confirm_password"
195 |         title="Confirm Password"
196 |         required
197 |         decorator={[FormItem]}
198 |         component={[Input, { type: 'password', placeholder: 'Please Input' }]}
199 |         reactions={createPasswordEqualValidate('password')}
200 |       />
201 |       <code>
202 |         <pre>
203 |           <FormConsumer>
204 |             {(form) => JSON.stringify(form.values, null, 2)}
205 |           </FormConsumer>
206 |         </pre>
207 |       </code>
208 |     </FormProvider>
209 |   )
210 | }
211 | ```
212 | 
```

--------------------------------------------------------------------------------
/packages/element/src/form-collapse/index.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { Collapse, CollapseItem, Badge } from 'element-ui'
  2 | import { model } from '@formily/reactive'
  3 | import type {
  4 |   Collapse as CollapseProps,
  5 |   CollapseItem as CollapseItemProps,
  6 | } from 'element-ui'
  7 | import {
  8 |   useField,
  9 |   useFieldSchema,
 10 |   RecursionField,
 11 |   h,
 12 |   Fragment,
 13 | } from '@formily/vue'
 14 | import { observer } from '@formily/reactive-vue'
 15 | import { Schema, SchemaKey } from '@formily/json-schema'
 16 | import { composeExport, stylePrefix } from '../__builtins__'
 17 | import { toArr } from '@formily/shared'
 18 | import { computed, defineComponent, PropType } from 'vue-demi'
 19 | import { GeneralField } from '@formily/core'
 20 | 
 21 | type ActiveKeys = string | number | Array<string | number>
 22 | 
 23 | type ActiveKey = string | number
 24 | 
 25 | type Panels = { name: SchemaKey; props: any; schema: Schema }[]
 26 | 
 27 | export interface IFormCollapse {
 28 |   activeKeys: ActiveKeys
 29 |   hasActiveKey(key: ActiveKey): boolean
 30 |   setActiveKeys(key: ActiveKeys): void
 31 |   addActiveKey(key: ActiveKey): void
 32 |   removeActiveKey(key: ActiveKey): void
 33 |   toggleActiveKey(key: ActiveKey): void
 34 | }
 35 | 
 36 | export interface IFormCollapseProps extends CollapseProps {
 37 |   formCollapse?: IFormCollapse
 38 |   activeKey?: ActiveKey
 39 | }
 40 | 
 41 | const usePanels = (collapseField: GeneralField, schema: Schema) => {
 42 |   const panels: Panels = []
 43 |   schema.mapProperties((schema, name) => {
 44 |     const field = collapseField.query(collapseField.address.concat(name)).take()
 45 |     if (field?.display === 'none' || field?.display === 'hidden') return
 46 |     if (schema['x-component']?.indexOf('FormCollapse.Item') > -1) {
 47 |       panels.push({
 48 |         name,
 49 |         props: {
 50 |           ...schema?.['x-component-props'],
 51 |           key: schema?.['x-component-props']?.key || name,
 52 |         },
 53 |         schema,
 54 |       })
 55 |     }
 56 |   })
 57 |   return panels
 58 | }
 59 | 
 60 | const createFormCollapse = (defaultActiveKeys?: ActiveKeys) => {
 61 |   const formCollapse = model({
 62 |     activeKeys: defaultActiveKeys,
 63 |     setActiveKeys(keys: ActiveKeys) {
 64 |       formCollapse.activeKeys = keys
 65 |     },
 66 |     hasActiveKey(key: ActiveKey) {
 67 |       if (Array.isArray(formCollapse.activeKeys)) {
 68 |         if (formCollapse.activeKeys.includes(key)) {
 69 |           return true
 70 |         }
 71 |       } else if (formCollapse.activeKeys == key) {
 72 |         return true
 73 |       }
 74 |       return false
 75 |     },
 76 |     addActiveKey(key: ActiveKey) {
 77 |       if (formCollapse.hasActiveKey(key)) return
 78 |       formCollapse.activeKeys = toArr(formCollapse.activeKeys).concat(key)
 79 |     },
 80 |     removeActiveKey(key: ActiveKey) {
 81 |       if (Array.isArray(formCollapse.activeKeys)) {
 82 |         formCollapse.activeKeys = formCollapse.activeKeys.filter(
 83 |           (item) => item != key
 84 |         )
 85 |       } else {
 86 |         formCollapse.activeKeys = ''
 87 |       }
 88 |     },
 89 |     toggleActiveKey(key: ActiveKey) {
 90 |       if (formCollapse.hasActiveKey(key)) {
 91 |         formCollapse.removeActiveKey(key)
 92 |       } else {
 93 |         formCollapse.addActiveKey(key)
 94 |       }
 95 |     },
 96 |   })
 97 |   return formCollapse
 98 | }
 99 | 
100 | const FormCollapse = observer(
101 |   defineComponent({
102 |     inheritAttrs: false,
103 |     props: {
104 |       formCollapse: { type: Object as PropType<IFormCollapse> },
105 |       activeKey: {
106 |         type: [String, Number],
107 |       },
108 |     },
109 |     setup(props, { attrs, emit }) {
110 |       const field = useField()
111 |       const schema = useFieldSchema()
112 |       const prefixCls = `${stylePrefix}-form-collapse`
113 |       const _formCollapse = computed(
114 |         () => props.formCollapse ?? createFormCollapse()
115 |       )
116 | 
117 |       const takeActiveKeys = (panels: Panels) => {
118 |         if (props.activeKey) return props.activeKey
119 |         if (_formCollapse.value?.activeKeys)
120 |           return _formCollapse.value?.activeKeys
121 |         if (attrs.accordion) return panels[0]?.name
122 |         return panels.map((item) => item.name)
123 |       }
124 | 
125 |       const badgedHeader = (key: SchemaKey, props: any) => {
126 |         const errors = field.value.form.queryFeedbacks({
127 |           type: 'error',
128 |           address: `${field.value.address.concat(key)}.*`,
129 |         })
130 |         if (errors.length) {
131 |           return h(
132 |             Badge,
133 |             {
134 |               class: [`${prefixCls}-errors-badge`],
135 |               props: {
136 |                 value: errors.length,
137 |               },
138 |             },
139 |             { default: () => props.title }
140 |           )
141 |         }
142 |         return props.title
143 |       }
144 | 
145 |       return () => {
146 |         const panels = usePanels(field.value, schema.value)
147 |         const activeKey = takeActiveKeys(panels)
148 |         return h(
149 |           Collapse,
150 |           {
151 |             class: prefixCls,
152 |             props: {
153 |               value: activeKey,
154 |             },
155 |             on: {
156 |               change: (key: string | string[]) => {
157 |                 emit('input', key)
158 |                 _formCollapse.value.setActiveKeys(key)
159 |               },
160 |             },
161 |           },
162 |           {
163 |             default: () => {
164 |               return panels.map(({ props, schema, name }, index) => {
165 |                 return h(
166 |                   CollapseItem,
167 |                   {
168 |                     key: index,
169 |                     props: {
170 |                       ...props,
171 |                       name,
172 |                     },
173 |                   },
174 |                   {
175 |                     default: () => [
176 |                       h(RecursionField, { props: { schema, name } }, {}),
177 |                     ],
178 |                     title: () =>
179 |                       h(
180 |                         'span',
181 |                         {},
182 |                         { default: () => badgedHeader(name, props) }
183 |                       ),
184 |                   }
185 |                 )
186 |               })
187 |             },
188 |           }
189 |         )
190 |       }
191 |     },
192 |   })
193 | )
194 | 
195 | export const FormCollapseItem = defineComponent<CollapseItemProps>({
196 |   name: 'FFormCollapseItem',
197 |   setup(_props, { slots }) {
198 |     return () => h(Fragment, {}, slots)
199 |   },
200 | })
201 | 
202 | const composeFormCollapse = composeExport(FormCollapse, {
203 |   Item: FormCollapseItem,
204 |   createFormCollapse,
205 | })
206 | 
207 | export { composeFormCollapse as FormCollapse }
208 | export default composeFormCollapse
209 | 
```

--------------------------------------------------------------------------------
/packages/antd/docs/components/Editable.zh-CN.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Editable
  2 | 
  3 | > 局部编辑器,对于一些空间要求较高的表单区域可以使用该组件
  4 | >
  5 | > Editable 组件相当于是 FormItem 组件的变体,所以通常放在 decorator 中
  6 | 
  7 | ## Markup Schema 案例
  8 | 
  9 | ```tsx
 10 | import React from 'react'
 11 | import {
 12 |   Input,
 13 |   DatePicker,
 14 |   Editable,
 15 |   FormItem,
 16 |   FormButtonGroup,
 17 |   Submit,
 18 | } from '@formily/antd'
 19 | import { createForm } from '@formily/core'
 20 | import { FormProvider, createSchemaField } from '@formily/react'
 21 | 
 22 | const SchemaField = createSchemaField({
 23 |   components: {
 24 |     DatePicker,
 25 |     Editable,
 26 |     Input,
 27 |     FormItem,
 28 |   },
 29 | })
 30 | 
 31 | const form = createForm()
 32 | 
 33 | export default () => (
 34 |   <FormProvider form={form}>
 35 |     <SchemaField>
 36 |       <SchemaField.String
 37 |         name="date"
 38 |         title="日期"
 39 |         x-decorator="Editable"
 40 |         x-component="DatePicker"
 41 |       />
 42 |       <SchemaField.String
 43 |         name="input"
 44 |         title="输入框"
 45 |         x-decorator="Editable"
 46 |         x-component="Input"
 47 |       />
 48 |       <SchemaField.Void
 49 |         name="void"
 50 |         title="虚拟节点容器"
 51 |         x-component="Editable.Popover"
 52 |         x-reactions={(field) => {
 53 |           field.title = field.query('.void.date2').get('value') || field.title
 54 |         }}
 55 |       >
 56 |         <SchemaField.String
 57 |           name="date2"
 58 |           title="日期"
 59 |           x-decorator="FormItem"
 60 |           x-component="DatePicker"
 61 |         />
 62 |         <SchemaField.String
 63 |           name="input2"
 64 |           title="输入框"
 65 |           x-decorator="FormItem"
 66 |           x-component="Input"
 67 |         />
 68 |       </SchemaField.Void>
 69 |       <SchemaField.Object
 70 |         name="iobject"
 71 |         title="对象节点容器"
 72 |         x-component="Editable.Popover"
 73 |         x-reactions={(field) => {
 74 |           field.title = field.value?.date || field.title
 75 |         }}
 76 |       >
 77 |         <SchemaField.String
 78 |           name="date"
 79 |           title="日期"
 80 |           x-decorator="FormItem"
 81 |           x-component="DatePicker"
 82 |         />
 83 |         <SchemaField.String
 84 |           name="input"
 85 |           title="输入框"
 86 |           x-decorator="FormItem"
 87 |           x-component="Input"
 88 |         />
 89 |       </SchemaField.Object>
 90 |     </SchemaField>
 91 |     <FormButtonGroup>
 92 |       <Submit onSubmit={console.log}>提交</Submit>
 93 |     </FormButtonGroup>
 94 |   </FormProvider>
 95 | )
 96 | ```
 97 | 
 98 | ## JSON Schema 案例
 99 | 
100 | ```tsx
101 | import React from 'react'
102 | import {
103 |   Input,
104 |   DatePicker,
105 |   Editable,
106 |   FormItem,
107 |   FormButtonGroup,
108 |   Submit,
109 | } from '@formily/antd'
110 | import { createForm } from '@formily/core'
111 | import { FormProvider, createSchemaField } from '@formily/react'
112 | 
113 | const SchemaField = createSchemaField({
114 |   components: {
115 |     DatePicker,
116 |     Editable,
117 |     Input,
118 |     FormItem,
119 |   },
120 | })
121 | 
122 | const form = createForm()
123 | 
124 | const schema = {
125 |   type: 'object',
126 |   properties: {
127 |     date: {
128 |       type: 'string',
129 |       title: '日期',
130 |       'x-decorator': 'Editable',
131 |       'x-component': 'DatePicker',
132 |     },
133 |     input: {
134 |       type: 'string',
135 |       title: '输入框',
136 |       'x-decorator': 'Editable',
137 |       'x-component': 'Input',
138 |     },
139 |     void: {
140 |       type: 'void',
141 |       title: '虚拟节点容器',
142 |       'x-component': 'Editable.Popover',
143 |       'x-reactions':
144 |         "{{(field) => field.title = field.query('.void.date2').get('value') || field.title}}",
145 |       properties: {
146 |         date2: {
147 |           type: 'string',
148 |           title: '日期',
149 |           'x-decorator': 'FormItem',
150 |           'x-component': 'DatePicker',
151 |         },
152 |         input2: {
153 |           type: 'string',
154 |           title: '输入框',
155 |           'x-decorator': 'FormItem',
156 |           'x-component': 'Input',
157 |         },
158 |       },
159 |     },
160 |     iobject: {
161 |       type: 'object',
162 |       title: '对象节点容器',
163 |       'x-component': 'Editable.Popover',
164 |       'x-reactions':
165 |         '{{(field) => field.title = field.value && field.value.date || field.title}}',
166 |       properties: {
167 |         date: {
168 |           type: 'string',
169 |           title: '日期',
170 |           'x-decorator': 'FormItem',
171 |           'x-component': 'DatePicker',
172 |         },
173 |         input: {
174 |           type: 'string',
175 |           title: '输入框',
176 |           'x-decorator': 'FormItem',
177 |           'x-component': 'Input',
178 |         },
179 |       },
180 |     },
181 |   },
182 | }
183 | 
184 | export default () => (
185 |   <FormProvider form={form}>
186 |     <SchemaField schema={schema} />
187 |     <FormButtonGroup>
188 |       <Submit onSubmit={console.log}>提交</Submit>
189 |     </FormButtonGroup>
190 |   </FormProvider>
191 | )
192 | ```
193 | 
194 | ## 纯 JSX 案例
195 | 
196 | ```tsx
197 | import React from 'react'
198 | import {
199 |   Input,
200 |   DatePicker,
201 |   Editable,
202 |   FormItem,
203 |   FormButtonGroup,
204 |   Submit,
205 | } from '@formily/antd'
206 | import { createForm } from '@formily/core'
207 | import { FormProvider, Field, VoidField, ObjectField } from '@formily/react'
208 | 
209 | const form = createForm()
210 | 
211 | export default () => (
212 |   <FormProvider form={form}>
213 |     <Field
214 |       name="date"
215 |       title="日期"
216 |       decorator={[Editable]}
217 |       component={[DatePicker]}
218 |     />
219 |     <Field
220 |       name="input"
221 |       title="输入框"
222 |       decorator={[Editable]}
223 |       component={[Input]}
224 |     />
225 |     <VoidField
226 |       name="void"
227 |       title="虚拟节点容器"
228 |       reactions={(field) => {
229 |         field.title = field.query('.void.date2').get('value') || field.title
230 |       }}
231 |       component={[Editable.Popover]}
232 |     >
233 |       <Field
234 |         name="date2"
235 |         title="日期"
236 |         decorator={[FormItem]}
237 |         component={[DatePicker]}
238 |       />
239 |       <Field
240 |         name="input2"
241 |         title="输入框"
242 |         decorator={[FormItem]}
243 |         component={[Input]}
244 |       />
245 |     </VoidField>
246 |     <ObjectField
247 |       name="iobject"
248 |       title="对象节点容器"
249 |       reactions={(field) => {
250 |         field.title = field.value?.date || field.title
251 |       }}
252 |       component={[Editable.Popover]}
253 |     >
254 |       <Field
255 |         name="date"
256 |         title="日期"
257 |         decorator={[FormItem]}
258 |         component={[DatePicker]}
259 |       />
260 |       <Field
261 |         name="input"
262 |         title="输入框"
263 |         decorator={[FormItem]}
264 |         component={[Input]}
265 |       />
266 |     </ObjectField>
267 | 
268 |     <FormButtonGroup>
269 |       <Submit onSubmit={console.log}>提交</Submit>
270 |     </FormButtonGroup>
271 |   </FormProvider>
272 | )
273 | ```
274 | 
275 | ## API
276 | 
277 | ### Editable
278 | 
279 | > 内联编辑
280 | 
281 | 参考 https://ant.design/components/form-cn/ 中的 FormItem 属性
282 | 
283 | ### Editable.Popover
284 | 
285 | > 浮层编辑
286 | 
287 | 参考 https://ant.design/components/popover-cn/
288 | 
```

--------------------------------------------------------------------------------
/packages/react/src/__tests__/schema.json.spec.tsx:
--------------------------------------------------------------------------------

```typescript
  1 | import React from 'react'
  2 | import { createForm } from '@formily/core'
  3 | import { FormProvider, createSchemaField } from '../index'
  4 | import { Schema } from '@formily/json-schema'
  5 | import { render } from '@testing-library/react'
  6 | 
  7 | const Input = ({ value, onChange }) => {
  8 |   return <input data-testid="input" value={value || ''} onChange={onChange} />
  9 | }
 10 | 
 11 | import { Button, Rate } from 'antd'
 12 | import { SearchOutlined, DollarOutlined } from '@ant-design/icons'
 13 | 
 14 | describe('json schema field', () => {
 15 |   test('string field', () => {
 16 |     const form = createForm()
 17 |     const SchemaField = createSchemaField({
 18 |       components: {
 19 |         Input,
 20 |       },
 21 |     })
 22 |     const { queryByTestId } = render(
 23 |       <FormProvider form={form}>
 24 |         <SchemaField
 25 |           name="string"
 26 |           schema={
 27 |             new Schema({
 28 |               type: 'string',
 29 |               default: '123',
 30 |               'x-component': 'Input',
 31 |             })
 32 |           }
 33 |         />
 34 |       </FormProvider>
 35 |     )
 36 |     expect(queryByTestId('input')).toBeVisible()
 37 |     expect(queryByTestId('input')?.getAttribute('value')).toEqual('123')
 38 |   })
 39 |   test('object field', () => {
 40 |     const form = createForm()
 41 |     const SchemaField = createSchemaField({
 42 |       components: {
 43 |         Input,
 44 |       },
 45 |     })
 46 |     const { queryByTestId } = render(
 47 |       <FormProvider form={form}>
 48 |         <SchemaField
 49 |           name="object"
 50 |           schema={{
 51 |             type: 'object',
 52 |             properties: {
 53 |               string: {
 54 |                 type: 'string',
 55 |                 'x-component': 'Input',
 56 |               },
 57 |             },
 58 |           }}
 59 |         />
 60 |       </FormProvider>
 61 |     )
 62 |     expect(queryByTestId('input')).toBeVisible()
 63 |   })
 64 |   test('x-component-props children', () => {
 65 |     const form = createForm()
 66 |     const Text: React.FC = ({ children }) => {
 67 |       return <div data-testid="children-test">{children}</div>
 68 |     }
 69 |     const SchemaField = createSchemaField({
 70 |       components: {
 71 |         Text,
 72 |       },
 73 |     })
 74 |     const { queryByTestId } = render(
 75 |       <FormProvider form={form}>
 76 |         <SchemaField
 77 |           name="object"
 78 |           schema={{
 79 |             type: 'object',
 80 |             properties: {
 81 |               string: {
 82 |                 type: 'string',
 83 |                 'x-component': 'Text',
 84 |                 'x-component-props': {
 85 |                   children: 'children',
 86 |                 },
 87 |               },
 88 |             },
 89 |           }}
 90 |         />
 91 |       </FormProvider>
 92 |     )
 93 |     expect(queryByTestId('children-test')).toBeVisible()
 94 |     expect(queryByTestId('children-test')?.innerHTML).toEqual('children')
 95 |   })
 96 |   test('x-content', async () => {
 97 |     const form = createForm()
 98 |     const Text: React.FC = ({ children }) => {
 99 |       return <div data-testid="content-test">{children}</div>
100 |     }
101 |     const SchemaField = createSchemaField({
102 |       components: {
103 |         Text,
104 |       },
105 |     })
106 |     const { queryByTestId } = render(
107 |       <FormProvider form={form}>
108 |         <SchemaField
109 |           name="object"
110 |           schema={{
111 |             type: 'object',
112 |             properties: {
113 |               string: {
114 |                 type: 'string',
115 |                 'x-component': 'Text',
116 |                 'x-content': 'content',
117 |               },
118 |             },
119 |           }}
120 |         />
121 |       </FormProvider>
122 |     )
123 |     expect(queryByTestId('content-test')).toBeVisible()
124 |     expect(queryByTestId('content-test')?.innerHTML).toEqual('content')
125 |   })
126 |   test('x-slot-node', () => {
127 |     const form = createForm()
128 |     const SchemaField = createSchemaField({
129 |       components: {
130 |         SearchOutlined,
131 |         Button,
132 |       },
133 |     })
134 |     const { queryByTestId } = render(
135 |       <FormProvider form={form}>
136 |         <SchemaField
137 |           name="object"
138 |           schema={{
139 |             type: 'object',
140 |             properties: {
141 |               icon: {
142 |                 'x-slot-node': {
143 |                   target: 'button.x-component-props.icon',
144 |                 },
145 |                 'x-component': 'SearchOutlined',
146 |                 'x-component-props': {
147 |                   'data-testid': 'icon',
148 |                 },
149 |               },
150 |               button: {
151 |                 type: 'string',
152 |                 'x-component': 'Button',
153 |                 'x-component-props': {
154 |                   'data-testid': 'button',
155 |                 },
156 |               },
157 |             },
158 |           }}
159 |         />
160 |       </FormProvider>
161 |     )
162 |     const button = queryByTestId('button')
163 |     const icon = queryByTestId('icon')
164 | 
165 |     expect(button).toContainElement(icon)
166 |   })
167 |   test('x-slot-node render prop', async () => {
168 |     const form = createForm()
169 |     const SchemaField = createSchemaField({
170 |       components: {
171 |         Rate,
172 |         DollarOutlined,
173 |       },
174 |     })
175 |     const { queryByRole, queryAllByTestId } = render(
176 |       <FormProvider form={form}>
177 |         <SchemaField
178 |           name="object"
179 |           schema={{
180 |             type: 'object',
181 |             properties: {
182 |               icon: {
183 |                 'x-slot-node': {
184 |                   target: 'rate.x-component-props.character',
185 |                   isRenderProp: true,
186 |                 },
187 |                 'x-component': 'DollarOutlined',
188 |                 'x-component-props': {
189 |                   'data-testid': 'icon',
190 |                   rotate: '{{$slotArgs[0].value * 45}}',
191 |                   style: {
192 |                     fontSize: '{{`${$slotArgs[0].value * 10}px`}}',
193 |                   },
194 |                 },
195 |               },
196 |               rate: {
197 |                 'x-component': 'Rate',
198 |                 'x-component-props': {
199 |                   defaultValue: 2,
200 |                 },
201 |               },
202 |             },
203 |           }}
204 |         />
205 |       </FormProvider>
206 |     )
207 | 
208 |     const rate = queryByRole('radiogroup')
209 |     expect(rate).toBeVisible()
210 |     const icons = queryAllByTestId('icon')
211 |     expect(icons).toHaveLength(10)
212 |     icons.forEach((icon) => {
213 |       expect(rate).toContainElement(icon)
214 |     })
215 | 
216 |     const style = window.getComputedStyle(icons[0])
217 |     const fontSize = style.fontSize
218 |     expect(fontSize).toBe('20px')
219 |   })
220 | })
221 | 
```

--------------------------------------------------------------------------------
/packages/antd/src/form-dialog/index.tsx:
--------------------------------------------------------------------------------

```typescript
  1 | import React, { Fragment, useRef, useLayoutEffect, useState } from 'react'
  2 | import { createPortal } from 'react-dom'
  3 | import { createForm, IFormProps, Form } from '@formily/core'
  4 | import { toJS } from '@formily/reactive'
  5 | import { FormProvider, Observer, observer, ReactFC } from '@formily/react'
  6 | import {
  7 |   isNum,
  8 |   isStr,
  9 |   isBool,
 10 |   isFn,
 11 |   applyMiddleware,
 12 |   IMiddleware,
 13 | } from '@formily/shared'
 14 | import { Modal, ModalProps } from 'antd'
 15 | import {
 16 |   usePrefixCls,
 17 |   loading,
 18 |   createPortalProvider,
 19 |   createPortalRoot,
 20 | } from '../__builtins__'
 21 | 
 22 | type FormDialogRenderer =
 23 |   | React.ReactElement
 24 |   | ((form: Form) => React.ReactElement)
 25 | 
 26 | type ModalTitle = string | number | React.ReactElement
 27 | 
 28 | const isModalTitle = (props: any): props is ModalTitle => {
 29 |   return (
 30 |     isNum(props) || isStr(props) || isBool(props) || React.isValidElement(props)
 31 |   )
 32 | }
 33 | 
 34 | const getModelProps = (props: any): IModalProps => {
 35 |   if (isModalTitle(props)) {
 36 |     return {
 37 |       title: props,
 38 |     }
 39 |   } else {
 40 |     return props
 41 |   }
 42 | }
 43 | 
 44 | export interface IFormDialog {
 45 |   forOpen(middleware: IMiddleware<IFormProps>): IFormDialog
 46 |   forConfirm(middleware: IMiddleware<Form>): IFormDialog
 47 |   forCancel(middleware: IMiddleware<Form>): IFormDialog
 48 |   open(props?: IFormProps): Promise<any>
 49 |   close(): void
 50 | }
 51 | 
 52 | export interface IModalProps extends ModalProps {
 53 |   onOk?: (event: React.MouseEvent<HTMLElement>) => void | boolean
 54 |   onCancel?: (event: React.MouseEvent<HTMLElement>) => void | boolean
 55 |   loadingText?: React.ReactNode
 56 | }
 57 | 
 58 | export function FormDialog(
 59 |   title: IModalProps,
 60 |   id: string,
 61 |   renderer: FormDialogRenderer
 62 | ): IFormDialog
 63 | export function FormDialog(
 64 |   title: IModalProps,
 65 |   renderer: FormDialogRenderer
 66 | ): IFormDialog
 67 | export function FormDialog(
 68 |   title: ModalTitle,
 69 |   id: string,
 70 |   renderer: FormDialogRenderer
 71 | ): IFormDialog
 72 | export function FormDialog(
 73 |   title: ModalTitle,
 74 |   renderer: FormDialogRenderer
 75 | ): IFormDialog
 76 | export function FormDialog(title: any, id: any, renderer?: any): IFormDialog {
 77 |   if (isFn(id) || React.isValidElement(id)) {
 78 |     renderer = id
 79 |     id = 'form-dialog'
 80 |   }
 81 |   const env = {
 82 |     host: document.createElement('div'),
 83 |     form: null,
 84 |     promise: null,
 85 |     openMiddlewares: [],
 86 |     confirmMiddlewares: [],
 87 |     cancelMiddlewares: [],
 88 |   }
 89 |   const root = createPortalRoot(env.host, id)
 90 |   const props = getModelProps(title)
 91 |   const modal = {
 92 |     ...props,
 93 |     afterClose: () => {
 94 |       props?.afterClose?.()
 95 |       root.unmount()
 96 |     },
 97 |   }
 98 |   const DialogContent = observer(() => {
 99 |     return <Fragment>{isFn(renderer) ? renderer(env.form) : renderer}</Fragment>
100 |   })
101 |   const renderDialog = (
102 |     visible = true,
103 |     resolve?: () => any,
104 |     reject?: () => any
105 |   ) => {
106 |     return (
107 |       <Observer>
108 |         {() => (
109 |           <Modal
110 |             {...modal}
111 |             visible={visible}
112 |             confirmLoading={env.form.submitting}
113 |             onCancel={(e) => {
114 |               if (modal?.onCancel?.(e) !== false) {
115 |                 reject()
116 |               }
117 |             }}
118 |             onOk={async (e) => {
119 |               if (modal?.onOk?.(e) !== false) {
120 |                 resolve()
121 |               }
122 |             }}
123 |           >
124 |             <FormProvider form={env.form}>
125 |               <DialogContent />
126 |             </FormProvider>
127 |           </Modal>
128 |         )}
129 |       </Observer>
130 |     )
131 |   }
132 | 
133 |   document.body.appendChild(env.host)
134 |   const formDialog = {
135 |     forOpen: (middleware: IMiddleware<IFormProps>) => {
136 |       if (isFn(middleware)) {
137 |         env.openMiddlewares.push(middleware)
138 |       }
139 |       return formDialog
140 |     },
141 |     forConfirm: (middleware: IMiddleware<Form>) => {
142 |       if (isFn(middleware)) {
143 |         env.confirmMiddlewares.push(middleware)
144 |       }
145 |       return formDialog
146 |     },
147 |     forCancel: (middleware: IMiddleware<Form>) => {
148 |       if (isFn(middleware)) {
149 |         env.cancelMiddlewares.push(middleware)
150 |       }
151 |       return formDialog
152 |     },
153 |     open: async (props: IFormProps) => {
154 |       if (env.promise) return env.promise
155 |       env.promise = new Promise(async (resolve, reject) => {
156 |         try {
157 |           props = await loading(modal.loadingText, () =>
158 |             applyMiddleware(props, env.openMiddlewares)
159 |           )
160 |           env.form = env.form || createForm(props)
161 |         } catch (e) {
162 |           reject(e)
163 |         }
164 |         root.render(() =>
165 |           renderDialog(
166 |             true,
167 |             () => {
168 |               env.form
169 |                 .submit(async () => {
170 |                   await applyMiddleware(env.form, env.confirmMiddlewares)
171 |                   resolve(toJS(env.form.values))
172 |                   formDialog.close()
173 |                 })
174 |                 .catch(() => {})
175 |             },
176 |             async () => {
177 |               await loading(modal.loadingText, () =>
178 |                 applyMiddleware(env.form, env.cancelMiddlewares)
179 |               )
180 |               formDialog.close()
181 |             }
182 |           )
183 |         )
184 |       })
185 |       return env.promise
186 |     },
187 |     close: () => {
188 |       if (!env.host) return
189 |       root.render(() => renderDialog(false))
190 |     },
191 |   }
192 |   return formDialog
193 | }
194 | 
195 | const DialogFooter: ReactFC = (props) => {
196 |   const ref = useRef<HTMLDivElement>()
197 |   const [footer, setFooter] = useState<HTMLDivElement>()
198 |   const footerRef = useRef<HTMLDivElement>()
199 |   const prefixCls = usePrefixCls('modal')
200 |   useLayoutEffect(() => {
201 |     const content = ref.current?.closest(`.${prefixCls}-content`)
202 |     if (content) {
203 |       if (!footerRef.current) {
204 |         footerRef.current = content.querySelector(`.${prefixCls}-footer`)
205 |         if (!footerRef.current) {
206 |           footerRef.current = document.createElement('div')
207 |           footerRef.current.classList.add(`${prefixCls}-footer`)
208 |           content.appendChild(footerRef.current)
209 |         }
210 |       }
211 |       setFooter(footerRef.current)
212 |     }
213 |   })
214 | 
215 |   footerRef.current = footer
216 | 
217 |   return (
218 |     <div ref={ref} style={{ display: 'none' }}>
219 |       {footer && createPortal(props.children, footer)}
220 |     </div>
221 |   )
222 | }
223 | 
224 | FormDialog.Footer = DialogFooter
225 | 
226 | FormDialog.Portal = createPortalProvider('form-dialog')
227 | 
228 | export default FormDialog
229 | 
```

--------------------------------------------------------------------------------
/packages/antd/src/form-drawer/index.tsx:
--------------------------------------------------------------------------------

```typescript
  1 | import React, { Fragment, useLayoutEffect, useRef, useState } from 'react'
  2 | import { createPortal } from 'react-dom'
  3 | import {
  4 |   createForm,
  5 |   IFormProps,
  6 |   Form,
  7 |   onFormSubmitSuccess,
  8 | } from '@formily/core'
  9 | import { toJS } from '@formily/reactive'
 10 | import { FormProvider, observer, ReactFC } from '@formily/react'
 11 | import {
 12 |   isNum,
 13 |   isStr,
 14 |   isBool,
 15 |   isFn,
 16 |   applyMiddleware,
 17 |   IMiddleware,
 18 | } from '@formily/shared'
 19 | import { Drawer, DrawerProps } from 'antd'
 20 | import {
 21 |   usePrefixCls,
 22 |   createPortalProvider,
 23 |   createPortalRoot,
 24 |   loading,
 25 | } from '../__builtins__'
 26 | 
 27 | type FormDrawerRenderer =
 28 |   | React.ReactElement
 29 |   | ((form: Form) => React.ReactElement)
 30 | 
 31 | type DrawerTitle = string | number | React.ReactElement
 32 | 
 33 | type EventType =
 34 |   | React.KeyboardEvent<HTMLDivElement>
 35 |   | React.MouseEvent<HTMLDivElement | HTMLButtonElement>
 36 | 
 37 | const isDrawerTitle = (props: any): props is DrawerTitle => {
 38 |   return (
 39 |     isNum(props) || isStr(props) || isBool(props) || React.isValidElement(props)
 40 |   )
 41 | }
 42 | 
 43 | const getDrawerProps = (props: any): IDrawerProps => {
 44 |   if (isDrawerTitle(props)) {
 45 |     return {
 46 |       title: props,
 47 |     }
 48 |   } else {
 49 |     return props
 50 |   }
 51 | }
 52 | 
 53 | export interface IFormDrawer {
 54 |   forOpen(middleware: IMiddleware<IFormProps>): IFormDrawer
 55 |   open(props?: IFormProps): Promise<any>
 56 |   close(): void
 57 | }
 58 | 
 59 | export interface IDrawerProps extends DrawerProps {
 60 |   onClose?: (e: EventType) => void | boolean
 61 |   loadingText?: React.ReactNode
 62 | }
 63 | 
 64 | export function FormDrawer(
 65 |   title: IDrawerProps,
 66 |   id: string,
 67 |   renderer: FormDrawerRenderer
 68 | ): IFormDrawer
 69 | export function FormDrawer(
 70 |   title: IDrawerProps,
 71 |   id: FormDrawerRenderer
 72 | ): IFormDrawer
 73 | export function FormDrawer(
 74 |   title: DrawerTitle,
 75 |   id: string,
 76 |   renderer: FormDrawerRenderer
 77 | ): IFormDrawer
 78 | export function FormDrawer(
 79 |   title: DrawerTitle,
 80 |   id: FormDrawerRenderer
 81 | ): IFormDrawer
 82 | export function FormDrawer(title: any, id: any, renderer?: any): IFormDrawer {
 83 |   if (isFn(id) || React.isValidElement(id)) {
 84 |     renderer = id
 85 |     id = 'form-drawer'
 86 |   }
 87 |   const env = {
 88 |     host: document.createElement('div'),
 89 |     openMiddlewares: [],
 90 |     form: null,
 91 |     promise: null,
 92 |   }
 93 |   const root = createPortalRoot(env.host, id)
 94 |   const props = getDrawerProps(title)
 95 |   const drawer = {
 96 |     width: '40%',
 97 |     ...props,
 98 |     onClose: (e: any) => {
 99 |       if (props?.onClose?.(e) !== false) {
100 |         formDrawer.close()
101 |       }
102 |     },
103 |     afterVisibleChange: (visible: boolean) => {
104 |       props?.afterVisibleChange?.(visible)
105 |       if (visible) return
106 |       root.unmount()
107 |     },
108 |   }
109 |   const DrawerContent = observer(() => {
110 |     return <Fragment>{isFn(renderer) ? renderer(env.form) : renderer}</Fragment>
111 |   })
112 |   const renderDrawer = (visible = true) => {
113 |     return (
114 |       <Drawer {...drawer} visible={visible}>
115 |         <FormProvider form={env.form}>
116 |           <DrawerContent />
117 |         </FormProvider>
118 |       </Drawer>
119 |     )
120 |   }
121 | 
122 |   document.body.appendChild(env.host)
123 |   const formDrawer = {
124 |     forOpen: (middleware: IMiddleware<IFormProps>) => {
125 |       if (isFn(middleware)) {
126 |         env.openMiddlewares.push(middleware)
127 |       }
128 |       return formDrawer
129 |     },
130 |     open: (props: IFormProps) => {
131 |       if (env.promise) return env.promise
132 |       env.promise = new Promise(async (resolve, reject) => {
133 |         try {
134 |           props = await loading(drawer.loadingText, () =>
135 |             applyMiddleware(props, env.openMiddlewares)
136 |           )
137 |           env.form =
138 |             env.form ||
139 |             createForm({
140 |               ...props,
141 |               effects(form) {
142 |                 onFormSubmitSuccess(() => {
143 |                   resolve(toJS(form.values))
144 |                   formDrawer.close()
145 |                 })
146 |                 props?.effects?.(form)
147 |               },
148 |             })
149 |         } catch (e) {
150 |           reject(e)
151 |         }
152 |         root.render(() => renderDrawer(false))
153 |         setTimeout(() => {
154 |           root.render(() => renderDrawer(true))
155 |         }, 16)
156 |       })
157 |       return env.promise
158 |     },
159 |     close: () => {
160 |       if (!env.host) return
161 |       root.render(() => renderDrawer(false))
162 |     },
163 |   }
164 |   return formDrawer
165 | }
166 | 
167 | const DrawerExtra: ReactFC = (props) => {
168 |   const ref = useRef<HTMLDivElement>()
169 |   const [extra, setExtra] = useState<HTMLDivElement>()
170 |   const extraRef = useRef<HTMLDivElement>()
171 |   const prefixCls = usePrefixCls('drawer')
172 |   useLayoutEffect(() => {
173 |     const content = ref.current
174 |       ?.closest(`.${prefixCls}-wrapper-body`)
175 |       ?.querySelector(`.${prefixCls}-header`)
176 |     if (content) {
177 |       if (!extraRef.current) {
178 |         extraRef.current = content.querySelector(`.${prefixCls}-extra`)
179 |         if (!extraRef.current) {
180 |           extraRef.current = document.createElement('div')
181 |           extraRef.current.classList.add(`${prefixCls}-extra`)
182 |           content.appendChild(extraRef.current)
183 |         }
184 |       }
185 |       setExtra(extraRef.current)
186 |     }
187 |   })
188 | 
189 |   extraRef.current = extra
190 | 
191 |   return (
192 |     <div ref={ref} style={{ display: 'none' }}>
193 |       {extra && createPortal(props.children, extra)}
194 |     </div>
195 |   )
196 | }
197 | 
198 | const DrawerFooter: ReactFC = (props) => {
199 |   const ref = useRef<HTMLDivElement>()
200 |   const [footer, setFooter] = useState<HTMLDivElement>()
201 |   const footerRef = useRef<HTMLDivElement>()
202 |   const prefixCls = usePrefixCls('drawer')
203 |   useLayoutEffect(() => {
204 |     const content = ref.current?.closest(`.${prefixCls}-wrapper-body`)
205 |     if (content) {
206 |       if (!footerRef.current) {
207 |         footerRef.current = content.querySelector(`.${prefixCls}-footer`)
208 |         if (!footerRef.current) {
209 |           footerRef.current = document.createElement('div')
210 |           footerRef.current.classList.add(`${prefixCls}-footer`)
211 |           content.appendChild(footerRef.current)
212 |         }
213 |       }
214 |       setFooter(footerRef.current)
215 |     }
216 |   })
217 | 
218 |   footerRef.current = footer
219 | 
220 |   return (
221 |     <div ref={ref} style={{ display: 'none' }}>
222 |       {footer && createPortal(props.children, footer)}
223 |     </div>
224 |   )
225 | }
226 | 
227 | FormDrawer.Extra = DrawerExtra
228 | 
229 | FormDrawer.Footer = DrawerFooter
230 | 
231 | FormDrawer.Portal = createPortalProvider('form-drawer')
232 | 
233 | export default FormDrawer
234 | 
```

--------------------------------------------------------------------------------
/docs/guide/advanced/destructor.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Compatible solution for front-end and back-end data differences
  2 | 
  3 | Many times, we always encounter scenarios where the front-end data structure does not match the back-end data structure. The seemingly simple problem is actually very uncomfortable to solve. The most common problems are:
  4 | 
  5 | The output of the front-end date range component is an array structure, but the format required by the back-end is to split a flat data structure. This problem is largely limited by the back-end domain model. Because from the perspective of back-end model design, splitting the flat structure is the best solution;
  6 | 
  7 | But from the perspective of front-end componentization, the array structure is the best;
  8 | 
  9 | So each side has its truth, but unfortunately, it can only cancel such an unequal treaty at the front end every time. However, with Formily, you don’t need to feel uncomfortable for such an embarrassing situation. **Formily provides the ability to deconstruct the path, which can help users quickly solve such problems.** Let's take a look at an example
 10 | 
 11 | ## Markup Schema Case
 12 | 
 13 | ```tsx
 14 | import React from 'react'
 15 | import {
 16 |   Form,
 17 |   FormItem,
 18 |   DatePicker,
 19 |   FormButtonGroup,
 20 |   Radio,
 21 |   Submit,
 22 | } from '@formily/antd'
 23 | import { createForm, onFieldValueChange } from '@formily/core'
 24 | import { createSchemaField, FormConsumer } from '@formily/react'
 25 | 
 26 | const SchemaField = createSchemaField({
 27 |   components: {
 28 |     FormItem,
 29 |     DatePicker,
 30 |     Radio,
 31 |   },
 32 | })
 33 | 
 34 | const form = createForm({
 35 |   effects() {
 36 |     onFieldValueChange('visible_destructor', (field) => {
 37 |       form.setFieldState('[startDate,endDate]', (state) => {
 38 |         state.visible = !!field.value
 39 |       })
 40 |     })
 41 |   },
 42 | })
 43 | 
 44 | export default () => {
 45 |   return (
 46 |     <Form form={form} layout="vertical">
 47 |       <SchemaField>
 48 |         <SchemaField.Boolean
 49 |           name="visible_destructor"
 50 |           title="Whether to display deconstructed fields"
 51 |           default={true}
 52 |           enum={[
 53 |             { label: 'yes', value: true },
 54 |             { label: 'no', value: false },
 55 |           ]}
 56 |           x-decorator="FormItem"
 57 |           x-component="Radio.Group"
 58 |         />
 59 |         <SchemaField.String
 60 |           name="undestructor"
 61 |           title="before deconstruction"
 62 |           x-decorator="FormItem"
 63 |           x-component="DatePicker.RangePicker"
 64 |         />
 65 |         <SchemaField.String
 66 |           name="[startDate,endDate]"
 67 |           title="after deconstruction"
 68 |           default={['2020-11-20', '2021-12-30']}
 69 |           x-decorator="FormItem"
 70 |           x-component="DatePicker.RangePicker"
 71 |         />
 72 |       </SchemaField>
 73 |       <code>
 74 |         <pre>
 75 |           <FormConsumer>
 76 |             {(form) => JSON.stringify(form.values, null, 2)}
 77 |           </FormConsumer>
 78 |         </pre>
 79 |       </code>
 80 |       <FormButtonGroup>
 81 |         <Submit onSubmit={console.log}>submit</Submit>
 82 |       </FormButtonGroup>
 83 |     </Form>
 84 |   )
 85 | }
 86 | ```
 87 | 
 88 | ## JSON Schema Cases
 89 | 
 90 | ```tsx
 91 | import React from 'react'
 92 | import {
 93 |   Form,
 94 |   FormItem,
 95 |   DatePicker,
 96 |   FormButtonGroup,
 97 |   Radio,
 98 |   Submit,
 99 | } from '@formily/antd'
100 | import { createForm } from '@formily/core'
101 | import { createSchemaField, FormConsumer } from '@formily/react'
102 | 
103 | const SchemaField = createSchemaField({
104 |   components: {
105 |     FormItem,
106 |     DatePicker,
107 |     Radio,
108 |   },
109 | })
110 | 
111 | const form = createForm()
112 | 
113 | const schema = {
114 |   type: 'object',
115 |   properties: {
116 |     visible_destructor: {
117 |       type: 'boolean',
118 |       title: 'Whether to display deconstructed fields',
119 |       default: true,
120 |       enum: [
121 |         { label: 'yes', value: true },
122 |         { label: 'no', value: false },
123 |       ],
124 |       'x-decorator': 'FormItem',
125 |       'x-component': 'Radio.Group',
126 |     },
127 |     undestructor: {
128 |       type: 'string',
129 |       title: 'before deconstruction',
130 |       'x-decorator': 'FormItem',
131 |       'x-component': 'DatePicker.RangePicker',
132 |     },
133 |     '[startDate,endDate]': {
134 |       type: 'string',
135 |       title: 'after deconstruction',
136 |       default: ['2020-11-20', '2021-12-30'],
137 |       'x-decorator': 'FormItem',
138 |       'x-component': 'DatePicker.RangePicker',
139 |       'x-reactions': {
140 |         dependencies: ['visible_destructor'],
141 |         fulfill: {
142 |           state: {
143 |             visible: '{{!!$deps[0]}}',
144 |           },
145 |         },
146 |       },
147 |     },
148 |   },
149 | }
150 | 
151 | export default () => {
152 |   return (
153 |     <Form form={form} layout="vertical">
154 |       <SchemaField schema={schema} />
155 |       <code>
156 |         <pre>
157 |           <FormConsumer>
158 |             {(form) => JSON.stringify(form.values, null, 2)}
159 |           </FormConsumer>
160 |         </pre>
161 |       </code>
162 |       <FormButtonGroup>
163 |         <Submit onSubmit={console.log}>submit</Submit>
164 |       </FormButtonGroup>
165 |     </Form>
166 |   )
167 | }
168 | ```
169 | 
170 | ## Pure JSX Case
171 | 
172 | ```tsx
173 | import React from 'react'
174 | import {
175 |   Form,
176 |   FormItem,
177 |   DatePicker,
178 |   FormButtonGroup,
179 |   Radio,
180 |   Submit,
181 | } from '@formily/antd'
182 | import { createForm } from '@formily/core'
183 | import { Field, FormConsumer } from '@formily/react'
184 | 
185 | const form = createForm()
186 | 
187 | export default () => {
188 |   return (
189 |     <Form form={form} layout="vertical">
190 |       <Field
191 |         name="visible_destructor"
192 |         title="Whether to display deconstructed fields"
193 |         initialValue={true}
194 |         dataSource={[
195 |           { label: 'yes', value: true },
196 |           { label: 'no', value: false },
197 |         ]}
198 |         decorator={[FormItem]}
199 |         component={[Radio.Group]}
200 |       />
201 |       <Field
202 |         name="undestructor"
203 |         title="before deconstruction"
204 |         decorator={[FormItem]}
205 |         component={[DatePicker.RangePicker]}
206 |       />
207 |       <Field
208 |         name="[startDate,endDate]"
209 |         title="after deconstruction"
210 |         initialValue={['2020-11-20', '2021-12-30']}
211 |         decorator={[FormItem]}
212 |         component={[DatePicker.RangePicker]}
213 |         reactions={(field) => {
214 |           field.visible = !!field.query('visible_destructor').value()
215 |         }}
216 |       />
217 |       <code>
218 |         <pre>
219 |           <FormConsumer>
220 |             {(form) => JSON.stringify(form.values, null, 2)}
221 |           </FormConsumer>
222 |         </pre>
223 |       </code>
224 |       <FormButtonGroup>
225 |         <Submit onSubmit={console.log}>submit</Submit>
226 |       </FormButtonGroup>
227 |     </Form>
228 |   )
229 | }
230 | ```
231 | 
```

--------------------------------------------------------------------------------
/packages/vue/docs/.vuepress/components/dumi-previewer.vue:
--------------------------------------------------------------------------------

```vue
  1 | <template>
  2 |   <client-only>
  3 |     <section class="dumi-previewer">
  4 |       <div class="dumi-previewer-demo">
  5 |         <template v-if="demoPath && demo">
  6 |           <component :is="demo" />
  7 |         </template>
  8 | 
  9 |         <template v-else>
 10 |           <slot name="demo"></slot>
 11 |         </template>
 12 |       </div>
 13 | 
 14 |       <div class="dumi-previewer-actions">
 15 |         <div>
 16 |           <svg
 17 |             xmlns="http://www.w3.org/2000/svg"
 18 |             xmlns:xlink="http://www.w3.org/1999/xlink"
 19 |             class="dumi-previewer-actions__icon"
 20 |             viewBox="0 0 256 296"
 21 |             @click="openCodeSandBox"
 22 |           >
 23 |             <path
 24 |               d="M115.498 261.088v-106.61L23.814 101.73v60.773l41.996 24.347v45.7l49.688 28.54zm23.814.627l50.605-29.151V185.78l42.269-24.495v-60.011l-92.874 53.621v106.82zm80.66-180.887l-48.817-28.289l-42.863 24.872l-43.188-24.897l-49.252 28.667l91.914 52.882l92.206-53.235zM0 222.212V74.495L127.987 0L256 74.182v147.797l-128.016 73.744L0 222.212z"
 25 |               fill="#000"
 26 |             ></path>
 27 |           </svg>
 28 |         </div>
 29 | 
 30 |         <div>
 31 |           <svg
 32 |             v-if="copied"
 33 |             class="dumi-previewer-actions__icon"
 34 |             style="fill: green"
 35 |             xmlns="http://www.w3.org/2000/svg"
 36 |             viewBox="0 0 24 24"
 37 |             width="24"
 38 |             height="24"
 39 |           >
 40 |             <path fill="none" d="M0 0h24v24H0z" />
 41 |             <path
 42 |               d="M10 15.172l9.192-9.193 1.415 1.414L10 18l-6.364-6.364 1.414-1.414z"
 43 |             />
 44 |           </svg>
 45 | 
 46 |           <svg
 47 |             v-else
 48 |             class="dumi-previewer-actions__icon"
 49 |             xmlns="http://www.w3.org/2000/svg"
 50 |             viewBox="0 0 24 24"
 51 |             width="24"
 52 |             height="24"
 53 |             @click="handleCopy"
 54 |           >
 55 |             <path fill="none" d="M0 0h24v24H0z" />
 56 |             <path
 57 |               d="M7 6V3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1h-3v3c0 .552-.45 1-1.007 1H4.007A1.001 1.001 0 0 1 3 21l.003-14c0-.552.45-1 1.007-1H7zM5.003 8L5 20h10V8H5.003zM9 6h8v10h2V4H9v2z"
 58 |             />
 59 |           </svg>
 60 | 
 61 |           <svg
 62 |             class="dumi-previewer-actions__icon"
 63 |             xmlns="http://www.w3.org/2000/svg"
 64 |             viewBox="0 0 24 24"
 65 |             width="24"
 66 |             height="24"
 67 |             @click="handleCollapse"
 68 |           >
 69 |             <path fill="none" d="M0 0h24v24H0z" />
 70 |             <path
 71 |               d="M24 12l-5.657 5.657-1.414-1.414L21.172 12l-4.243-4.243 1.414-1.414L24 12zM2.828 12l4.243 4.243-1.414 1.414L0 12l5.657-5.657L7.07 7.757 2.828 12zm6.96 9H7.66l6.552-18h2.128L9.788 21z"
 72 |             />
 73 |           </svg>
 74 |         </div>
 75 |       </div>
 76 | 
 77 |       <div v-show="!collapsed" class="dumi-previewer-source">
 78 |         <div v-html="highlightCode" class="language-vue extra-class" />
 79 |       </div>
 80 |     </section>
 81 |   </client-only>
 82 | </template>
 83 | 
 84 | <script>
 85 | import copy from 'copy-to-clipboard'
 86 | import highlight from './highlight'
 87 | import { createCodeSandBox } from './createCodeSandBox'
 88 | 
 89 | export default {
 90 |   name: 'dumi-previewer',
 91 | 
 92 |   props: {
 93 |     code: {
 94 |       type: String,
 95 |       default: '',
 96 |     },
 97 | 
 98 |     demoPath: {
 99 |       type: String,
100 |       default: '',
101 |     },
102 |   },
103 | 
104 |   data() {
105 |     return {
106 |       collapsed: false,
107 |       copied: false,
108 |       timerId: null,
109 |       demoStr: '',
110 |       /**
111 |        * take over VuePress render
112 |        * 接管VuePress渲染
113 |        */
114 |       demo: null,
115 |     }
116 |   },
117 | 
118 |   computed: {
119 |     decodedCode() {
120 |       return decodeURIComponent(this.code || this.demoStr)
121 |     },
122 | 
123 |     highlightCode() {
124 |       return highlight(this.decodedCode, 'vue')
125 |     },
126 |   },
127 | 
128 |   created() {
129 |     if (this.demoPath) {
130 |       import(
131 |         /* webpackPrefetch: true */ `../../demos/${this.demoPath}.vue`
132 |       ).then((module) => {
133 |         this.demo = module.default
134 |       })
135 |       import(
136 |         /* webpackPrefetch: true */ `!raw-loader!../../demos/${this.demoPath}.vue`
137 |       ).then((module) => {
138 |         this.demoStr = module.default
139 |       })
140 |     }
141 |   },
142 | 
143 |   beforeDestroy() {
144 |     clearTimeout(this.timerId)
145 |   },
146 | 
147 |   methods: {
148 |     handleCollapse() {
149 |       this.collapsed = !this.collapsed
150 |     },
151 | 
152 |     handleCopy() {
153 |       this.copied = true
154 |       copy(this.decodedCode)
155 | 
156 |       clearTimeout(this.timer)
157 |       this.timerId = setTimeout(() => {
158 |         this.copied = false
159 |       }, 2000)
160 |     },
161 | 
162 |     openCodeSandBox() {
163 |       createCodeSandBox(this.demoStr)
164 |     },
165 |   },
166 | }
167 | </script>
168 | 
169 | <style lang="stylus">
170 | .dumi-previewer {
171 |   background-color: #fff;
172 |   border: 1px solid #ebedf1;
173 |   border-radius: 1px;
174 | 
175 |   .dumi-previewer-demo {
176 |     padding: 40px 24px;
177 |   }
178 | 
179 |   .dumi-previewer-actions {
180 |     display: flex;
181 |     align-items: center;
182 |     justify-content: space-between;
183 |     border-top: 1px dashed #ebedf1;
184 |     height: 40px;
185 |     padding: 0 1em;
186 | 
187 |     .dumi-previewer-actions__icon {
188 |       width: 16px;
189 |       height: 16px;
190 |       padding: 8px 4px;
191 |       opacity: 0.4;
192 |       cursor: pointer;
193 |       transition: opacity .3s;
194 | 
195 |       &:hover {
196 |         opacity: 0.6;
197 |       }
198 |     }
199 |   }
200 | 
201 |   .dumi-previewer-source {
202 |     border-top: 1px dashed #ebedf1;
203 | 
204 |     div[class*="language-"] {
205 |       background-color: #f9fafb;
206 |       border-radius: 0;
207 |     }
208 | 
209 |     pre[class*="language-"] {
210 |       margin: 0 !important;
211 |     }
212 | 
213 |     pre[class*="language-"] code {
214 |       color: #000 !important;
215 |     }
216 | 
217 |     .token.cdata,.token.comment,.token.doctype,.token.prolog {
218 |       color: #708090
219 |     }
220 | 
221 |     .token.punctuation {
222 |       color: #999
223 |     }
224 | 
225 |     .token.namespace {
226 |       opacity: .7
227 |     }
228 | 
229 |     .token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag {
230 |       color: #905
231 |     }
232 | 
233 |     .token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string {
234 |       color: #690
235 |     }
236 | 
237 |     .language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url {
238 |       color: #9a6e3a;
239 |       background: hsla(0,0%,100%,.5)
240 |     }
241 | 
242 |     .token.atrule,.token.attr-value,.token.keyword {
243 |       color: #07a
244 |     }
245 | 
246 |     .token.class-name,.token.function {
247 |       color: #dd4a68
248 |     }
249 | 
250 |     .token.important,.token.regex,.token.variable {
251 |       color: #e90
252 |     }
253 |   }
254 | }
255 | </style>
256 | 
```

--------------------------------------------------------------------------------
/packages/antd/docs/components/FormStep.zh-CN.md:
--------------------------------------------------------------------------------

```markdown
  1 | # FormStep
  2 | 
  3 | > 分步表单组件
  4 | >
  5 | > 注意:该组件只能用在 Schema 场景
  6 | 
  7 | ## Markup Schema 案例
  8 | 
  9 | ```tsx
 10 | import React from 'react'
 11 | import { FormStep, FormItem, Input, FormButtonGroup } from '@formily/antd'
 12 | import { createForm } from '@formily/core'
 13 | import { FormProvider, FormConsumer, createSchemaField } from '@formily/react'
 14 | import { Button } from 'antd'
 15 | 
 16 | const SchemaField = createSchemaField({
 17 |   components: {
 18 |     FormItem,
 19 |     FormStep,
 20 |     Input,
 21 |   },
 22 | })
 23 | 
 24 | const form = createForm()
 25 | const formStep = FormStep.createFormStep()
 26 | 
 27 | export default () => {
 28 |   return (
 29 |     <FormProvider form={form}>
 30 |       <SchemaField>
 31 |         <SchemaField.Void
 32 |           x-component="FormStep"
 33 |           x-component-props={{ formStep }}
 34 |         >
 35 |           <SchemaField.Void
 36 |             x-component="FormStep.StepPane"
 37 |             x-component-props={{ title: '第一步' }}
 38 |           >
 39 |             <SchemaField.String
 40 |               name="aaa"
 41 |               x-decorator="FormItem"
 42 |               required
 43 |               x-component="Input"
 44 |             />
 45 |           </SchemaField.Void>
 46 |           <SchemaField.Void
 47 |             x-component="FormStep.StepPane"
 48 |             x-component-props={{ title: '第二步' }}
 49 |           >
 50 |             <SchemaField.String
 51 |               name="bbb"
 52 |               x-decorator="FormItem"
 53 |               required
 54 |               x-component="Input"
 55 |             />
 56 |           </SchemaField.Void>
 57 |           <SchemaField.Void
 58 |             type="void"
 59 |             x-component="FormStep.StepPane"
 60 |             x-component-props={{ title: '第三步' }}
 61 |           >
 62 |             <SchemaField.String
 63 |               name="ccc"
 64 |               x-decorator="FormItem"
 65 |               required
 66 |               x-component="Input"
 67 |             />
 68 |           </SchemaField.Void>
 69 |         </SchemaField.Void>
 70 |       </SchemaField>
 71 |       <FormConsumer>
 72 |         {() => (
 73 |           <FormButtonGroup>
 74 |             <Button
 75 |               disabled={!formStep.allowBack}
 76 |               onClick={() => {
 77 |                 formStep.back()
 78 |               }}
 79 |             >
 80 |               上一步
 81 |             </Button>
 82 |             <Button
 83 |               disabled={!formStep.allowNext}
 84 |               onClick={() => {
 85 |                 formStep.next()
 86 |               }}
 87 |             >
 88 |               下一步
 89 |             </Button>
 90 |             <Button
 91 |               disabled={formStep.allowNext}
 92 |               onClick={() => {
 93 |                 formStep.submit(console.log)
 94 |               }}
 95 |             >
 96 |               提交
 97 |             </Button>
 98 |           </FormButtonGroup>
 99 |         )}
100 |       </FormConsumer>
101 |     </FormProvider>
102 |   )
103 | }
104 | ```
105 | 
106 | ## JSON Schema 案例
107 | 
108 | ```tsx
109 | import React from 'react'
110 | import { FormStep, FormItem, Input, FormButtonGroup } from '@formily/antd'
111 | import { createForm } from '@formily/core'
112 | import { FormProvider, FormConsumer, createSchemaField } from '@formily/react'
113 | import { Button } from 'antd'
114 | 
115 | const SchemaField = createSchemaField({
116 |   components: {
117 |     FormItem,
118 |     FormStep,
119 |     Input,
120 |   },
121 | })
122 | 
123 | const form = createForm()
124 | const formStep = FormStep.createFormStep()
125 | 
126 | const schema = {
127 |   type: 'object',
128 |   properties: {
129 |     step: {
130 |       type: 'void',
131 |       'x-component': 'FormStep',
132 |       'x-component-props': {
133 |         formStep: '{{formStep}}',
134 |       },
135 |       properties: {
136 |         step1: {
137 |           type: 'void',
138 |           'x-component': 'FormStep.StepPane',
139 |           'x-component-props': {
140 |             title: '第一步',
141 |           },
142 |           properties: {
143 |             aaa: {
144 |               type: 'string',
145 |               title: 'AAA',
146 |               required: true,
147 |               'x-decorator': 'FormItem',
148 |               'x-component': 'Input',
149 |             },
150 |           },
151 |         },
152 |         step2: {
153 |           type: 'void',
154 |           'x-component': 'FormStep.StepPane',
155 |           'x-component-props': {
156 |             title: '第二步',
157 |           },
158 |           properties: {
159 |             bbb: {
160 |               type: 'string',
161 |               title: 'AAA',
162 |               required: true,
163 |               'x-decorator': 'FormItem',
164 |               'x-component': 'Input',
165 |             },
166 |           },
167 |         },
168 |         step3: {
169 |           type: 'void',
170 |           'x-component': 'FormStep.StepPane',
171 |           'x-component-props': {
172 |             title: '第三步',
173 |           },
174 |           properties: {
175 |             ccc: {
176 |               type: 'string',
177 |               title: 'AAA',
178 |               required: true,
179 |               'x-decorator': 'FormItem',
180 |               'x-component': 'Input',
181 |             },
182 |           },
183 |         },
184 |       },
185 |     },
186 |   },
187 | }
188 | 
189 | export default () => {
190 |   return (
191 |     <FormProvider form={form}>
192 |       <SchemaField schema={schema} scope={{ formStep }} />
193 |       <FormConsumer>
194 |         {() => (
195 |           <FormButtonGroup>
196 |             <Button
197 |               disabled={!formStep.allowBack}
198 |               onClick={() => {
199 |                 formStep.back()
200 |               }}
201 |             >
202 |               上一步
203 |             </Button>
204 |             <Button
205 |               disabled={!formStep.allowNext}
206 |               onClick={() => {
207 |                 formStep.next()
208 |               }}
209 |             >
210 |               下一步
211 |             </Button>
212 |             <Button
213 |               disabled={formStep.allowNext}
214 |               onClick={() => {
215 |                 formStep.submit(console.log)
216 |               }}
217 |             >
218 |               提交
219 |             </Button>
220 |           </FormButtonGroup>
221 |         )}
222 |       </FormConsumer>
223 |     </FormProvider>
224 |   )
225 | }
226 | ```
227 | 
228 | ## API
229 | 
230 | ### FormStep
231 | 
232 | | 属性名   | 类型      | 描述                                               | 默认值 |
233 | | -------- | --------- | -------------------------------------------------- | ------ |
234 | | formStep | IFormStep | 传入通过 createFormStep/useFormStep 创建出来的模型 |        |
235 | 
236 | 其余参考 https://ant.design/components/steps-cn/
237 | 
238 | ### FormStep.StepPane
239 | 
240 | 参考 https://ant.design/components/steps-cn/ Steps.Step 属性
241 | 
242 | ### FormStep.createFormStep
243 | 
244 | ```ts pure
245 | import { Form } from '@formily/core'
246 | 
247 | interface createFormStep {
248 |   (current?: number): IFormStep
249 | }
250 | 
251 | interface IFormTab {
252 |   //当前索引
253 |   current: number
254 |   //是否允许向后
255 |   allowNext: boolean
256 |   //是否允许向前
257 |   allowBack: boolean
258 |   //设置当前索引
259 |   setCurrent(key: number): void
260 |   //提交表单
261 |   submit: Form['submit']
262 |   //向后
263 |   next(): void
264 |   //向前
265 |   back(): void
266 | }
267 | ```
268 | 
```

--------------------------------------------------------------------------------
/packages/next/docs/components/FormStep.zh-CN.md:
--------------------------------------------------------------------------------

```markdown
  1 | # FormStep
  2 | 
  3 | > 分步表单组件
  4 | >
  5 | > 注意:该组件只能用在 Schema 场景
  6 | 
  7 | ## Markup Schema 案例
  8 | 
  9 | ```tsx
 10 | import React from 'react'
 11 | import { FormStep, FormItem, Input, FormButtonGroup } from '@formily/next'
 12 | import { createForm } from '@formily/core'
 13 | import { FormProvider, FormConsumer, createSchemaField } from '@formily/react'
 14 | import { Button } from '@alifd/next'
 15 | 
 16 | const SchemaField = createSchemaField({
 17 |   components: {
 18 |     FormItem,
 19 |     FormStep,
 20 |     Input,
 21 |   },
 22 | })
 23 | 
 24 | const form = createForm()
 25 | const formStep = FormStep.createFormStep()
 26 | 
 27 | export default () => {
 28 |   return (
 29 |     <FormProvider form={form}>
 30 |       <SchemaField>
 31 |         <SchemaField.Void
 32 |           x-component="FormStep"
 33 |           x-component-props={{ formStep }}
 34 |         >
 35 |           <SchemaField.Void
 36 |             x-component="FormStep.StepPane"
 37 |             x-component-props={{ title: '第一步' }}
 38 |           >
 39 |             <SchemaField.String
 40 |               name="aaa"
 41 |               x-decorator="FormItem"
 42 |               required
 43 |               x-component="Input"
 44 |             />
 45 |           </SchemaField.Void>
 46 |           <SchemaField.Void
 47 |             x-component="FormStep.StepPane"
 48 |             x-component-props={{ title: '第二步' }}
 49 |           >
 50 |             <SchemaField.String
 51 |               name="bbb"
 52 |               x-decorator="FormItem"
 53 |               required
 54 |               x-component="Input"
 55 |             />
 56 |           </SchemaField.Void>
 57 |           <SchemaField.Void
 58 |             type="void"
 59 |             x-component="FormStep.StepPane"
 60 |             x-component-props={{ title: '第三步' }}
 61 |           >
 62 |             <SchemaField.String
 63 |               name="ccc"
 64 |               x-decorator="FormItem"
 65 |               required
 66 |               x-component="Input"
 67 |             />
 68 |           </SchemaField.Void>
 69 |         </SchemaField.Void>
 70 |       </SchemaField>
 71 |       <FormConsumer>
 72 |         {() => (
 73 |           <FormButtonGroup>
 74 |             <Button
 75 |               disabled={!formStep.allowBack}
 76 |               onClick={() => {
 77 |                 formStep.back()
 78 |               }}
 79 |             >
 80 |               上一步
 81 |             </Button>
 82 |             <Button
 83 |               disabled={!formStep.allowNext}
 84 |               onClick={() => {
 85 |                 formStep.next()
 86 |               }}
 87 |             >
 88 |               下一步
 89 |             </Button>
 90 |             <Button
 91 |               disabled={formStep.allowNext}
 92 |               onClick={() => {
 93 |                 formStep.submit(console.log)
 94 |               }}
 95 |             >
 96 |               提交
 97 |             </Button>
 98 |           </FormButtonGroup>
 99 |         )}
100 |       </FormConsumer>
101 |     </FormProvider>
102 |   )
103 | }
104 | ```
105 | 
106 | ## JSON Schema 案例
107 | 
108 | ```tsx
109 | import React from 'react'
110 | import { FormStep, FormItem, Input, FormButtonGroup } from '@formily/next'
111 | import { createForm } from '@formily/core'
112 | import { FormProvider, FormConsumer, createSchemaField } from '@formily/react'
113 | import { Button } from '@alifd/next'
114 | 
115 | const SchemaField = createSchemaField({
116 |   components: {
117 |     FormItem,
118 |     FormStep,
119 |     Input,
120 |   },
121 | })
122 | 
123 | const form = createForm()
124 | const formStep = FormStep.createFormStep()
125 | 
126 | const schema = {
127 |   type: 'object',
128 |   properties: {
129 |     step: {
130 |       type: 'void',
131 |       'x-component': 'FormStep',
132 |       'x-component-props': {
133 |         formStep: '{{formStep}}',
134 |       },
135 |       properties: {
136 |         step1: {
137 |           type: 'void',
138 |           'x-component': 'FormStep.StepPane',
139 |           'x-component-props': {
140 |             title: '第一步',
141 |           },
142 |           properties: {
143 |             aaa: {
144 |               type: 'string',
145 |               title: 'AAA',
146 |               required: true,
147 |               'x-decorator': 'FormItem',
148 |               'x-component': 'Input',
149 |             },
150 |           },
151 |         },
152 |         step2: {
153 |           type: 'void',
154 |           'x-component': 'FormStep.StepPane',
155 |           'x-component-props': {
156 |             title: '第二步',
157 |           },
158 |           properties: {
159 |             bbb: {
160 |               type: 'string',
161 |               title: 'AAA',
162 |               required: true,
163 |               'x-decorator': 'FormItem',
164 |               'x-component': 'Input',
165 |             },
166 |           },
167 |         },
168 |         step3: {
169 |           type: 'void',
170 |           'x-component': 'FormStep.StepPane',
171 |           'x-component-props': {
172 |             title: '第三步',
173 |           },
174 |           properties: {
175 |             ccc: {
176 |               type: 'string',
177 |               title: 'AAA',
178 |               required: true,
179 |               'x-decorator': 'FormItem',
180 |               'x-component': 'Input',
181 |             },
182 |           },
183 |         },
184 |       },
185 |     },
186 |   },
187 | }
188 | 
189 | export default () => {
190 |   return (
191 |     <FormProvider form={form}>
192 |       <SchemaField schema={schema} scope={{ formStep }} />
193 |       <FormConsumer>
194 |         {() => (
195 |           <FormButtonGroup>
196 |             <Button
197 |               disabled={!formStep.allowBack}
198 |               onClick={() => {
199 |                 formStep.back()
200 |               }}
201 |             >
202 |               上一步
203 |             </Button>
204 |             <Button
205 |               disabled={!formStep.allowNext}
206 |               onClick={() => {
207 |                 formStep.next()
208 |               }}
209 |             >
210 |               下一步
211 |             </Button>
212 |             <Button
213 |               disabled={formStep.allowNext}
214 |               onClick={() => {
215 |                 formStep.submit(console.log)
216 |               }}
217 |             >
218 |               提交
219 |             </Button>
220 |           </FormButtonGroup>
221 |         )}
222 |       </FormConsumer>
223 |     </FormProvider>
224 |   )
225 | }
226 | ```
227 | 
228 | ## API
229 | 
230 | ### FormStep
231 | 
232 | | 属性名   | 类型      | 描述                                               | 默认值 |
233 | | -------- | --------- | -------------------------------------------------- | ------ |
234 | | formStep | IFormStep | 传入通过 createFormStep/useFormStep 创建出来的模型 |        |
235 | 
236 | 其余参考 https://fusion.design/pc/component/basic/step
237 | 
238 | ### FormStep.StepPane
239 | 
240 | 参考 https://fusion.design/pc/component/basic/step Steps.Step 属性
241 | 
242 | ### FormStep.createFormStep
243 | 
244 | ```ts pure
245 | import { Form } from '@formily/core'
246 | 
247 | interface createFormStep {
248 |   (current?: number): IFormStep
249 | }
250 | 
251 | interface IFormTab {
252 |   //当前索引
253 |   current: number
254 |   //是否允许向后
255 |   allowNext: boolean
256 |   //是否允许向前
257 |   allowBack: boolean
258 |   //设置当前索引
259 |   setCurrent(key: number): void
260 |   //提交表单
261 |   submit: Form['submit']
262 |   //向后
263 |   next(): void
264 |   //向前
265 |   back(): void
266 | }
267 | ```
268 | 
```

--------------------------------------------------------------------------------
/packages/element/docs/.vuepress/components/dumi-previewer.vue:
--------------------------------------------------------------------------------

```vue
  1 | <template>
  2 |   <client-only>
  3 |     <section class="dumi-previewer">
  4 |       <div class="dumi-previewer-demo">
  5 |         <template v-if="demoPath && demo">
  6 |           <component :is="demo" />
  7 |         </template>
  8 | 
  9 |         <template v-else>
 10 |           <slot name="demo"></slot>
 11 |         </template>
 12 |       </div>
 13 | 
 14 |       <div class="dumi-previewer-actions">
 15 |         <div>
 16 |           <svg
 17 |             xmlns="http://www.w3.org/2000/svg"
 18 |             xmlns:xlink="http://www.w3.org/1999/xlink"
 19 |             class="dumi-previewer-actions__icon"
 20 |             viewBox="0 0 256 296"
 21 |             @click="openCodeSandBox"
 22 |           >
 23 |             <path
 24 |               d="M115.498 261.088v-106.61L23.814 101.73v60.773l41.996 24.347v45.7l49.688 28.54zm23.814.627l50.605-29.151V185.78l42.269-24.495v-60.011l-92.874 53.621v106.82zm80.66-180.887l-48.817-28.289l-42.863 24.872l-43.188-24.897l-49.252 28.667l91.914 52.882l92.206-53.235zM0 222.212V74.495L127.987 0L256 74.182v147.797l-128.016 73.744L0 222.212z"
 25 |               fill="#000"
 26 |             ></path>
 27 |           </svg>
 28 |         </div>
 29 | 
 30 |         <div>
 31 |           <svg
 32 |             v-if="copied"
 33 |             class="dumi-previewer-actions__icon"
 34 |             style="fill: green"
 35 |             xmlns="http://www.w3.org/2000/svg"
 36 |             viewBox="0 0 24 24"
 37 |             width="24"
 38 |             height="24"
 39 |           >
 40 |             <path fill="none" d="M0 0h24v24H0z" />
 41 |             <path
 42 |               d="M10 15.172l9.192-9.193 1.415 1.414L10 18l-6.364-6.364 1.414-1.414z"
 43 |             />
 44 |           </svg>
 45 | 
 46 |           <svg
 47 |             v-else
 48 |             class="dumi-previewer-actions__icon"
 49 |             xmlns="http://www.w3.org/2000/svg"
 50 |             viewBox="0 0 24 24"
 51 |             width="24"
 52 |             height="24"
 53 |             @click="handleCopy"
 54 |           >
 55 |             <path fill="none" d="M0 0h24v24H0z" />
 56 |             <path
 57 |               d="M7 6V3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1h-3v3c0 .552-.45 1-1.007 1H4.007A1.001 1.001 0 0 1 3 21l.003-14c0-.552.45-1 1.007-1H7zM5.003 8L5 20h10V8H5.003zM9 6h8v10h2V4H9v2z"
 58 |             />
 59 |           </svg>
 60 | 
 61 |           <svg
 62 |             class="dumi-previewer-actions__icon"
 63 |             xmlns="http://www.w3.org/2000/svg"
 64 |             viewBox="0 0 24 24"
 65 |             width="24"
 66 |             height="24"
 67 |             @click="handleCollapse"
 68 |           >
 69 |             <path fill="none" d="M0 0h24v24H0z" />
 70 |             <path
 71 |               d="M24 12l-5.657 5.657-1.414-1.414L21.172 12l-4.243-4.243 1.414-1.414L24 12zM2.828 12l4.243 4.243-1.414 1.414L0 12l5.657-5.657L7.07 7.757 2.828 12zm6.96 9H7.66l6.552-18h2.128L9.788 21z"
 72 |             />
 73 |           </svg>
 74 |         </div>
 75 |       </div>
 76 | 
 77 |       <div v-show="!innerCollapsed" class="dumi-previewer-source">
 78 |         <div v-html="highlightCode" class="language-vue extra-class" />
 79 |       </div>
 80 |     </section>
 81 |   </client-only>
 82 | </template>
 83 | 
 84 | <script>
 85 | import copy from 'copy-to-clipboard'
 86 | import highlight from './highlight'
 87 | import { createCodeSandBox } from './createCodeSandBox'
 88 | 
 89 | export default {
 90 |   name: 'dumi-previewer',
 91 | 
 92 |   props: {
 93 |     code: {
 94 |       type: String,
 95 |       default: '',
 96 |     },
 97 | 
 98 |     demoPath: {
 99 |       type: String,
100 |       default: '',
101 |     },
102 |     collapsed: {
103 |       type: Boolean,
104 |       default: true,
105 |     },
106 |   },
107 | 
108 |   data() {
109 |     return {
110 |       innerCollapsed: this.collapsed,
111 |       copied: false,
112 |       timerId: null,
113 |       demoStr: '',
114 |       /**
115 |        * take over VuePress render
116 |        * 接管VuePress渲染
117 |        */
118 |       demo: null,
119 |     }
120 |   },
121 | 
122 |   computed: {
123 |     decodedCode() {
124 |       return this.code || this.demoStr
125 |     },
126 | 
127 |     highlightCode() {
128 |       return highlight(this.decodedCode, 'vue')
129 |     },
130 |   },
131 | 
132 |   created() {
133 |     if (this.demoPath) {
134 |       import(
135 |         /* webpackPrefetch: true */ `../../demos/${this.demoPath}.vue`
136 |       ).then((module) => {
137 |         this.demo = module.default
138 |       })
139 |       import(
140 |         /* webpackPrefetch: true */ `!raw-loader!../../demos/${this.demoPath}.vue`
141 |       ).then((module) => {
142 |         this.demoStr = module.default
143 |       })
144 |     }
145 |   },
146 | 
147 |   beforeDestroy() {
148 |     clearTimeout(this.timerId)
149 |   },
150 | 
151 |   methods: {
152 |     handleCollapse() {
153 |       this.innerCollapsed = !this.innerCollapsed
154 |     },
155 | 
156 |     handleCopy() {
157 |       this.copied = true
158 |       copy(this.decodedCode)
159 | 
160 |       clearTimeout(this.timer)
161 |       this.timerId = setTimeout(() => {
162 |         this.copied = false
163 |       }, 2000)
164 |     },
165 | 
166 |     openCodeSandBox() {
167 |       createCodeSandBox(this.demoStr)
168 |     },
169 |   },
170 | }
171 | </script>
172 | 
173 | <style lang="stylus">
174 | .dumi-previewer {
175 |   background-color: #fff;
176 |   border: 1px solid #ebedf1;
177 |   border-radius: 1px;
178 | 
179 |   .dumi-previewer-demo {
180 |     padding: 40px 24px;
181 |   }
182 | 
183 |   .dumi-previewer-actions {
184 |     display: flex;
185 |     align-items: center;
186 |     justify-content: space-between;
187 |     border-top: 1px dashed #ebedf1;
188 |     height: 40px;
189 |     padding: 0 1em;
190 | 
191 |     .dumi-previewer-actions__icon {
192 |       width: 16px;
193 |       height: 16px;
194 |       padding: 8px 4px;
195 |       opacity: 0.4;
196 |       cursor: pointer;
197 |       transition: opacity .3s;
198 | 
199 |       &:hover {
200 |         opacity: 0.6;
201 |       }
202 |     }
203 |   }
204 | 
205 |   .dumi-previewer-source {
206 |     border-top: 1px dashed #ebedf1;
207 | 
208 |     div[class*="language-"] {
209 |       background-color: #f9fafb;
210 |       border-radius: 0;
211 |     }
212 | 
213 |     pre[class*="language-"] {
214 |       margin: 0 !important;
215 |     }
216 | 
217 |     pre[class*="language-"] code {
218 |       color: #000 !important;
219 |     }
220 | 
221 |     .token.cdata,.token.comment,.token.doctype,.token.prolog {
222 |       color: #708090
223 |     }
224 | 
225 |     .token.punctuation {
226 |       color: #999
227 |     }
228 | 
229 |     .token.namespace {
230 |       opacity: .7
231 |     }
232 | 
233 |     .token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag {
234 |       color: #905
235 |     }
236 | 
237 |     .token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string {
238 |       color: #690
239 |     }
240 | 
241 |     .language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url {
242 |       color: #9a6e3a;
243 |       background: hsla(0,0%,100%,.5)
244 |     }
245 | 
246 |     .token.atrule,.token.attr-value,.token.keyword {
247 |       color: #07a
248 |     }
249 | 
250 |     .token.class-name,.token.function {
251 |       color: #dd4a68
252 |     }
253 | 
254 |     .token.important,.token.regex,.token.variable {
255 |       color: #e90
256 |     }
257 |   }
258 | }
259 | </style>
260 | 
```

--------------------------------------------------------------------------------
/packages/react/src/components/SchemaField.tsx:
--------------------------------------------------------------------------------

```typescript
  1 | import React, { useContext, Fragment } from 'react'
  2 | import { ISchema, Schema } from '@formily/json-schema'
  3 | import { RecursionField } from './RecursionField'
  4 | import { render } from '../shared/render'
  5 | import {
  6 |   SchemaMarkupContext,
  7 |   SchemaOptionsContext,
  8 |   SchemaComponentsContext,
  9 | } from '../shared'
 10 | import {
 11 |   ReactComponentPath,
 12 |   JSXComponent,
 13 |   ISchemaFieldReactFactoryOptions,
 14 |   SchemaReactComponents,
 15 |   ISchemaFieldProps,
 16 |   ISchemaMarkupFieldProps,
 17 |   ISchemaTypeFieldProps,
 18 | } from '../types'
 19 | import { lazyMerge } from '@formily/shared'
 20 | import { ExpressionScope } from './ExpressionScope'
 21 | const env = {
 22 |   nonameId: 0,
 23 | }
 24 | 
 25 | const getRandomName = () => {
 26 |   return `NO_NAME_FIELD_$${env.nonameId++}`
 27 | }
 28 | 
 29 | export function createSchemaField<Components extends SchemaReactComponents>(
 30 |   options: ISchemaFieldReactFactoryOptions<Components> = {}
 31 | ) {
 32 |   function SchemaField<
 33 |     Decorator extends JSXComponent,
 34 |     Component extends JSXComponent
 35 |   >(props: ISchemaFieldProps<Decorator, Component>) {
 36 |     const schema = Schema.isSchemaInstance(props.schema)
 37 |       ? props.schema
 38 |       : new Schema({
 39 |           type: 'object',
 40 |           ...props.schema,
 41 |         })
 42 |     const renderMarkup = () => {
 43 |       env.nonameId = 0
 44 |       if (props.schema) return null
 45 |       return render(
 46 |         <SchemaMarkupContext.Provider value={schema}>
 47 |           {props.children}
 48 |         </SchemaMarkupContext.Provider>
 49 |       )
 50 |     }
 51 | 
 52 |     const renderChildren = () => {
 53 |       return <RecursionField {...props} schema={schema} />
 54 |     }
 55 | 
 56 |     return (
 57 |       <SchemaOptionsContext.Provider value={options}>
 58 |         <SchemaComponentsContext.Provider
 59 |           value={lazyMerge(options.components, props.components)}
 60 |         >
 61 |           <ExpressionScope value={lazyMerge(options.scope, props.scope)}>
 62 |             {renderMarkup()}
 63 |             {renderChildren()}
 64 |           </ExpressionScope>
 65 |         </SchemaComponentsContext.Provider>
 66 |       </SchemaOptionsContext.Provider>
 67 |     )
 68 |   }
 69 | 
 70 |   SchemaField.displayName = 'SchemaField'
 71 | 
 72 |   function MarkupRender(props: any) {
 73 |     const parent = useContext(SchemaMarkupContext)
 74 |     if (!parent) return <Fragment />
 75 |     const renderChildren = () => {
 76 |       return <React.Fragment>{props.children}</React.Fragment>
 77 |     }
 78 |     const appendArraySchema = (schema: ISchema) => {
 79 |       const items = parent.items as Schema
 80 |       if (items && items.name !== props.name) {
 81 |         return parent.addProperty(props.name, schema)
 82 |       } else {
 83 |         return parent.setItems(schema)
 84 |       }
 85 |     }
 86 |     if (parent.type === 'object' || parent.type === 'void') {
 87 |       const schema = parent.addProperty(props.name, props)
 88 |       return (
 89 |         <SchemaMarkupContext.Provider value={schema}>
 90 |           {renderChildren()}
 91 |         </SchemaMarkupContext.Provider>
 92 |       )
 93 |     } else if (parent.type === 'array') {
 94 |       const schema = appendArraySchema(props)
 95 |       return (
 96 |         <SchemaMarkupContext.Provider
 97 |           value={Array.isArray(schema) ? schema[0] : schema}
 98 |         >
 99 |           {props.children}
100 |         </SchemaMarkupContext.Provider>
101 |       )
102 |     } else {
103 |       return renderChildren()
104 |     }
105 |   }
106 | 
107 |   function MarkupField<
108 |     Decorator extends ReactComponentPath<Components>,
109 |     Component extends ReactComponentPath<Components>
110 |   >(props: ISchemaMarkupFieldProps<Components, Component, Decorator>) {
111 |     return <MarkupRender {...props} name={props.name || getRandomName()} />
112 |   }
113 | 
114 |   MarkupField.displayName = 'MarkupField'
115 | 
116 |   function StringField<
117 |     Decorator extends ReactComponentPath<Components>,
118 |     Component extends ReactComponentPath<Components>
119 |   >(props: ISchemaTypeFieldProps<Components, Component, Decorator>) {
120 |     return <MarkupField {...props} type="string" />
121 |   }
122 | 
123 |   StringField.displayName = 'StringField'
124 | 
125 |   function ObjectField<
126 |     Decorator extends ReactComponentPath<Components>,
127 |     Component extends ReactComponentPath<Components>
128 |   >(props: ISchemaTypeFieldProps<Components, Component, Decorator>) {
129 |     return <MarkupField {...props} type="object" />
130 |   }
131 | 
132 |   ObjectField.displayName = 'ObjectField'
133 | 
134 |   function ArrayField<
135 |     Decorator extends ReactComponentPath<Components>,
136 |     Component extends ReactComponentPath<Components>
137 |   >(props: ISchemaTypeFieldProps<Components, Component, Decorator>) {
138 |     return <MarkupField {...props} type="array" />
139 |   }
140 | 
141 |   ArrayField.displayName = 'ArrayField'
142 |   function BooleanField<
143 |     Decorator extends ReactComponentPath<Components>,
144 |     Component extends ReactComponentPath<Components>
145 |   >(props: ISchemaTypeFieldProps<Components, Component, Decorator>) {
146 |     return <MarkupField {...props} type="boolean" />
147 |   }
148 | 
149 |   BooleanField.displayName = 'BooleanField'
150 | 
151 |   function NumberField<
152 |     Decorator extends ReactComponentPath<Components>,
153 |     Component extends ReactComponentPath<Components>
154 |   >(props: ISchemaTypeFieldProps<Components, Component, Decorator>) {
155 |     return <MarkupField {...props} type="number" />
156 |   }
157 | 
158 |   NumberField.displayName = 'NumberField'
159 | 
160 |   function DateField<
161 |     Decorator extends ReactComponentPath<Components>,
162 |     Component extends ReactComponentPath<Components>
163 |   >(props: ISchemaTypeFieldProps<Components, Component, Decorator>) {
164 |     return <MarkupField {...props} type="date" />
165 |   }
166 | 
167 |   DateField.displayName = 'DateField'
168 | 
169 |   function DateTimeField<
170 |     Decorator extends ReactComponentPath<Components>,
171 |     Component extends ReactComponentPath<Components>
172 |   >(props: ISchemaTypeFieldProps<Components, Component, Decorator>) {
173 |     return <MarkupField {...props} type="datetime" />
174 |   }
175 | 
176 |   DateTimeField.displayName = 'DateTimeField'
177 | 
178 |   function VoidField<
179 |     Decorator extends ReactComponentPath<Components>,
180 |     Component extends ReactComponentPath<Components>
181 |   >(props: ISchemaTypeFieldProps<Components, Component, Decorator>) {
182 |     return <MarkupField {...props} type="void" />
183 |   }
184 | 
185 |   VoidField.displayName = 'VoidField'
186 | 
187 |   SchemaField.Markup = MarkupField
188 |   SchemaField.String = StringField
189 |   SchemaField.Object = ObjectField
190 |   SchemaField.Array = ArrayField
191 |   SchemaField.Boolean = BooleanField
192 |   SchemaField.Date = DateField
193 |   SchemaField.DateTime = DateTimeField
194 |   SchemaField.Void = VoidField
195 |   SchemaField.Number = NumberField
196 | 
197 |   return SchemaField
198 | }
199 | 
```

--------------------------------------------------------------------------------
/packages/antd/docs/components/PreviewText.zh-CN.md:
--------------------------------------------------------------------------------

```markdown
  1 | # PreviewText
  2 | 
  3 | > 阅读态组件,主要用来实现类 Input,类 DatePicker 这些组件的阅读态
  4 | 
  5 | ## 简单用例
  6 | 
  7 | ```tsx
  8 | import React from 'react'
  9 | import { PreviewText, FormItem, FormLayout } from '@formily/antd'
 10 | import { createForm } from '@formily/core'
 11 | import { FormProvider, createSchemaField } from '@formily/react'
 12 | 
 13 | const SchemaField = createSchemaField({
 14 |   components: {
 15 |     FormItem,
 16 |     PreviewText,
 17 |   },
 18 | })
 19 | 
 20 | const form = createForm()
 21 | 
 22 | export default () => {
 23 |   return (
 24 |     <FormLayout labelCol={6} wrapperCol={10}>
 25 |       <FormProvider form={form}>
 26 |         <SchemaField>
 27 |           <SchemaField.String
 28 |             x-decorator="FormItem"
 29 |             title="文本预览"
 30 |             x-component="PreviewText.Input"
 31 |             default={'Hello world'}
 32 |           />
 33 |           <SchemaField.String
 34 |             x-decorator="FormItem"
 35 |             title="选择项预览"
 36 |             x-component="PreviewText.Select"
 37 |             x-component-props={{
 38 |               mode: 'multiple',
 39 |             }}
 40 |             default={['123', '222']}
 41 |             enum={[
 42 |               { label: 'A111', value: '123' },
 43 |               { label: 'A222', value: '222' },
 44 |             ]}
 45 |           />
 46 |           <SchemaField.String
 47 |             x-decorator="FormItem"
 48 |             title="树选择预览"
 49 |             x-component="PreviewText.TreeSelect"
 50 |             x-component-props={{
 51 |               multiple: true,
 52 |             }}
 53 |             default={['123', '222']}
 54 |             enum={[
 55 |               { label: 'A111', value: '123' },
 56 |               { label: 'A222', value: '222' },
 57 |             ]}
 58 |           />
 59 |           <SchemaField.String
 60 |             x-decorator="FormItem"
 61 |             title="树选择(treeData)预览"
 62 |             x-component="PreviewText.TreeSelect"
 63 |             x-component-props={{
 64 |               multiple: true,
 65 |               treeNodeLabelProp: 'name',
 66 |               treeData: [
 67 |                 { name: 'A111', value: '123' },
 68 |                 { name: 'A222', value: '222' },
 69 |               ],
 70 |             }}
 71 |             default={['123', '222']}
 72 |           />
 73 |           <SchemaField.String
 74 |             x-decorator="FormItem"
 75 |             title="日期预览"
 76 |             x-component="PreviewText.DatePicker"
 77 |             default={'2020-11-23 22:15:20'}
 78 |           />
 79 |           <SchemaField.String
 80 |             x-decorator="FormItem"
 81 |             title="Cascader预览"
 82 |             x-component="PreviewText.Cascader"
 83 |             default={'yuhang'}
 84 |             enum={[
 85 |               {
 86 |                 label: '杭州',
 87 |                 value: 'hangzhou',
 88 |                 children: [
 89 |                   {
 90 |                     label: '余杭',
 91 |                     value: 'yuhang',
 92 |                   },
 93 |                 ],
 94 |               },
 95 |             ]}
 96 |           />
 97 |         </SchemaField>
 98 |       </FormProvider>
 99 |     </FormLayout>
100 |   )
101 | }
102 | ```
103 | 
104 | ## 扩展阅读态
105 | 
106 | ```tsx
107 | import React from 'react'
108 | import {
109 |   PreviewText,
110 |   FormItem,
111 |   FormLayout,
112 |   FormButtonGroup,
113 | } from '@formily/antd'
114 | import { createForm } from '@formily/core'
115 | import {
116 |   FormProvider,
117 |   mapReadPretty,
118 |   connect,
119 |   createSchemaField,
120 | } from '@formily/react'
121 | import { Button, Input as AntdInput } from 'antd'
122 | 
123 | const Input = connect(AntdInput, mapReadPretty(PreviewText.Input))
124 | 
125 | const SchemaField = createSchemaField({
126 |   components: {
127 |     Input,
128 |     FormItem,
129 |     PreviewText,
130 |   },
131 | })
132 | 
133 | const form = createForm()
134 | 
135 | export default () => {
136 |   return (
137 |     <PreviewText.Placeholder value="暂无数据">
138 |       <FormLayout labelCol={6} wrapperCol={10}>
139 |         <FormProvider form={form}>
140 |           <SchemaField>
141 |             <SchemaField.Markup
142 |               type="string"
143 |               x-decorator="FormItem"
144 |               title="文本预览"
145 |               required
146 |               x-component="Input"
147 |               default={'Hello world'}
148 |             />
149 |             <SchemaField.Markup
150 |               type="string"
151 |               x-decorator="FormItem"
152 |               title="选择项预览"
153 |               x-component="PreviewText.Select"
154 |               x-component-props={{
155 |                 mode: 'multiple',
156 |               }}
157 |               default={['123']}
158 |               enum={[
159 |                 { label: 'A111', value: '123' },
160 |                 { label: 'A222', value: '222' },
161 |               ]}
162 |             />
163 |             <SchemaField.Markup
164 |               type="string"
165 |               x-decorator="FormItem"
166 |               title="日期预览"
167 |               x-component="PreviewText.DatePicker"
168 |             />
169 |             <SchemaField.Markup
170 |               type="string"
171 |               x-decorator="FormItem"
172 |               title="Cascader预览"
173 |               x-component="PreviewText.Cascader"
174 |               default={'yuhang'}
175 |               enum={[
176 |                 {
177 |                   label: '杭州',
178 |                   value: 'hangzhou',
179 |                   children: [
180 |                     {
181 |                       label: '余杭',
182 |                       value: 'yuhang',
183 |                     },
184 |                   ],
185 |                 },
186 |               ]}
187 |             />
188 |           </SchemaField>
189 |           <FormButtonGroup.FormItem>
190 |             <Button
191 |               onClick={() => {
192 |                 form.setState((state) => {
193 |                   state.editable = !state.editable
194 |                 })
195 |               }}
196 |             >
197 |               切换阅读态
198 |             </Button>
199 |           </FormButtonGroup.FormItem>
200 |         </FormProvider>
201 |       </FormLayout>
202 |     </PreviewText.Placeholder>
203 |   )
204 | }
205 | ```
206 | 
207 | ## API
208 | 
209 | ### PreviewText.Input
210 | 
211 | 参考 https://ant.design/components/input-cn/
212 | 
213 | ### PreviewText.Select
214 | 
215 | 参考 https://ant.design/components/select-cn/
216 | 
217 | ### PreviewText.TreeSelect
218 | 
219 | 参考 https://ant.design/components/tree-select-cn/
220 | 
221 | ### PreviewText.Cascader
222 | 
223 | 参考 https://ant.design/components/cascader-cn/
224 | 
225 | ### PreviewText.DatePicker
226 | 
227 | 参考 https://ant.design/components/date-picker-cn/
228 | 
229 | ### PreviewText.DateRangePicker
230 | 
231 | 参考 https://ant.design/components/date-picker-cn/
232 | 
233 | ### PreviewText.TimePicker
234 | 
235 | 参考 https://ant.design/components/time-picker-cn/
236 | 
237 | ### PreviewText.TimeRangePicker
238 | 
239 | 参考 https://ant.design/components/time-picker-cn/
240 | 
241 | ### PreviewText.NumberPicker
242 | 
243 | 参考 https://ant.design/components/input-number-cn/
244 | 
245 | ### PreviewText.Placeholder
246 | 
247 | | 属性名 | 类型   | 描述       | 默认值 |
248 | | ------ | ------ | ---------- | ------ |
249 | | value  | stirng | 缺省占位符 | N/A    |
250 | 
251 | ### PreviewText.usePlaceholder
252 | 
253 | ```ts pure
254 | interface usePlaceholder {
255 |   (): string
256 | }
257 | ```
258 | 
```
Page 18/52FirstPrevNextLast