#
tokens: 47046/50000 6/1152 files (page 30/52)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 30 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/antd/src/form-item/index.tsx:
--------------------------------------------------------------------------------

```typescript
  1 | import React, { useEffect, useRef, useContext, useState } from 'react'
  2 | import cls from 'classnames'
  3 | import { usePrefixCls, pickDataProps } from '../__builtins__'
  4 | import { isVoidField } from '@formily/core'
  5 | import { connect, mapProps } from '@formily/react'
  6 | import { useFormLayout, FormLayoutShallowContext } from '../form-layout'
  7 | import { isElement } from 'react-is'
  8 | import { Tooltip, Popover, ConfigProvider } from 'antd'
  9 | import {
 10 |   QuestionCircleOutlined,
 11 |   CloseCircleOutlined,
 12 |   CheckCircleOutlined,
 13 |   ExclamationCircleOutlined,
 14 | } from '@ant-design/icons'
 15 | 
 16 | export interface IFormItemProps {
 17 |   className?: string
 18 |   style?: React.CSSProperties
 19 |   prefixCls?: string
 20 |   label?: React.ReactNode
 21 |   colon?: boolean
 22 |   tooltip?: React.ReactNode | React.ComponentProps<typeof Tooltip>
 23 |   tooltipIcon?: React.ReactNode
 24 |   layout?: 'vertical' | 'horizontal' | 'inline'
 25 |   tooltipLayout?: 'icon' | 'text'
 26 |   labelStyle?: React.CSSProperties
 27 |   labelAlign?: 'left' | 'right'
 28 |   labelFor?: string
 29 |   labelWrap?: boolean
 30 |   labelWidth?: number | string
 31 |   wrapperWidth?: number | string
 32 |   labelCol?: number
 33 |   wrapperCol?: number
 34 |   wrapperAlign?: 'left' | 'right'
 35 |   wrapperWrap?: boolean
 36 |   wrapperStyle?: React.CSSProperties
 37 |   fullness?: boolean
 38 |   addonBefore?: React.ReactNode
 39 |   addonAfter?: React.ReactNode
 40 |   size?: 'small' | 'default' | 'large'
 41 |   inset?: boolean
 42 |   extra?: React.ReactNode
 43 |   feedbackText?: React.ReactNode
 44 |   feedbackLayout?: 'loose' | 'terse' | 'popover' | 'none' | (string & {})
 45 |   feedbackStatus?: 'error' | 'warning' | 'success' | 'pending' | (string & {})
 46 |   feedbackIcon?: React.ReactNode
 47 |   enableOutlineFeedback?: boolean
 48 |   getPopupContainer?: (node: HTMLElement) => HTMLElement
 49 |   asterisk?: boolean
 50 |   optionalMarkHidden?: boolean
 51 |   gridSpan?: number
 52 |   bordered?: boolean
 53 | }
 54 | 
 55 | type ComposeFormItem = React.FC<React.PropsWithChildren<IFormItemProps>> & {
 56 |   BaseItem?: React.FC<React.PropsWithChildren<IFormItemProps>>
 57 | }
 58 | 
 59 | const isTooltipProps = (
 60 |   tooltip: React.ReactNode | React.ComponentProps<typeof Tooltip>
 61 | ): tooltip is React.ComponentProps<typeof Tooltip> => {
 62 |   return !isElement(tooltip)
 63 | }
 64 | 
 65 | const useFormItemLayout = (props: IFormItemProps) => {
 66 |   const layout = useFormLayout()
 67 |   const layoutType = props.layout ?? layout.layout ?? 'horizontal'
 68 |   return {
 69 |     ...props,
 70 |     layout: layoutType,
 71 |     colon: props.colon ?? layout.colon,
 72 |     labelAlign:
 73 |       layoutType === 'vertical'
 74 |         ? props.labelAlign ?? 'left'
 75 |         : props.labelAlign ?? layout.labelAlign ?? 'right',
 76 |     labelWrap: props.labelWrap ?? layout.labelWrap,
 77 |     labelWidth: props.labelWidth ?? layout.labelWidth,
 78 |     wrapperWidth: props.wrapperWidth ?? layout.wrapperWidth,
 79 |     labelCol: props.labelCol ?? layout.labelCol,
 80 |     wrapperCol: props.wrapperCol ?? layout.wrapperCol,
 81 |     wrapperAlign: props.wrapperAlign ?? layout.wrapperAlign,
 82 |     wrapperWrap: props.wrapperWrap ?? layout.wrapperWrap,
 83 |     fullness: props.fullness ?? layout.fullness,
 84 |     size: props.size ?? layout.size,
 85 |     inset: props.inset ?? layout.inset,
 86 |     asterisk: props.asterisk,
 87 |     requiredMark: layout.requiredMark,
 88 |     optionalMarkHidden: props.optionalMarkHidden,
 89 |     bordered: props.bordered ?? layout.bordered,
 90 |     feedbackIcon: props.feedbackIcon,
 91 |     feedbackLayout: props.feedbackLayout ?? layout.feedbackLayout ?? 'loose',
 92 |     tooltipLayout: props.tooltipLayout ?? layout.tooltipLayout ?? 'icon',
 93 |     tooltipIcon: props.tooltipIcon ?? layout.tooltipIcon ?? (
 94 |       <QuestionCircleOutlined />
 95 |     ),
 96 |   }
 97 | }
 98 | 
 99 | function useOverflow<
100 |   Container extends HTMLElement,
101 |   Content extends HTMLElement
102 | >() {
103 |   const [overflow, setOverflow] = useState(false)
104 |   const containerRef = useRef<Container>()
105 |   const contentRef = useRef<Content>()
106 |   const layout = useFormLayout()
107 |   const labelCol = JSON.stringify(layout.labelCol)
108 | 
109 |   useEffect(() => {
110 |     requestAnimationFrame(() => {
111 |       if (containerRef.current && contentRef.current) {
112 |         const contentWidth = contentRef.current.getBoundingClientRect().width
113 |         const containerWidth =
114 |           containerRef.current.getBoundingClientRect().width
115 |         if (contentWidth && containerWidth && containerWidth < contentWidth) {
116 |           if (!overflow) setOverflow(true)
117 |         } else {
118 |           if (overflow) setOverflow(false)
119 |         }
120 |       }
121 |     })
122 |   }, [labelCol])
123 | 
124 |   return {
125 |     overflow,
126 |     containerRef,
127 |     contentRef,
128 |   }
129 | }
130 | 
131 | const ICON_MAP = {
132 |   error: <CloseCircleOutlined />,
133 |   success: <CheckCircleOutlined />,
134 |   warning: <ExclamationCircleOutlined />,
135 | }
136 | 
137 | export const BaseItem: React.FC<React.PropsWithChildren<IFormItemProps>> = ({
138 |   children,
139 |   ...props
140 | }) => {
141 |   const [active, setActive] = useState(false)
142 |   const formLayout = useFormItemLayout(props)
143 |   const { locale } = useContext(ConfigProvider.ConfigContext)
144 |   const { containerRef, contentRef, overflow } = useOverflow<
145 |     HTMLDivElement,
146 |     HTMLSpanElement
147 |   >()
148 |   const {
149 |     label,
150 |     style,
151 |     layout,
152 |     colon = true,
153 |     addonBefore,
154 |     addonAfter,
155 |     asterisk,
156 |     requiredMark = true,
157 |     optionalMarkHidden = false,
158 |     feedbackStatus,
159 |     extra,
160 |     feedbackText,
161 |     fullness,
162 |     feedbackLayout,
163 |     feedbackIcon,
164 |     enableOutlineFeedback = true,
165 |     getPopupContainer,
166 |     inset,
167 |     bordered = true,
168 |     labelWidth,
169 |     wrapperWidth,
170 |     labelCol,
171 |     wrapperCol,
172 |     labelAlign,
173 |     wrapperAlign = 'left',
174 |     size,
175 |     labelWrap,
176 |     wrapperWrap,
177 |     tooltipLayout,
178 |     tooltip,
179 |     tooltipIcon,
180 |   } = formLayout
181 |   const labelStyle = { ...formLayout.labelStyle }
182 |   const wrapperStyle = { ...formLayout.wrapperStyle }
183 |   // 固定宽度
184 |   let enableCol = false
185 |   if (labelWidth || wrapperWidth) {
186 |     if (labelWidth) {
187 |       labelStyle.width = labelWidth === 'auto' ? undefined : labelWidth
188 |       labelStyle.maxWidth = labelWidth === 'auto' ? undefined : labelWidth
189 |     }
190 |     if (wrapperWidth) {
191 |       wrapperStyle.width = wrapperWidth === 'auto' ? undefined : wrapperWidth
192 |       wrapperStyle.maxWidth = wrapperWidth === 'auto' ? undefined : wrapperWidth
193 |     }
194 |     // 栅格模式
195 |   }
196 |   if (labelCol || wrapperCol) {
197 |     if (!labelStyle.width && !wrapperStyle.width && layout !== 'vertical') {
198 |       enableCol = true
199 |     }
200 |   }
201 | 
202 |   const prefixCls = usePrefixCls('formily-item', props)
203 |   const formatChildren =
204 |     feedbackLayout === 'popover' ? (
205 |       <Popover
206 |         autoAdjustOverflow
207 |         placement="top"
208 |         content={
209 |           <div
210 |             className={cls({
211 |               [`${prefixCls}-${feedbackStatus}-help`]: !!feedbackStatus,
212 |               [`${prefixCls}-help`]: true,
213 |             })}
214 |           >
215 |             {ICON_MAP[feedbackStatus]} {feedbackText}
216 |           </div>
217 |         }
218 |         visible={!!feedbackText}
219 |         getPopupContainer={getPopupContainer}
220 |       >
221 |         {children}
222 |       </Popover>
223 |     ) : (
224 |       children
225 |     )
226 | 
227 |   const gridStyles: React.CSSProperties = {}
228 | 
229 |   const tooltipNode = isTooltipProps(tooltip) ? (
230 |     <Tooltip {...tooltip}></Tooltip>
231 |   ) : (
232 |     tooltip
233 |   )
234 | 
235 |   const getOverflowTooltip = () => {
236 |     if (overflow) {
237 |       return (
238 |         <div>
239 |           <div>{label}</div>
240 |           <div>{tooltipNode}</div>
241 |         </div>
242 |       )
243 |     }
244 |     return tooltipNode
245 |   }
246 | 
247 |   const renderLabelText = () => {
248 |     const labelChildren = (
249 |       <div className={`${prefixCls}-label-content`} ref={containerRef}>
250 |         <span ref={contentRef}>
251 |           {asterisk && requiredMark === true && (
252 |             <span className={`${prefixCls}-asterisk`}>{'*'}</span>
253 |           )}
254 |           <label htmlFor={props.labelFor}>{label}</label>
255 |           {!asterisk && requiredMark === 'optional' && !optionalMarkHidden && (
256 |             <span className={`${prefixCls}-optional`}>
257 |               {locale?.Form?.optional}
258 |             </span>
259 |           )}
260 |         </span>
261 |       </div>
262 |     )
263 | 
264 |     if ((tooltipLayout === 'text' && tooltip) || overflow) {
265 |       return (
266 |         <Tooltip
267 |           placement="top"
268 |           align={{ offset: [0, 10] }}
269 |           title={getOverflowTooltip()}
270 |         >
271 |           {labelChildren}
272 |         </Tooltip>
273 |       )
274 |     }
275 |     return labelChildren
276 |   }
277 | 
278 |   const renderTooltipIcon = () => {
279 |     if (tooltip && tooltipLayout === 'icon' && !overflow) {
280 |       return (
281 |         <span className={`${prefixCls}-label-tooltip-icon`}>
282 |           <Tooltip
283 |             placement="top"
284 |             align={{ offset: [0, 2] }}
285 |             title={tooltipNode}
286 |           >
287 |             {tooltipIcon}
288 |           </Tooltip>
289 |         </span>
290 |       )
291 |     }
292 |   }
293 | 
294 |   const renderLabel = () => {
295 |     if (!label) return null
296 |     return (
297 |       <div
298 |         className={cls({
299 |           [`${prefixCls}-label`]: true,
300 |           [`${prefixCls}-label-tooltip`]:
301 |             (tooltip && tooltipLayout === 'text') || overflow,
302 |           [`${prefixCls}-item-col-${labelCol}`]: enableCol && !!labelCol,
303 |         })}
304 |         style={labelStyle}
305 |       >
306 |         {renderLabelText()}
307 |         {renderTooltipIcon()}
308 |         {label !== ' ' && (
309 |           <span className={`${prefixCls}-colon`}>{colon ? ':' : ''}</span>
310 |         )}
311 |       </div>
312 |     )
313 |   }
314 | 
315 |   return (
316 |     <div
317 |       {...pickDataProps(props)}
318 |       style={{
319 |         ...style,
320 |         ...gridStyles,
321 |       }}
322 |       data-grid-span={props.gridSpan}
323 |       className={cls({
324 |         [`${prefixCls}`]: true,
325 |         [`${prefixCls}-layout-${layout}`]: true,
326 |         [`${prefixCls}-${feedbackStatus}`]:
327 |           enableOutlineFeedback && !!feedbackStatus,
328 |         [`${prefixCls}-feedback-has-text`]: !!feedbackText,
329 |         [`${prefixCls}-size-${size}`]: !!size,
330 |         [`${prefixCls}-feedback-layout-${feedbackLayout}`]: !!feedbackLayout,
331 |         [`${prefixCls}-fullness`]: !!fullness || !!inset || !!feedbackIcon,
332 |         [`${prefixCls}-inset`]: !!inset,
333 |         [`${prefixCls}-active`]: active,
334 |         [`${prefixCls}-inset-active`]: !!inset && active,
335 |         [`${prefixCls}-label-align-${labelAlign}`]: true,
336 |         [`${prefixCls}-control-align-${wrapperAlign}`]: true,
337 |         [`${prefixCls}-label-wrap`]: !!labelWrap,
338 |         [`${prefixCls}-control-wrap`]: !!wrapperWrap,
339 |         [`${prefixCls}-bordered-none`]:
340 |           bordered === false || !!inset || !!feedbackIcon,
341 |         [props.className]: !!props.className,
342 |       })}
343 |       onFocus={() => {
344 |         if (feedbackIcon || inset) {
345 |           setActive(true)
346 |         }
347 |       }}
348 |       onBlur={() => {
349 |         if (feedbackIcon || inset) {
350 |           setActive(false)
351 |         }
352 |       }}
353 |     >
354 |       {renderLabel()}
355 |       <div
356 |         className={cls({
357 |           [`${prefixCls}-control`]: true,
358 |           [`${prefixCls}-item-col-${wrapperCol}`]:
359 |             enableCol && !!wrapperCol && label,
360 |         })}
361 |       >
362 |         <div className={cls(`${prefixCls}-control-content`)}>
363 |           {addonBefore && (
364 |             <div className={cls(`${prefixCls}-addon-before`)}>
365 |               {addonBefore}
366 |             </div>
367 |           )}
368 |           <div
369 |             style={wrapperStyle}
370 |             className={cls({
371 |               [`${prefixCls}-control-content-component`]: true,
372 |               [`${prefixCls}-control-content-component-has-feedback-icon`]:
373 |                 !!feedbackIcon,
374 |             })}
375 |           >
376 |             <FormLayoutShallowContext.Provider value={undefined}>
377 |               {formatChildren}
378 |             </FormLayoutShallowContext.Provider>
379 |             {feedbackIcon && (
380 |               <div className={cls(`${prefixCls}-feedback-icon`)}>
381 |                 {feedbackIcon}
382 |               </div>
383 |             )}
384 |           </div>
385 |           {addonAfter && (
386 |             <div className={cls(`${prefixCls}-addon-after`)}>{addonAfter}</div>
387 |           )}
388 |         </div>
389 |         {!!feedbackText &&
390 |           feedbackLayout !== 'popover' &&
391 |           feedbackLayout !== 'none' && (
392 |             <div
393 |               className={cls({
394 |                 [`${prefixCls}-${feedbackStatus}-help`]: !!feedbackStatus,
395 |                 [`${prefixCls}-help`]: true,
396 |                 [`${prefixCls}-help-enter`]: true,
397 |                 [`${prefixCls}-help-enter-active`]: true,
398 |               })}
399 |             >
400 |               {feedbackText}
401 |             </div>
402 |           )}
403 |         {extra && <div className={cls(`${prefixCls}-extra`)}>{extra}</div>}
404 |       </div>
405 |     </div>
406 |   )
407 | }
408 | 
409 | // 适配
410 | export const FormItem: ComposeFormItem = connect(
411 |   BaseItem,
412 |   mapProps((props, field) => {
413 |     if (isVoidField(field))
414 |       return {
415 |         label: field.title || props.label,
416 |         asterisk: props.asterisk,
417 |         extra: props.extra || field.description,
418 |       }
419 |     if (!field) return props
420 |     const takeFeedbackStatus = () => {
421 |       if (field.validating) return 'pending'
422 |       return field.decoratorProps.feedbackStatus || field.validateStatus
423 |     }
424 |     const takeMessage = () => {
425 |       const split = (messages: any[]) => {
426 |         return messages.reduce((buf, text, index) => {
427 |           if (!text) return buf
428 |           return index < messages.length - 1
429 |             ? buf.concat([text, ', '])
430 |             : buf.concat([text])
431 |         }, [])
432 |       }
433 |       if (field.validating) return
434 |       if (props.feedbackText) return props.feedbackText
435 |       if (field.selfErrors.length) return split(field.selfErrors)
436 |       if (field.selfWarnings.length) return split(field.selfWarnings)
437 |       if (field.selfSuccesses.length) return split(field.selfSuccesses)
438 |     }
439 |     const takeAsterisk = () => {
440 |       if (field.required && field.pattern !== 'readPretty') {
441 |         return true
442 |       }
443 |       if ('asterisk' in props) {
444 |         return props.asterisk
445 |       }
446 |       return false
447 |     }
448 |     return {
449 |       label: props.label || field.title,
450 |       feedbackStatus: takeFeedbackStatus(),
451 |       feedbackText: takeMessage(),
452 |       asterisk: takeAsterisk(),
453 |       optionalMarkHidden:
454 |         field.pattern === 'readPretty' && !('asterisk' in props),
455 |       extra: props.extra || field.description,
456 |     }
457 |   })
458 | )
459 | 
460 | FormItem.BaseItem = BaseItem
461 | 
462 | export default FormItem
463 | 
```

--------------------------------------------------------------------------------
/packages/next/docs/components/ArrayCards.md:
--------------------------------------------------------------------------------

```markdown
  1 | # ArrayCards
  2 | 
  3 | > Card list, it is more suitable to use ArrayCards for scenarios with a large number of fields in each row and more linkages
  4 | >
  5 | > Note: This component is only applicable to Schema scenarios
  6 | 
  7 | ## Markup Schema example
  8 | 
  9 | ```tsx
 10 | import React from 'react'
 11 | import {
 12 |   FormItem,
 13 |   Input,
 14 |   ArrayCards,
 15 |   FormButtonGroup,
 16 |   Submit,
 17 | } from '@formily/next'
 18 | import { createForm } from '@formily/core'
 19 | import { FormProvider, createSchemaField } from '@formily/react'
 20 | 
 21 | const SchemaField = createSchemaField({
 22 |   components: {
 23 |     FormItem,
 24 |     Input,
 25 |     ArrayCards,
 26 |   },
 27 | })
 28 | 
 29 | const form = createForm()
 30 | 
 31 | export default () => {
 32 |   return (
 33 |     <FormProvider form={form}>
 34 |       <SchemaField>
 35 |         <SchemaField.Array
 36 |           name="string_array"
 37 |           maxItems={3}
 38 |           x-decorator="FormItem"
 39 |           x-component="ArrayCards"
 40 |           x-component-props={{
 41 |             title: 'String array',
 42 |           }}
 43 |         >
 44 |           <SchemaField.Void>
 45 |             <SchemaField.Void x-component="ArrayCards.Index" />
 46 |             <SchemaField.String
 47 |               name="input"
 48 |               x-decorator="FormItem"
 49 |               title="Input"
 50 |               required
 51 |               x-component="Input"
 52 |             />
 53 |             <SchemaField.Void x-component="ArrayCards.Remove" />
 54 |             <SchemaField.Void x-component="ArrayCards.Copy" />
 55 |             <SchemaField.Void x-component="ArrayCards.MoveUp" />
 56 |             <SchemaField.Void x-component="ArrayCards.MoveDown" />
 57 |           </SchemaField.Void>
 58 |           <SchemaField.Void
 59 |             x-component="ArrayCards.Addition"
 60 |             title="Add entry"
 61 |           />
 62 |         </SchemaField.Array>
 63 |         <SchemaField.Array
 64 |           name="array"
 65 |           maxItems={3}
 66 |           x-decorator="FormItem"
 67 |           x-component="ArrayCards"
 68 |           x-component-props={{
 69 |             title: 'Object array',
 70 |           }}
 71 |         >
 72 |           <SchemaField.Object>
 73 |             <SchemaField.Void x-component="ArrayCards.Index" />
 74 |             <SchemaField.String
 75 |               name="input"
 76 |               x-decorator="FormItem"
 77 |               title="Input"
 78 |               required
 79 |               x-component="Input"
 80 |             />
 81 |             <SchemaField.Void x-component="ArrayCards.Remove" />
 82 |             <SchemaField.Void x-component="ArrayCards.MoveUp" />
 83 |             <SchemaField.Void x-component="ArrayCards.MoveDown" />
 84 |           </SchemaField.Object>
 85 |           <SchemaField.Void
 86 |             x-component="ArrayCards.Addition"
 87 |             title="Add entry"
 88 |           />
 89 |         </SchemaField.Array>
 90 |       </SchemaField>
 91 |       <FormButtonGroup>
 92 |         <Submit onSubmit={console.log}>Submit</Submit>
 93 |       </FormButtonGroup>
 94 |     </FormProvider>
 95 |   )
 96 | }
 97 | ```
 98 | 
 99 | ## JSON Schema case
100 | 
101 | ```tsx
102 | import React from 'react'
103 | import {
104 |   FormItem,
105 |   Input,
106 |   ArrayCards,
107 |   FormButtonGroup,
108 |   Submit,
109 | } from '@formily/next'
110 | import { createForm } from '@formily/core'
111 | import { FormProvider, createSchemaField } from '@formily/react'
112 | 
113 | const SchemaField = createSchemaField({
114 |   components: {
115 |     FormItem,
116 |     Input,
117 |     ArrayCards,
118 |   },
119 | })
120 | 
121 | const form = createForm()
122 | 
123 | const schema = {
124 |   type: 'object',
125 |   properties: {
126 |     string_array: {
127 |       type: 'array',
128 |       'x-component': 'ArrayCards',
129 |       maxItems: 3,
130 |       'x-decorator': 'FormItem',
131 |       'x-component-props': {
132 |         title: 'String array',
133 |       },
134 |       items: {
135 |         type: 'void',
136 |         properties: {
137 |           index: {
138 |             type: 'void',
139 |             'x-component': 'ArrayCards.Index',
140 |           },
141 |           input: {
142 |             type: 'string',
143 |             'x-decorator': 'FormItem',
144 |             title: 'Input',
145 |             required: true,
146 |             'x-component': 'Input',
147 |           },
148 |           remove: {
149 |             type: 'void',
150 |             'x-component': 'ArrayCards.Remove',
151 |           },
152 |           moveUp: {
153 |             type: 'void',
154 |             'x-component': 'ArrayCards.MoveUp',
155 |           },
156 |           moveDown: {
157 |             type: 'void',
158 |             'x-component': 'ArrayCards.MoveDown',
159 |           },
160 |         },
161 |       },
162 |       properties: {
163 |         addition: {
164 |           type: 'void',
165 |           title: 'Add entry',
166 |           'x-component': 'ArrayCards.Addition',
167 |         },
168 |       },
169 |     },
170 |     array: {
171 |       type: 'array',
172 |       'x-component': 'ArrayCards',
173 |       maxItems: 3,
174 |       'x-decorator': 'FormItem',
175 |       'x-component-props': {
176 |         title: 'Object array',
177 |       },
178 |       items: {
179 |         type: 'object',
180 |         properties: {
181 |           index: {
182 |             type: 'void',
183 |             'x-component': 'ArrayCards.Index',
184 |           },
185 |           input: {
186 |             type: 'string',
187 |             'x-decorator': 'FormItem',
188 |             title: 'Input',
189 |             required: true,
190 |             'x-component': 'Input',
191 |           },
192 |           remove: {
193 |             type: 'void',
194 |             'x-component': 'ArrayCards.Remove',
195 |           },
196 |           moveUp: {
197 |             type: 'void',
198 |             'x-component': 'ArrayCards.MoveUp',
199 |           },
200 |           moveDown: {
201 |             type: 'void',
202 |             'x-component': 'ArrayCards.MoveDown',
203 |           },
204 |         },
205 |       },
206 |       properties: {
207 |         addition: {
208 |           type: 'void',
209 |           title: 'Add entry',
210 |           'x-component': 'ArrayCards.Addition',
211 |         },
212 |       },
213 |     },
214 |   },
215 | }
216 | 
217 | export default () => {
218 |   return (
219 |     <FormProvider form={form}>
220 |       <SchemaField schema={schema} />
221 |       <FormButtonGroup>
222 |         <Submit onSubmit={console.log}>Submit</Submit>
223 |       </FormButtonGroup>
224 |     </FormProvider>
225 |   )
226 | }
227 | ```
228 | 
229 | ## Effects linkage case
230 | 
231 | ```tsx
232 | import React from 'react'
233 | import {
234 |   FormItem,
235 |   Input,
236 |   ArrayCards,
237 |   FormButtonGroup,
238 |   Submit,
239 | } from '@formily/next'
240 | import { createForm, onFieldChange, onFieldReact } from '@formily/core'
241 | import { FormProvider, createSchemaField } from '@formily/react'
242 | 
243 | const SchemaField = createSchemaField({
244 |   components: {
245 |     FormItem,
246 |     Input,
247 |     ArrayCards,
248 |   },
249 | })
250 | 
251 | const form = createForm({
252 |   effects: () => {
253 |     //Active linkage mode
254 |     onFieldChange('array.*.aa', ['value'], (field, form) => {
255 |       form.setFieldState(field.query('.bb'), (state) => {
256 |         state.visible = field.value != '123'
257 |       })
258 |     })
259 |     //Passive linkage mode
260 |     onFieldReact('array.*.dd', (field) => {
261 |       field.visible = field.query('.cc').get('value') != '123'
262 |     })
263 |   },
264 | })
265 | 
266 | export default () => {
267 |   return (
268 |     <FormProvider form={form}>
269 |       <SchemaField>
270 |         <SchemaField.Array
271 |           name="array"
272 |           maxItems={3}
273 |           x-component="ArrayCards"
274 |           x-decorator="FormItem"
275 |           x-component-props={{
276 |             title: 'Object array',
277 |           }}
278 |         >
279 |           <SchemaField.Object>
280 |             <SchemaField.Void x-component="ArrayCards.Index" />
281 |             <SchemaField.String
282 |               name="aa"
283 |               x-decorator="FormItem"
284 |               title="AA"
285 |               required
286 |               description="AA hide BB when entering 123"
287 |               x-component="Input"
288 |             />
289 |             <SchemaField.String
290 |               name="bb"
291 |               x-decorator="FormItem"
292 |               title="BB"
293 |               required
294 |               x-component="Input"
295 |             />
296 |             <SchemaField.String
297 |               name="cc"
298 |               x-decorator="FormItem"
299 |               title="CC"
300 |               required
301 |               description="Hide DD when CC enters 123"
302 |               x-component="Input"
303 |             />
304 |             <SchemaField.String
305 |               name="dd"
306 |               x-decorator="FormItem"
307 |               title="DD"
308 |               required
309 |               x-component="Input"
310 |             />
311 |             <SchemaField.Void x-component="ArrayCards.Remove" />
312 |             <SchemaField.Void x-component="ArrayCards.MoveUp" />
313 |             <SchemaField.Void x-component="ArrayCards.MoveDown" />
314 |           </SchemaField.Object>
315 |           <SchemaField.Void
316 |             x-component="ArrayCards.Addition"
317 |             title="Add entry"
318 |           />
319 |         </SchemaField.Array>
320 |       </SchemaField>
321 |       <FormButtonGroup>
322 |         <Submit onSubmit={console.log}>Submit</Submit>
323 |       </FormButtonGroup>
324 |     </FormProvider>
325 |   )
326 | }
327 | ```
328 | 
329 | ## JSON Schema linkage case
330 | 
331 | ```tsx
332 | import React from 'react'
333 | import {
334 |   FormItem,
335 |   Input,
336 |   ArrayCards,
337 |   FormButtonGroup,
338 |   Submit,
339 | } from '@formily/next'
340 | import { createForm } from '@formily/core'
341 | import { FormProvider, createSchemaField } from '@formily/react'
342 | 
343 | const SchemaField = createSchemaField({
344 |   components: {
345 |     FormItem,
346 |     Input,
347 |     ArrayCards,
348 |   },
349 | })
350 | 
351 | const form = createForm()
352 | 
353 | const schema = {
354 |   type: 'object',
355 |   properties: {
356 |     array: {
357 |       type: 'array',
358 |       'x-component': 'ArrayCards',
359 |       maxItems: 3,
360 |       title: 'Object array',
361 |       items: {
362 |         type: 'object',
363 |         properties: {
364 |           index: {
365 |             type: 'void',
366 |             'x-component': 'ArrayCards.Index',
367 |           },
368 |           aa: {
369 |             type: 'string',
370 |             'x-decorator': 'FormItem',
371 |             title: 'AA',
372 |             required: true,
373 |             'x-component': 'Input',
374 |             description: 'Enter 123',
375 |           },
376 |           bb: {
377 |             type: 'string',
378 |             title: 'BB',
379 |             required: true,
380 |             'x-decorator': 'FormItem',
381 |             'x-component': 'Input',
382 |             'x-reactions': [
383 |               {
384 |                 dependencies: ['.aa'],
385 |                 when: "{{$deps[0] != '123'}}",
386 |                 fulfill: {
387 |                   schema: {
388 |                     title: 'BB',
389 |                     'x-disabled': true,
390 |                   },
391 |                 },
392 |                 otherwise: {
393 |                   schema: {
394 |                     title: 'Changed',
395 |                     'x-disabled': false,
396 |                   },
397 |                 },
398 |               },
399 |             ],
400 |           },
401 |           remove: {
402 |             type: 'void',
403 |             'x-component': 'ArrayCards.Remove',
404 |           },
405 |           moveUp: {
406 |             type: 'void',
407 |             'x-component': 'ArrayCards.MoveUp',
408 |           },
409 |           moveDown: {
410 |             type: 'void',
411 |             'x-component': 'ArrayCards.MoveDown',
412 |           },
413 |         },
414 |       },
415 |       properties: {
416 |         addition: {
417 |           type: 'void',
418 |           title: 'Add entry',
419 |           'x-component': 'ArrayCards.Addition',
420 |         },
421 |       },
422 |     },
423 |   },
424 | }
425 | 
426 | export default () => {
427 |   return (
428 |     <FormProvider form={form}>
429 |       <SchemaField schema={schema} />
430 |       <FormButtonGroup>
431 |         <Submit onSubmit={console.log}>Submit</Submit>
432 |       </FormButtonGroup>
433 |     </FormProvider>
434 |   )
435 | }
436 | ```
437 | 
438 | ## API
439 | 
440 | ### ArrayCards
441 | 
442 | Extended attributes
443 | 
444 | | Property name | Type                      | Description     | Default value |
445 | | ------------- | ------------------------- | --------------- | ------------- |
446 | | onAdd         | `(index: number) => void` | add method      |               |
447 | | onRemove      | `(index: number) => void` | remove method   |               |
448 | | onCopy        | `(index: number) => void` | copy method     |               |
449 | | onMoveUp      | `(index: number) => void` | moveUp method   |               |
450 | | onMoveDown    | `(index: number) => void` | moveDown method |               |
451 | 
452 | Other Reference https://fusion.design/pc/component/basic/card
453 | 
454 | ### ArrayCards.Addition
455 | 
456 | > Add button
457 | 
458 | Extended attributes
459 | 
460 | | Property name | Type                 | Description   | Default value |
461 | | ------------- | -------------------- | ------------- | ------------- |
462 | | title         | ReactText            | Copywriting   |               |
463 | | method        | `'push' \|'unshift'` | add method    | `'push'`      |
464 | | defaultValue  | `any`                | Default value |               |
465 | 
466 | Other references https://fusion.design/pc/component/basic/button
467 | 
468 | Note: The title attribute can receive the title mapping in the Field model, that is, uploading the title in the Field is also effective
469 | 
470 | ### ArrayCards.Copy
471 | 
472 | > Copy button
473 | 
474 | Extended attributes
475 | 
476 | | Property name | Type                 | Description | Default value |
477 | | ------------- | -------------------- | ----------- | ------------- |
478 | | title         | ReactText            | Copywriting |               |
479 | | method        | `'push' \|'unshift'` | add method  | `'push'`      |
480 | 
481 | Other references https://fusion.design/pc/component/basic/button
482 | 
483 | Note: The title attribute can receive the title mapping in the Field model, that is, uploading the title in the Field is also effective
484 | 
485 | ### ArrayCards.Remove
486 | 
487 | > Delete button
488 | 
489 | | Property name | Type      | Description | Default value |
490 | | ------------- | --------- | ----------- | ------------- |
491 | | title         | ReactText | Copywriting |               |
492 | 
493 | Other references https://ant.design/components/icon-cn/
494 | 
495 | Note: The title attribute can receive the title mapping in the Field model, that is, uploading the title in the Field is also effective
496 | 
497 | ### ArrayCards.MoveDown
498 | 
499 | > Move down button
500 | 
501 | | Property name | Type      | Description | Default value |
502 | | ------------- | --------- | ----------- | ------------- |
503 | | title         | ReactText | Copywriting |               |
504 | 
505 | Other references https://ant.design/components/icon-cn/
506 | 
507 | Note: The title attribute can receive the title mapping in the Field model, that is, uploading the title in the Field is also effective
508 | 
509 | ### ArrayCards.MoveUp
510 | 
511 | > Move up button
512 | 
513 | | Property name | Type      | Description | Default value |
514 | | ------------- | --------- | ----------- | ------------- |
515 | | title         | ReactText | Copywriting |               |
516 | 
517 | Other references https://ant.design/components/icon-cn/
518 | 
519 | Note: The title attribute can receive the title mapping in the Field model, that is, uploading the title in the Field is also effective
520 | 
521 | ### ArrayCards.Index
522 | 
523 | > Index Renderer
524 | 
525 | No attributes
526 | 
527 | ### ArrayCards.useIndex
528 | 
529 | > Read the React Hook of the current rendering row index
530 | 
531 | ### ArrayCards.useRecord
532 | 
533 | > Read the React Hook of the current rendering row
534 | 
```

--------------------------------------------------------------------------------
/packages/validator/src/__tests__/validator.spec.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import {
  2 |   validate,
  3 |   registerValidateRules,
  4 |   registerValidateFormats,
  5 |   setValidateLanguage,
  6 |   registerValidateMessageTemplateEngine,
  7 | } from '../index'
  8 | 
  9 | registerValidateRules({
 10 |   custom: (value) => (value === '123' ? 'custom error' : ''),
 11 |   customBool: () => false,
 12 |   customBool2: () => true,
 13 | })
 14 | 
 15 | registerValidateFormats({
 16 |   custom: /^[\u4e00-\u9fa5]+$/,
 17 | })
 18 | 
 19 | const hasError = (results: any, message?: string) => {
 20 |   if (!message) {
 21 |     return expect(results?.error?.[0]).not.toBeUndefined()
 22 |   }
 23 |   return expect(results?.error?.[0]).toEqual(message)
 24 | }
 25 | 
 26 | const noError = (results: any) => {
 27 |   return expect(results?.error?.[0]).toBeUndefined()
 28 | }
 29 | 
 30 | test('empty string validate', async () => {
 31 |   const results = await validate('', { required: true })
 32 |   expect(results).toEqual({
 33 |     error: ['The field value is required'],
 34 |     success: [],
 35 |     warning: [],
 36 |   })
 37 | })
 38 | 
 39 | test('empty array validate', async () => {
 40 |   const results = await validate([], { required: true })
 41 |   expect(results).toEqual({
 42 |     error: ['The field value is required'],
 43 |     success: [],
 44 |     warning: [],
 45 |   })
 46 |   noError(await validate([''], { required: true }))
 47 | })
 48 | 
 49 | test('empty object validate', async () => {
 50 |   const results = await validate({}, { required: true })
 51 |   expect(results).toEqual({
 52 |     error: ['The field value is required'],
 53 |     success: [],
 54 |     warning: [],
 55 |   })
 56 | })
 57 | 
 58 | test('empty number validate', async () => {
 59 |   const results = await validate(0, { required: true })
 60 |   expect(results).toEqual({
 61 |     error: [],
 62 |     success: [],
 63 |     warning: [],
 64 |   })
 65 | })
 66 | 
 67 | test('multi validate', async () => {
 68 |   const results = await validate('', {
 69 |     required: true,
 70 |     validator() {
 71 |       return 'validate error'
 72 |     },
 73 |   })
 74 |   expect(results).toEqual({
 75 |     error: ['The field value is required', 'validate error'],
 76 |     success: [],
 77 |     warning: [],
 78 |   })
 79 | })
 80 | 
 81 | test('message scope', async () => {
 82 |   const results = await validate(
 83 |     '',
 84 |     {
 85 |       required: true,
 86 |       validator() {
 87 |         return 'validate error {{name}}'
 88 |       },
 89 |     },
 90 |     {
 91 |       context: {
 92 |         name: 'scopeName',
 93 |       },
 94 |     }
 95 |   )
 96 |   expect(results).toEqual({
 97 |     error: ['The field value is required', 'validate error scopeName'],
 98 |     success: [],
 99 |     warning: [],
100 |   })
101 | })
102 | 
103 | test('first validate', async () => {
104 |   const results = await validate(
105 |     '',
106 |     {
107 |       required: true,
108 |       validator() {
109 |         return 'validate error'
110 |       },
111 |     },
112 |     {
113 |       validateFirst: true,
114 |     }
115 |   )
116 |   expect(results).toEqual({
117 |     error: ['The field value is required'],
118 |     success: [],
119 |     warning: [],
120 |   })
121 | })
122 | 
123 | test('custom validate results', async () => {
124 |   const results = await validate('', {
125 |     validator() {
126 |       return { type: 'error', message: 'validate error' }
127 |     },
128 |   })
129 |   expect(results).toEqual({
130 |     error: ['validate error'],
131 |     success: [],
132 |     warning: [],
133 |   })
134 | })
135 | 
136 | test('exception validate', async () => {
137 |   const results1 = await validate('', {
138 |     validator() {
139 |       throw new Error('validate error')
140 |     },
141 |   })
142 |   expect(results1).toEqual({
143 |     error: ['validate error'],
144 |     success: [],
145 |     warning: [],
146 |   })
147 | 
148 |   const results2 = await validate('', {
149 |     validator() {
150 |       throw 'custom string'
151 |     },
152 |   })
153 |   expect(results2).toEqual({
154 |     error: ['custom string'],
155 |     success: [],
156 |     warning: [],
157 |   })
158 | })
159 | 
160 | test('max/maxItems/maxLength/minItems/minLength/min/maximum/exclusiveMaximum/minimum/exclusiveMinimum/len', async () => {
161 |   hasError(await validate(6, { max: 5 }))
162 |   hasError(await validate(6, { maxLength: 5 }))
163 |   hasError(await validate(6, { maxItems: 5 }))
164 |   noError(await validate(5, { max: 5 }))
165 |   noError(await validate(5, { maxLength: 5 }))
166 |   noError(await validate(5, { maxItems: 5 }))
167 |   hasError(await validate([1, 2, 3, 4, 5, 6], { max: 5 }))
168 |   hasError(await validate([1, 2, 3, 4, 5, 6], { maxLength: 5 }))
169 |   hasError(await validate([1, 2, 3, 4, 5, 6], { maxItems: 5 }))
170 |   noError(await validate([1, 2, 3, 4, 5], { max: 5 }))
171 |   noError(await validate([1, 2, 3, 4, 5], { maxLength: 5 }))
172 |   noError(await validate([1, 2, 3, 4, 5], { maxItems: 5 }))
173 |   hasError(await validate('123456', { max: 5 }))
174 |   hasError(await validate('123456', { maxLength: 5 }))
175 |   hasError(await validate('123456', { maxItems: 5 }))
176 |   noError(await validate('12345', { max: 5 }))
177 |   noError(await validate('12345', { maxLength: 5 }))
178 |   noError(await validate('12345', { maxItems: 5 }))
179 |   hasError(await validate(2, { min: 3 }))
180 |   hasError(await validate(2, { minLength: 3 }))
181 |   hasError(await validate(2, { minItems: 3 }))
182 |   noError(await validate(3, { min: 3 }))
183 |   noError(await validate(3, { minLength: 3 }))
184 |   noError(await validate(3, { minItems: 3 }))
185 |   hasError(await validate([1, 2], { min: 3 }))
186 |   hasError(await validate([1, 2], { minLength: 3 }))
187 |   hasError(await validate([1, 2], { minItems: 3 }))
188 |   noError(await validate([1, 2, 3], { min: 3 }))
189 |   noError(await validate([1, 2, 3], { minLength: 3 }))
190 |   noError(await validate([1, 2, 3], { minItems: 3 }))
191 |   hasError(await validate('12', { min: 3 }))
192 |   hasError(await validate('12', { minLength: 3 }))
193 |   hasError(await validate('12', { minItems: 3 }))
194 |   noError(await validate('123', { min: 3 }))
195 |   noError(await validate('123', { minLength: 3 }))
196 |   noError(await validate('123', { minItems: 3 }))
197 | 
198 |   hasError(await validate(6, { maximum: 5 }))
199 |   noError(await validate(5, { maximum: 5 }))
200 |   hasError(await validate([1, 2, 3, 4, 5, 6], { maximum: 5 }))
201 |   noError(await validate([1, 2, 3, 4, 5], { maximum: 5 }))
202 |   hasError(await validate('123456', { maximum: 5 }))
203 |   noError(await validate('12345', { maximum: 5 }))
204 |   hasError(await validate(2, { minimum: 3 }))
205 |   noError(await validate(3, { minimum: 3 }))
206 |   hasError(await validate([1, 2], { minimum: 3 }))
207 |   noError(await validate([1, 2, 3], { minimum: 3 }))
208 |   hasError(await validate('12', { minimum: 3 }))
209 |   noError(await validate('123', { minimum: 3 }))
210 | 
211 |   hasError(await validate(6, { exclusiveMaximum: 5 }))
212 |   hasError(await validate(5, { exclusiveMaximum: 5 }))
213 |   hasError(await validate([1, 2, 3, 4, 5, 6], { exclusiveMaximum: 5 }))
214 |   hasError(await validate([1, 2, 3, 4, 5], { exclusiveMaximum: 5 }))
215 |   hasError(await validate('123456', { exclusiveMaximum: 5 }))
216 |   hasError(await validate('12345', { exclusiveMaximum: 5 }))
217 |   hasError(await validate(2, { exclusiveMinimum: 3 }))
218 |   hasError(await validate(3, { exclusiveMinimum: 3 }))
219 |   hasError(await validate([1, 2], { exclusiveMinimum: 3 }))
220 |   hasError(await validate([1, 2, 3], { exclusiveMinimum: 3 }))
221 |   hasError(await validate('12', { exclusiveMinimum: 3 }))
222 |   hasError(await validate('123', { exclusiveMinimum: 3 }))
223 | 
224 |   hasError(await validate('1234', { len: 3 }))
225 |   hasError(await validate({ aa: 1, bb: 2, cc: 3 }, { maxProperties: 2 }))
226 |   noError(await validate({ aa: 1, cc: 3 }, { maxProperties: 2 }))
227 |   hasError(await validate({ aa: 1 }, { minProperties: 2 }))
228 |   noError(await validate({ aa: 1, bb: 2, cc: 3 }, { minProperties: 2 }))
229 |   noError(await validate({ aa: 1, cc: 3 }, { maxProperties: 2 }))
230 | })
231 | 
232 | test('const', async () => {
233 |   noError(await validate('', { const: '123' }))
234 |   noError(await validate('123', { const: '123' }))
235 |   hasError(await validate('xxx', { const: '123' }))
236 | })
237 | 
238 | test('multipleOf', async () => {
239 |   noError(await validate('', { multipleOf: 2 }))
240 |   noError(await validate(4, { multipleOf: 2 }))
241 |   hasError(await validate(3, { multipleOf: 2 }))
242 | })
243 | 
244 | test('uniqueItems', async () => {
245 |   noError(await validate('', { uniqueItems: true }))
246 |   noError(await validate(4, { uniqueItems: true }))
247 |   hasError(await validate([1, 2], { uniqueItems: true }))
248 |   hasError(
249 |     await validate([{ label: '11', value: '11' }, { label: '11' }], {
250 |       uniqueItems: true,
251 |     })
252 |   )
253 |   noError(await validate([1, 1], { uniqueItems: true }))
254 |   noError(
255 |     await validate(
256 |       [
257 |         { label: '11', value: '11' },
258 |         { label: '11', value: '11' },
259 |       ],
260 |       { uniqueItems: true }
261 |     )
262 |   )
263 | })
264 | 
265 | test('pattern', async () => {
266 |   hasError(await validate('aaa', { pattern: /^\d+$/ }))
267 | })
268 | 
269 | test('validator', async () => {
270 |   hasError(
271 |     await validate('aaa', {
272 |       validator() {
273 |         return false
274 |       },
275 |       message: 'error',
276 |     }),
277 |     'error'
278 |   )
279 | })
280 | 
281 | test('whitespace', async () => {
282 |   hasError(
283 |     await validate(' ', {
284 |       whitespace: true,
285 |     })
286 |   )
287 | })
288 | 
289 | test('enum', async () => {
290 |   hasError(
291 |     await validate('11', {
292 |       enum: ['22', '33'],
293 |     })
294 |   )
295 |   noError(
296 |     await validate('11', {
297 |       enum: ['22', '33', '11'],
298 |     })
299 |   )
300 | })
301 | 
302 | test('filter trigger type(unmatch)', async () => {
303 |   expect(
304 |     await validate(
305 |       '',
306 |       {
307 |         triggerType: 'onBlur',
308 |         required: true,
309 |         validator() {
310 |           return 'validate error'
311 |         },
312 |       },
313 |       {
314 |         validateFirst: true,
315 |         triggerType: 'onInput',
316 |       }
317 |     )
318 |   ).toEqual({
319 |     error: [],
320 |     success: [],
321 |     warning: [],
322 |   })
323 | })
324 | 
325 | test('filter trigger type(match first validate)', async () => {
326 |   expect(
327 |     await validate(
328 |       '',
329 |       {
330 |         triggerType: 'onBlur',
331 |         required: true,
332 |         validator() {
333 |           return 'validate error'
334 |         },
335 |       },
336 |       {
337 |         validateFirst: true,
338 |         triggerType: 'onBlur',
339 |       }
340 |     )
341 |   ).toEqual({
342 |     error: ['The field value is required'],
343 |     success: [],
344 |     warning: [],
345 |   })
346 | })
347 | 
348 | test('filter trigger type(match multi validate)', async () => {
349 |   expect(
350 |     await validate(
351 |       '',
352 |       {
353 |         triggerType: 'onBlur',
354 |         required: true,
355 |         validator() {
356 |           return 'validate error'
357 |         },
358 |       },
359 |       {
360 |         triggerType: 'onBlur',
361 |       }
362 |     )
363 |   ).toEqual({
364 |     error: ['The field value is required', 'validate error'],
365 |     success: [],
366 |     warning: [],
367 |   })
368 | })
369 | 
370 | test('validate formats(date)', async () => {
371 |   noError(await validate('', 'date'))
372 |   hasError(await validate('2020-1', 'date'))
373 |   hasError(await validate('2020-01- 11:23:33', 'date'))
374 |   hasError(await validate('12/01/', 'date'))
375 |   noError(await validate('2020-1-12', 'date'))
376 |   noError(await validate('2020/1/12', 'date'))
377 |   noError(await validate('2020-01-12', 'date'))
378 |   noError(await validate('2020/01/12', 'date'))
379 |   noError(await validate('12/01/2020', 'date'))
380 |   noError(await validate('2020-01-12 11:23:33', 'date'))
381 |   noError(await validate('2020/01/12 11:23:33', 'date'))
382 |   noError(await validate('12/01/2020 11:23:33', 'date'))
383 |   noError(await validate('12/1/2020 11:23:33', 'date'))
384 | })
385 | 
386 | test('validate formats(number)', async () => {
387 |   noError(await validate('', 'number'))
388 |   hasError(await validate('12323d', 'number'))
389 |   noError(await validate('12323', 'number'))
390 |   noError(await validate('12323.12', 'number'))
391 |   noError(await validate('-12323.12', 'number'))
392 |   noError(await validate('+12323.12', 'number'))
393 | })
394 | 
395 | test('validate formats(integer)', async () => {
396 |   noError(await validate('', 'integer'))
397 |   hasError(await validate('222.333', 'integer'))
398 |   noError(await validate('12323', 'integer'))
399 | })
400 | 
401 | test('validate formats(phone)', async () => {
402 |   noError(await validate('', 'phone'))
403 |   hasError(await validate('222333', 'phone'))
404 |   noError(await validate('15934567899', 'phone'))
405 | })
406 | 
407 | test('validate formats(money)', async () => {
408 |   noError(await validate('$12', 'money'))
409 |   hasError(await validate('$12.', 'money'))
410 |   noError(await validate('$12.3', 'money'))
411 | })
412 | 
413 | test('validate custom validator', async () => {
414 |   hasError(await validate('123', { custom: true }))
415 |   noError(await validate('', { custom: true }))
416 | })
417 | 
418 | test('validate custom formats', async () => {
419 |   hasError(await validate('aa asd', 'custom'))
420 |   hasError(await validate('aa asd 中文', 'custom'))
421 |   noError(await validate('中文', 'custom'))
422 | })
423 | 
424 | test('validate undefined format', async () => {
425 |   expect(
426 |     (
427 |       await validate('a', {
428 |         required: false,
429 |         pattern: '(\\d{3,4}-\\d{7,8}-\\d{4})|(4\\d{4,9})|(\\d{3,4}-\\d{7,8})',
430 |         format: undefined,
431 |         message: 'error',
432 |       })
433 |     ).error
434 |   ).toEqual(['error'])
435 | })
436 | 
437 | test('validator return boolean', async () => {
438 |   hasError(
439 |     await validate('123', {
440 |       customBool: true,
441 |       message: 'custom error',
442 |     }),
443 |     'custom error'
444 |   )
445 |   noError(
446 |     await validate('123', {
447 |       customBool2: true,
448 |       message: 'custom error',
449 |     })
450 |   )
451 | })
452 | 
453 | test('language', async () => {
454 |   setValidateLanguage('zh-CN')
455 |   hasError(
456 |     await validate('', {
457 |       required: true,
458 |     }),
459 |     '该字段是必填字段'
460 |   )
461 |   setValidateLanguage('en-US')
462 |   hasError(
463 |     await validate('', {
464 |       required: true,
465 |     }),
466 |     'The field value is required'
467 |   )
468 | })
469 | 
470 | test('validator template', async () => {
471 |   registerValidateMessageTemplateEngine((message) => {
472 |     if (typeof message !== 'string') return message
473 |     return message.replace(/\<\<\s*([\w.]+)\s*\>\>/g, (_, $0) => {
474 |       return { aa: 123 }[$0]
475 |     })
476 |   })
477 |   hasError(
478 |     await validate('', () => {
479 |       return `<<aa>>=123`
480 |     }),
481 |     '123=123'
482 |   )
483 | })
484 | 
485 | test('validator template with format', async () => {
486 |   registerValidateMessageTemplateEngine((message) => {
487 |     if (typeof message !== 'string') return message
488 |     return message.replace(/\<\<\s*([\w.]+)\s*\>\>/g, (_, $0) => {
489 |       return { aa: 123 }[$0]
490 |     })
491 |   })
492 |   hasError(
493 |     await validate('', (value, rules, ctx, format) => {
494 |       return `<<aa>>=123&${format('<<aa>>')}`
495 |     }),
496 |     '123=123&123'
497 |   )
498 | })
499 | 
500 | test('validator template with format and scope', async () => {
501 |   registerValidateMessageTemplateEngine((message) => {
502 |     if (typeof message !== 'string') return message
503 |     return message.replace(/\<\<\s*([\w.]+)\s*\>\>/g, (_, $0) => {
504 |       return { aa: 123 }[$0]
505 |     })
506 |   })
507 | 
508 |   const result = await validate(
509 |     '',
510 |     (value, rules, ctx, format) => {
511 |       return `<<aa>>=123&${format('<<aa>>{{name}}')}`
512 |     },
513 |     {
514 |       context: {
515 |         name: 'scopeName',
516 |       },
517 |     }
518 |   )
519 | 
520 |   expect(result.error[0]).toEqual('123=123&123scopeName')
521 | })
522 | 
523 | test('validator order with format', async () => {
524 |   hasError(
525 |     await validate('', [
526 |       { required: true },
527 |       {
528 |         format: 'url',
529 |       },
530 |     ]),
531 |     'The field value is required'
532 |   )
533 | })
534 | 
```

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

```markdown
  1 | # Form Controlled
  2 | 
  3 | Formily 2.x has given up supporting controlled mode for form components and field components. Because the internal management state mode of the form itself is not a controlled mode, there will be many boundary problems in the process of changing the controlled mode to the uncontrolled mode. At the same time, the controlled mode will have a large number of dirty inspection processes, and the performance is very poor. Instead, the controlled mode itself can solve most of the problems.
  4 | 
  5 | So Formily no longer supports the controlled mode, but if we insist on implementing ordinary React controlled, we can still support it. It can only achieve value control, not field-level control, which is the Field component we use. The properties will only take effect during the first rendering. Any changes to the properties in the future will not be automatically updated. If you want to update automatically, unless you recreate the Form instance (obviously this will lose all the previously maintained state).
  6 | 
  7 | Therefore, we more recommend using [@formily/reactive](https://reactive.formilyjs.org) to achieve responsive control, which can achieve both value control and field-level control.
  8 | 
  9 | ## Value Controlled
 10 | 
 11 | Ordinary controlled mode, which will rely heavily on dirty checking to achieve data synchronization, and the number of component renderings will be very high.
 12 | 
 13 | ```tsx
 14 | import React, { useMemo, useState, useEffect, useRef } from 'react'
 15 | import { createForm, onFormValuesChange } from '@formily/core'
 16 | import { createSchemaField } from '@formily/react'
 17 | import { Form, FormItem, Input } from '@formily/antd'
 18 | 
 19 | const SchemaField = createSchemaField({
 20 |   components: {
 21 |     Input,
 22 |     FormItem,
 23 |   },
 24 | })
 25 | 
 26 | const MyForm = (props) => {
 27 |   const form = useMemo(
 28 |     () =>
 29 |       createForm({
 30 |         values: props.values,
 31 |         effects: () => {
 32 |           onFormValuesChange((form) => {
 33 |             props.onChange(form.values)
 34 |           })
 35 |         },
 36 |       }),
 37 |     []
 38 |   )
 39 |   const count = useRef(1)
 40 | 
 41 |   useEffect(() => {
 42 |     form.setValues(props.values, 'overwrite')
 43 |   }, [JSON.stringify(props.values)])
 44 | 
 45 |   return (
 46 |     <Form form={form}>
 47 |       <SchemaField>
 48 |         <SchemaField.String
 49 |           name="input"
 50 |           x-decorator="FormItem"
 51 |           x-component="Input"
 52 |           x-component-props={{ placeholder: 'controlled target' }}
 53 |         />
 54 |       </SchemaField>
 55 |       Form component rendering times:{count.current++}
 56 |     </Form>
 57 |   )
 58 | }
 59 | 
 60 | export default () => {
 61 |   const [values, setValues] = useState({ input: '' })
 62 |   const count = useRef(1)
 63 |   return (
 64 |     <>
 65 |       <FormItem>
 66 |         <Input
 67 |           value={values.input}
 68 |           placeholder="controller"
 69 |           onChange={(event) => {
 70 |             setValues({ ...values, input: event.target.value })
 71 |           }}
 72 |         />
 73 |       </FormItem>
 74 |       <MyForm
 75 |         values={values}
 76 |         onChange={(values) => {
 77 |           setValues({ ...values })
 78 |         }}
 79 |       />
 80 |       root component rendering times: {count.current++}
 81 |     </>
 82 |   )
 83 | }
 84 | ```
 85 | 
 86 | ## Responsive Value Controlled
 87 | 
 88 | Responsive control is mainly to use [@formily/reactive](https://reactive.formilyjs.org) to achieve responsive updates, we can easily achieve two-way binding, while the performance is full of normal controlled updates.
 89 | 
 90 | ```tsx
 91 | import React, { useMemo, useRef } from 'react'
 92 | import { createForm } from '@formily/core'
 93 | import { createSchemaField } from '@formily/react'
 94 | import { Form, FormItem, Input } from '@formily/antd'
 95 | import { observable } from '@formily/reactive'
 96 | import { observer } from '@formily/reactive-react'
 97 | 
 98 | const SchemaField = createSchemaField({
 99 |   components: {
100 |     Input,
101 |     FormItem,
102 |   },
103 | })
104 | 
105 | const MyForm = (props) => {
106 |   const count = useRef(1)
107 |   const form = useMemo(
108 |     () =>
109 |       createForm({
110 |         values: props.values,
111 |       }),
112 |     []
113 |   )
114 | 
115 |   return (
116 |     <Form form={form}>
117 |       <SchemaField>
118 |         <SchemaField.String
119 |           name="input"
120 |           x-decorator="FormItem"
121 |           x-component="Input"
122 |           x-component-props={{ placeholder: 'controlled target' }}
123 |         />
124 |       </SchemaField>
125 |       Form component rendering times:{count.current++}
126 |     </Form>
127 |   )
128 | }
129 | 
130 | const Controller = observer((props) => {
131 |   const count = useRef(1)
132 |   return (
133 |     <FormItem>
134 |       <Input
135 |         value={props.values.input}
136 |         placeholder="controller"
137 |         onChange={(event) => {
138 |           props.values.input = event.target.value
139 |         }}
140 |       />
141 |       Controller component rendering times:{count.current++}
142 |     </FormItem>
143 |   )
144 | })
145 | 
146 | export default () => {
147 |   const count = useRef(1)
148 |   const values = useMemo(() =>
149 |     observable({
150 |       input: '',
151 |     })
152 |   )
153 |   return (
154 |     <>
155 |       <Controller values={values} />
156 |       <MyForm values={values} />
157 |       root component rendering times:{count.current++}
158 |     </>
159 |   )
160 | }
161 | ```
162 | 
163 | ## Schema Controlled
164 | 
165 | There will be a requirement for the form configuration scenario. The Schema of the form will change frequently. In fact, it is equivalent to frequently creating new forms. The state of the previous operation should be discarded.
166 | 
167 | ```tsx
168 | import React, { useMemo, useState } from 'react'
169 | import { createForm } from '@formily/core'
170 | import { createSchemaField } from '@formily/react'
171 | import { Form, FormItem, Input, Select } from '@formily/antd'
172 | import { Button, Space } from 'antd'
173 | 
174 | const SchemaField = createSchemaField({
175 |   components: {
176 |     Input,
177 |     FormItem,
178 |     Select,
179 |   },
180 | })
181 | 
182 | export default () => {
183 |   const [current, setCurrent] = useState({})
184 |   const form = useMemo(() => createForm(), [current])
185 |   return (
186 |     <Form form={form} layout="vertical">
187 |       <Space style={{ marginBottom: 20 }}>
188 |         <Button
189 |           onClick={() => {
190 |             setCurrent({
191 |               type: 'object',
192 |               properties: {
193 |                 aa: {
194 |                   type: 'string',
195 |                   title: 'AA',
196 |                   'x-decorator': 'FormItem',
197 |                   'x-component': 'Input',
198 |                   'x-component-props': {
199 |                     placeholder: 'Input',
200 |                   },
201 |                 },
202 |               },
203 |             })
204 |           }}
205 |         >
206 |           Schema1
207 |         </Button>
208 |         <Button
209 |           onClick={() => {
210 |             setCurrent({
211 |               type: 'object',
212 |               properties: {
213 |                 aa: {
214 |                   type: 'string',
215 |                   title: 'AA',
216 |                   'x-decorator': 'FormItem',
217 |                   enum: [
218 |                     {
219 |                       label: '111',
220 |                       value: '111',
221 |                     },
222 |                     { label: '222', value: '222' },
223 |                   ],
224 |                   'x-component': 'Select',
225 |                   'x-component-props': {
226 |                     placeholder: 'Select',
227 |                   },
228 |                 },
229 |                 bb: {
230 |                   type: 'string',
231 |                   title: 'BB',
232 |                   'x-decorator': 'FormItem',
233 |                   'x-component': 'Input',
234 |                 },
235 |               },
236 |             })
237 |           }}
238 |         >
239 |           Schema2
240 |         </Button>
241 |       </Space>
242 |       <SchemaField schema={current} />
243 |     </Form>
244 |   )
245 | }
246 | ```
247 | 
248 | ## Schema fragment linkage (top level control)
249 | 
250 | The most important thing for fragment linkage is to manually clean up the field model, otherwise the UI cannot be synchronized
251 | 
252 | ```tsx
253 | import React, { useMemo, useRef } from 'react'
254 | import { createForm } from '@formily/core'
255 | import { createSchemaField, observer } from '@formily/react'
256 | import { Form, FormItem, Input, Select } from '@formily/antd'
257 | 
258 | const SchemaField = createSchemaField({
259 |   components: {
260 |     Input,
261 |     FormItem,
262 |     Select,
263 |   },
264 | })
265 | 
266 | const DYNAMIC_INJECT_SCHEMA = {
267 |   type_1: {
268 |     type: 'void',
269 |     properties: {
270 |       aa: {
271 |         type: 'string',
272 |         title: 'AA',
273 |         'x-decorator': 'FormItem',
274 |         'x-component': 'Input',
275 |         'x-component-props': {
276 |           placeholder: 'Input',
277 |         },
278 |       },
279 |     },
280 |   },
281 |   type_2: {
282 |     type: 'void',
283 |     properties: {
284 |       aa: {
285 |         type: 'string',
286 |         title: 'AA',
287 |         'x-decorator': 'FormItem',
288 |         enum: [
289 |           {
290 |             label: '111',
291 |             value: '111',
292 |           },
293 |           { label: '222', value: '222' },
294 |         ],
295 |         'x-component': 'Select',
296 |         'x-component-props': {
297 |           placeholder: 'Select',
298 |         },
299 |       },
300 |       bb: {
301 |         type: 'string',
302 |         title: 'BB',
303 |         'x-decorator': 'FormItem',
304 |         'x-component': 'Input',
305 |       },
306 |     },
307 |   },
308 | }
309 | 
310 | const App = observer(() => {
311 |   const oldTypeRef = useRef()
312 |   const form = useMemo(() => createForm(), [])
313 |   const currentType = form.values.type
314 |   const schema = {
315 |     type: 'object',
316 |     properties: {
317 |       type: {
318 |         type: 'string',
319 |         title: 'Type',
320 |         enum: [
321 |           { label: 'type 1', value: 'type_1' },
322 |           { label: 'type 2', value: 'type_2' },
323 |         ],
324 |         'x-decorator': 'FormItem',
325 |         'x-component': 'Select',
326 |       },
327 |       container: DYNAMIC_INJECT_SCHEMA[currentType],
328 |     },
329 |   }
330 | 
331 |   if (oldTypeRef.current !== currentType) {
332 |     form.clearFormGraph('container.*') //Recycle field model
333 |   }
334 | 
335 |   oldTypeRef.current = currentType
336 | 
337 |   return (
338 |     <Form form={form} layout="vertical">
339 |       <SchemaField schema={schema} />
340 |     </Form>
341 |   )
342 | })
343 | 
344 | export default App
345 | ```
346 | 
347 | ## Schema fragment linkage (custom component)
348 | 
349 | ```tsx
350 | import React, { useMemo, useState, useEffect } from 'react'
351 | import { createForm } from '@formily/core'
352 | import {
353 |   createSchemaField,
354 |   RecursionField,
355 |   useForm,
356 |   useField,
357 |   observer,
358 | } from '@formily/react'
359 | import { Form, FormItem, Input, Select } from '@formily/antd'
360 | 
361 | const Custom = observer(() => {
362 |   const field = useField()
363 |   const form = useForm()
364 |   const [schema, setSchema] = useState({})
365 | 
366 |   useEffect(() => {
367 |     form.clearFormGraph(`${field.address}.*`) //Recycle field model
368 |     //Can be obtained asynchronously
369 |     setSchema(DYNAMIC_INJECT_SCHEMA[form.values.type])
370 |   }, [form.values.type])
371 | 
372 |   return (
373 |     <RecursionField
374 |       basePath={field.address}
375 |       schema={schema}
376 |       onlyRenderProperties
377 |     />
378 |   )
379 | })
380 | 
381 | const SchemaField = createSchemaField({
382 |   components: {
383 |     Input,
384 |     FormItem,
385 |     Select,
386 |     Custom,
387 |   },
388 | })
389 | 
390 | const DYNAMIC_INJECT_SCHEMA = {
391 |   type_1: {
392 |     type: 'void',
393 |     properties: {
394 |       aa: {
395 |         type: 'string',
396 |         title: 'AA',
397 |         'x-decorator': 'FormItem',
398 |         'x-component': 'Input',
399 |         'x-component-props': {
400 |           placeholder: 'Input',
401 |         },
402 |       },
403 |     },
404 |   },
405 |   type_2: {
406 |     type: 'void',
407 |     properties: {
408 |       aa: {
409 |         type: 'string',
410 |         title: 'AA',
411 |         'x-decorator': 'FormItem',
412 |         enum: [
413 |           {
414 |             label: '111',
415 |             value: '111',
416 |           },
417 |           { label: '222', value: '222' },
418 |         ],
419 |         'x-component': 'Select',
420 |         'x-component-props': {
421 |           placeholder: 'Select',
422 |         },
423 |       },
424 |       bb: {
425 |         type: 'string',
426 |         title: 'BB',
427 |         'x-decorator': 'FormItem',
428 |         'x-component': 'Input',
429 |       },
430 |     },
431 |   },
432 | }
433 | 
434 | const App = observer(() => {
435 |   const form = useMemo(() => createForm(), [])
436 |   const schema = {
437 |     type: 'object',
438 |     properties: {
439 |       type: {
440 |         type: 'string',
441 |         title: 'Type',
442 |         enum: [
443 |           { label: 'type 1', value: 'type_1' },
444 |           { label: 'type 2', value: 'type_2' },
445 |         ],
446 |         'x-decorator': 'FormItem',
447 |         'x-component': 'Select',
448 |       },
449 |       container: {
450 |         type: 'object',
451 |         'x-component': 'Custom',
452 |       },
453 |     },
454 |   }
455 | 
456 |   return (
457 |     <Form form={form} layout="vertical">
458 |       <SchemaField schema={schema} />
459 |     </Form>
460 |   )
461 | })
462 | 
463 | export default App
464 | ```
465 | 
466 | ## Field Level Control
467 | 
468 | ### Best Practices
469 | 
470 | It is recommended to use [@formily/reactive](https://reactive.formilyjs.org) to achieve responsive control.
471 | 
472 | ```tsx
473 | import React from 'react'
474 | import { createForm } from '@formily/core'
475 | import { createSchemaField } from '@formily/react'
476 | import { Form, FormItem, Input } from '@formily/antd'
477 | import { observable } from '@formily/reactive'
478 | import { observer } from '@formily/reactive-react'
479 | 
480 | const SchemaField = createSchemaField({
481 |   components: {
482 |     Input,
483 |     FormItem,
484 |   },
485 | })
486 | 
487 | const form = createForm()
488 | 
489 | const obs = observable({
490 |   input: '',
491 | })
492 | 
493 | const Controller = observer(() => {
494 |   return (
495 |     <FormItem>
496 |       <Input
497 |         value={obs.input}
498 |         placeholder="controller"
499 |         onChange={(event) => {
500 |           obs.input = event.target.value
501 |         }}
502 |       />
503 |     </FormItem>
504 |   )
505 | })
506 | 
507 | export default () => {
508 |   return (
509 |     <>
510 |       <Controller />
511 |       <Form form={form}>
512 |         <SchemaField>
513 |           <SchemaField.String
514 |             name="input"
515 |             x-decorator="FormItem"
516 |             x-component="Input"
517 |             x-component-props={{ placeholder: 'controlled target' }}
518 |             x-reactions={(field) => {
519 |               field.component[1].placeholder = obs.input || 'controlled target'
520 |             }}
521 |           />
522 |         </SchemaField>
523 |       </Form>
524 |     </>
525 |   )
526 | }
527 | ```
528 | 
529 | ### Anti-pattern
530 | 
531 | It is not possible to update automatically when using traditional controlled mode.
532 | 
533 | ```tsx
534 | import React, { useState } from 'react'
535 | import { createForm } from '@formily/core'
536 | import { createSchemaField } from '@formily/react'
537 | import { Form, FormItem, Input } from '@formily/antd'
538 | 
539 | const SchemaField = createSchemaField({
540 |   components: {
541 |     Input,
542 |     FormItem,
543 |   },
544 | })
545 | 
546 | const form = createForm()
547 | 
548 | export default () => {
549 |   const [value, setValue] = useState('')
550 |   return (
551 |     <>
552 |       <FormItem>
553 |         <Input
554 |           value={value}
555 |           placeholder="controller"
556 |           onChange={(event) => {
557 |             setValue(event.target.value)
558 |           }}
559 |         />
560 |       </FormItem>
561 |       <Form form={form}>
562 |         <SchemaField>
563 |           <SchemaField.String
564 |             name="input"
565 |             x-decorator="FormItem"
566 |             x-component="Input"
567 |             x-component-props={{ placeholder: value || 'controlled target' }}
568 |           />
569 |         </SchemaField>
570 |       </Form>
571 |     </>
572 |   )
573 | }
574 | ```
575 | 
```

--------------------------------------------------------------------------------
/packages/antd/docs/components/ArrayCards.md:
--------------------------------------------------------------------------------

```markdown
  1 | # ArrayCards
  2 | 
  3 | > Card list, it is more suitable to use ArrayCards for scenarios with a large number of fields in each row and more linkages
  4 | >
  5 | > Note: This component is only applicable to Schema scenarios
  6 | 
  7 | ## Markup Schema example
  8 | 
  9 | ```tsx
 10 | import React from 'react'
 11 | import {
 12 |   FormItem,
 13 |   Input,
 14 |   ArrayCards,
 15 |   FormButtonGroup,
 16 |   Submit,
 17 | } from '@formily/antd'
 18 | import { createForm } from '@formily/core'
 19 | import { FormProvider, createSchemaField } from '@formily/react'
 20 | 
 21 | const SchemaField = createSchemaField({
 22 |   components: {
 23 |     FormItem,
 24 |     Input,
 25 |     ArrayCards,
 26 |   },
 27 | })
 28 | 
 29 | const form = createForm()
 30 | 
 31 | export default () => {
 32 |   return (
 33 |     <FormProvider form={form}>
 34 |       <SchemaField>
 35 |         <SchemaField.Array
 36 |           name="string_array"
 37 |           maxItems={3}
 38 |           x-decorator="FormItem"
 39 |           x-component="ArrayCards"
 40 |           x-component-props={{
 41 |             title: 'String array',
 42 |           }}
 43 |         >
 44 |           <SchemaField.Void>
 45 |             <SchemaField.Void x-component="ArrayCards.Index" />
 46 |             <SchemaField.String
 47 |               name="input"
 48 |               x-decorator="FormItem"
 49 |               title="Input"
 50 |               required
 51 |               x-component="Input"
 52 |             />
 53 |             <SchemaField.Void x-component="ArrayCards.Remove" />
 54 |             <SchemaField.Void x-component="ArrayCards.Copy" />
 55 |             <SchemaField.Void x-component="ArrayCards.MoveUp" />
 56 |             <SchemaField.Void x-component="ArrayCards.MoveDown" />
 57 |           </SchemaField.Void>
 58 |           <SchemaField.Void
 59 |             x-component="ArrayCards.Addition"
 60 |             title="Add entry"
 61 |           />
 62 |         </SchemaField.Array>
 63 |         <SchemaField.Array
 64 |           name="array"
 65 |           maxItems={3}
 66 |           x-decorator="FormItem"
 67 |           x-component="ArrayCards"
 68 |           x-component-props={{
 69 |             title: 'Object array',
 70 |           }}
 71 |         >
 72 |           <SchemaField.Object>
 73 |             <SchemaField.Void x-component="ArrayCards.Index" />
 74 |             <SchemaField.String
 75 |               name="input"
 76 |               x-decorator="FormItem"
 77 |               title="Input"
 78 |               required
 79 |               x-component="Input"
 80 |             />
 81 |             <SchemaField.Void x-component="ArrayCards.Remove" />
 82 |             <SchemaField.Void x-component="ArrayCards.MoveUp" />
 83 |             <SchemaField.Void x-component="ArrayCards.MoveDown" />
 84 |           </SchemaField.Object>
 85 |           <SchemaField.Void
 86 |             x-component="ArrayCards.Addition"
 87 |             title="Add entry"
 88 |           />
 89 |         </SchemaField.Array>
 90 |       </SchemaField>
 91 |       <FormButtonGroup>
 92 |         <Submit onSubmit={console.log}>Submit</Submit>
 93 |       </FormButtonGroup>
 94 |     </FormProvider>
 95 |   )
 96 | }
 97 | ```
 98 | 
 99 | ## JSON Schema case
100 | 
101 | ```tsx
102 | import React from 'react'
103 | import {
104 |   FormItem,
105 |   Input,
106 |   ArrayCards,
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 |     FormItem,
116 |     Input,
117 |     ArrayCards,
118 |   },
119 | })
120 | 
121 | const form = createForm()
122 | 
123 | const schema = {
124 |   type: 'object',
125 |   properties: {
126 |     string_array: {
127 |       type: 'array',
128 |       'x-component': 'ArrayCards',
129 |       maxItems: 3,
130 |       'x-decorator': 'FormItem',
131 |       'x-component-props': {
132 |         title: 'String array',
133 |       },
134 |       items: {
135 |         type: 'void',
136 |         properties: {
137 |           index: {
138 |             type: 'void',
139 |             'x-component': 'ArrayCards.Index',
140 |           },
141 |           input: {
142 |             type: 'string',
143 |             'x-decorator': 'FormItem',
144 |             title: 'Input',
145 |             required: true,
146 |             'x-component': 'Input',
147 |           },
148 |           remove: {
149 |             type: 'void',
150 |             'x-component': 'ArrayCards.Remove',
151 |           },
152 |           moveUp: {
153 |             type: 'void',
154 |             'x-component': 'ArrayCards.MoveUp',
155 |           },
156 |           moveDown: {
157 |             type: 'void',
158 |             'x-component': 'ArrayCards.MoveDown',
159 |           },
160 |         },
161 |       },
162 |       properties: {
163 |         addition: {
164 |           type: 'void',
165 |           title: 'Add entry',
166 |           'x-component': 'ArrayCards.Addition',
167 |         },
168 |       },
169 |     },
170 |     array: {
171 |       type: 'array',
172 |       'x-component': 'ArrayCards',
173 |       maxItems: 3,
174 |       'x-decorator': 'FormItem',
175 |       'x-component-props': {
176 |         title: 'Object array',
177 |       },
178 |       items: {
179 |         type: 'object',
180 |         properties: {
181 |           index: {
182 |             type: 'void',
183 |             'x-component': 'ArrayCards.Index',
184 |           },
185 |           input: {
186 |             type: 'string',
187 |             'x-decorator': 'FormItem',
188 |             title: 'Input',
189 |             required: true,
190 |             'x-component': 'Input',
191 |           },
192 |           remove: {
193 |             type: 'void',
194 |             'x-component': 'ArrayCards.Remove',
195 |           },
196 |           moveUp: {
197 |             type: 'void',
198 |             'x-component': 'ArrayCards.MoveUp',
199 |           },
200 |           moveDown: {
201 |             type: 'void',
202 |             'x-component': 'ArrayCards.MoveDown',
203 |           },
204 |         },
205 |       },
206 |       properties: {
207 |         addition: {
208 |           type: 'void',
209 |           title: 'Add entry',
210 |           'x-component': 'ArrayCards.Addition',
211 |         },
212 |       },
213 |     },
214 |   },
215 | }
216 | 
217 | export default () => {
218 |   return (
219 |     <FormProvider form={form}>
220 |       <SchemaField schema={schema} />
221 |       <FormButtonGroup>
222 |         <Submit onSubmit={console.log}>Submit</Submit>
223 |       </FormButtonGroup>
224 |     </FormProvider>
225 |   )
226 | }
227 | ```
228 | 
229 | ## Effects linkage case
230 | 
231 | ```tsx
232 | import React from 'react'
233 | import {
234 |   FormItem,
235 |   Input,
236 |   ArrayCards,
237 |   FormButtonGroup,
238 |   Submit,
239 | } from '@formily/antd'
240 | import { createForm, onFieldChange, onFieldReact } from '@formily/core'
241 | import { FormProvider, createSchemaField } from '@formily/react'
242 | 
243 | const SchemaField = createSchemaField({
244 |   components: {
245 |     FormItem,
246 |     Input,
247 |     ArrayCards,
248 |   },
249 | })
250 | 
251 | const form = createForm({
252 |   effects: () => {
253 |     //Active linkage mode
254 |     onFieldChange('array.*.aa', ['value'], (field, form) => {
255 |       form.setFieldState(field.query('.bb'), (state) => {
256 |         state.visible = field.value != '123'
257 |       })
258 |     })
259 |     //Passive linkage mode
260 |     onFieldReact('array.*.dd', (field) => {
261 |       field.visible = field.query('.cc').get('value') != '123'
262 |     })
263 |   },
264 | })
265 | 
266 | export default () => {
267 |   return (
268 |     <FormProvider form={form}>
269 |       <SchemaField>
270 |         <SchemaField.Array
271 |           name="array"
272 |           maxItems={3}
273 |           x-component="ArrayCards"
274 |           x-decorator="FormItem"
275 |           x-component-props={{
276 |             title: 'Object array',
277 |           }}
278 |         >
279 |           <SchemaField.Object>
280 |             <SchemaField.Void x-component="ArrayCards.Index" />
281 |             <SchemaField.String
282 |               name="aa"
283 |               x-decorator="FormItem"
284 |               title="AA"
285 |               required
286 |               description="AA hide BB when entering 123"
287 |               x-component="Input"
288 |             />
289 |             <SchemaField.String
290 |               name="bb"
291 |               x-decorator="FormItem"
292 |               title="BB"
293 |               required
294 |               x-component="Input"
295 |             />
296 |             <SchemaField.String
297 |               name="cc"
298 |               x-decorator="FormItem"
299 |               title="CC"
300 |               required
301 |               description="Hide DD when CC enters 123"
302 |               x-component="Input"
303 |             />
304 |             <SchemaField.String
305 |               name="dd"
306 |               x-decorator="FormItem"
307 |               title="DD"
308 |               required
309 |               x-component="Input"
310 |             />
311 |             <SchemaField.Void x-component="ArrayCards.Remove" />
312 |             <SchemaField.Void x-component="ArrayCards.MoveUp" />
313 |             <SchemaField.Void x-component="ArrayCards.MoveDown" />
314 |           </SchemaField.Object>
315 |           <SchemaField.Void
316 |             x-component="ArrayCards.Addition"
317 |             title="Add entry"
318 |           />
319 |         </SchemaField.Array>
320 |       </SchemaField>
321 |       <FormButtonGroup>
322 |         <Submit onSubmit={console.log}>Submit</Submit>
323 |       </FormButtonGroup>
324 |     </FormProvider>
325 |   )
326 | }
327 | ```
328 | 
329 | ## JSON Schema linkage case
330 | 
331 | ```tsx
332 | import React from 'react'
333 | import {
334 |   FormItem,
335 |   Input,
336 |   ArrayCards,
337 |   FormButtonGroup,
338 |   Submit,
339 | } from '@formily/antd'
340 | import { createForm } from '@formily/core'
341 | import { FormProvider, createSchemaField } from '@formily/react'
342 | 
343 | const SchemaField = createSchemaField({
344 |   components: {
345 |     FormItem,
346 |     Input,
347 |     ArrayCards,
348 |   },
349 | })
350 | 
351 | const form = createForm()
352 | 
353 | const schema = {
354 |   type: 'object',
355 |   properties: {
356 |     array: {
357 |       type: 'array',
358 |       'x-component': 'ArrayCards',
359 |       maxItems: 3,
360 |       title: 'Object array',
361 |       items: {
362 |         type: 'object',
363 |         properties: {
364 |           index: {
365 |             type: 'void',
366 |             'x-component': 'ArrayCards.Index',
367 |           },
368 |           aa: {
369 |             type: 'string',
370 |             'x-decorator': 'FormItem',
371 |             title: 'AA',
372 |             required: true,
373 |             'x-component': 'Input',
374 |             description: 'Enter 123',
375 |           },
376 |           bb: {
377 |             type: 'string',
378 |             title: 'BB',
379 |             required: true,
380 |             'x-decorator': 'FormItem',
381 |             'x-component': 'Input',
382 |             'x-reactions': [
383 |               {
384 |                 dependencies: ['.aa'],
385 |                 when: "{{$deps[0] != '123'}}",
386 |                 fulfill: {
387 |                   schema: {
388 |                     title: 'BB',
389 |                     'x-disabled': true,
390 |                   },
391 |                 },
392 |                 otherwise: {
393 |                   schema: {
394 |                     title: 'Changed',
395 |                     'x-disabled': false,
396 |                   },
397 |                 },
398 |               },
399 |             ],
400 |           },
401 |           remove: {
402 |             type: 'void',
403 |             'x-component': 'ArrayCards.Remove',
404 |           },
405 |           moveUp: {
406 |             type: 'void',
407 |             'x-component': 'ArrayCards.MoveUp',
408 |           },
409 |           moveDown: {
410 |             type: 'void',
411 |             'x-component': 'ArrayCards.MoveDown',
412 |           },
413 |         },
414 |       },
415 |       properties: {
416 |         addition: {
417 |           type: 'void',
418 |           title: 'Add entry',
419 |           'x-component': 'ArrayCards.Addition',
420 |         },
421 |       },
422 |     },
423 |   },
424 | }
425 | 
426 | export default () => {
427 |   return (
428 |     <FormProvider form={form}>
429 |       <SchemaField schema={schema} />
430 |       <FormButtonGroup>
431 |         <Submit onSubmit={console.log}>Submit</Submit>
432 |       </FormButtonGroup>
433 |     </FormProvider>
434 |   )
435 | }
436 | ```
437 | 
438 | ## API
439 | 
440 | ### ArrayCards
441 | 
442 | Extended attributes
443 | 
444 | | Property name | Type                      | Description     | Default value |
445 | | ------------- | ------------------------- | --------------- | ------------- |
446 | | onAdd         | `(index: number) => void` | add method      |               |
447 | | onRemove      | `(index: number) => void` | remove method   |               |
448 | | onCopy        | `(index: number) => void` | copy method     |               |
449 | | onMoveUp      | `(index: number) => void` | moveUp method   |               |
450 | | onMoveDown    | `(index: number) => void` | moveDown method |               |
451 | 
452 | Other Reference https://ant.design/components/card-cn/
453 | 
454 | ### ArrayCards.Addition
455 | 
456 | > Add button
457 | 
458 | Extended attributes
459 | 
460 | | Property name | Type                 | Description   | Default value |
461 | | ------------- | -------------------- | ------------- | ------------- |
462 | | title         | ReactText            | Copywriting   |               |
463 | | method        | `'push' \|'unshift'` | add method    | `'push'`      |
464 | | defaultValue  | `any`                | Default value |               |
465 | 
466 | Other references https://ant.design/components/button-cn/
467 | 
468 | Note: The title attribute can receive the title mapping in the Field model, that is, uploading the title in the Field is also effective
469 | 
470 | Note: You can disable default behavior with `onClick={e => e.preventDefault()}` in props.
471 | 
472 | ### ArrayCards.Copy
473 | 
474 | > Copy button
475 | 
476 | Extended attributes
477 | 
478 | | Property name | Type                 | Description | Default value |
479 | | ------------- | -------------------- | ----------- | ------------- |
480 | | title         | ReactText            | Copywriting |               |
481 | | method        | `'push' \|'unshift'` | Copy method | `'push'`      |
482 | 
483 | Other references https://ant.design/components/button-cn/
484 | 
485 | Note: The title attribute can receive the title mapping in the Field model, that is, uploading the title in the Field is also effective
486 | 
487 | Note: You can disable default behavior with `onClick={e => e.preventDefault()}` in props.
488 | 
489 | ### ArrayCards.Remove
490 | 
491 | > Delete button
492 | 
493 | | Property name | Type      | Description | Default value |
494 | | ------------- | --------- | ----------- | ------------- |
495 | | title         | ReactText | Copywriting |               |
496 | 
497 | Other references https://ant.design/components/icon-cn/
498 | 
499 | Note: The title attribute can receive the title mapping in the Field model, that is, uploading the title in the Field is also effective
500 | 
501 | Note: You can disable default behavior with `onClick={e => e.preventDefault()}` in props.
502 | 
503 | ### ArrayCards.MoveDown
504 | 
505 | > Move down button
506 | 
507 | | Property name | Type      | Description | Default value |
508 | | ------------- | --------- | ----------- | ------------- |
509 | | title         | ReactText | Copywriting |               |
510 | 
511 | Other references https://ant.design/components/icon-cn/
512 | 
513 | Note: The title attribute can receive the title mapping in the Field model, that is, uploading the title in the Field is also effective
514 | 
515 | Note: You can disable default behavior with `onClick={e => e.preventDefault()}` in props.
516 | 
517 | ### ArrayCards.MoveUp
518 | 
519 | > Move up button
520 | 
521 | | Property name | Type      | Description | Default value |
522 | | ------------- | --------- | ----------- | ------------- |
523 | | title         | ReactText | Copywriting |               |
524 | 
525 | Other references https://ant.design/components/icon-cn/
526 | 
527 | Note: The title attribute can receive the title mapping in the Field model, that is, uploading the title in the Field is also effective
528 | 
529 | Note: You can disable default behavior with `onClick={e => e.preventDefault()}` in props.
530 | 
531 | ### ArrayCards.Index
532 | 
533 | > Index Renderer
534 | 
535 | No attributes
536 | 
537 | ### ArrayCards.useIndex
538 | 
539 | > Read the React Hook of the current rendering row index
540 | 
541 | ### ArrayCards.useRecord
542 | 
543 | > Read the React Hook of the current rendering row
544 | 
```

--------------------------------------------------------------------------------
/packages/core/docs/api/entry/FieldEffectHooks.md:
--------------------------------------------------------------------------------

```markdown
  1 | ---
  2 | order: 2
  3 | ---
  4 | 
  5 | # Field Effect Hooks
  6 | 
  7 | ## onFieldInit
  8 | 
  9 | #### Description
 10 | 
 11 | Used to monitor the side effect hook of a field initialization, we will trigger the field initialization event when we call createField
 12 | 
 13 | #### Signature
 14 | 
 15 | ```ts
 16 | interface onFieldInit {
 17 |   (pattern: FormPathPattern, callback: (field: Field, form: Form) => void)
 18 | }
 19 | ```
 20 | 
 21 | <Alert>
 22 |   For the syntax format of FormPathPattern, please refer to <a href="/api/entry/form-path">FormPath</a>
 23 | </Alert>
 24 | 
 25 | #### Example
 26 | 
 27 | ```tsx
 28 | import React, { useMemo, useState } from 'react'
 29 | import { createForm, onFieldInit } from '@formily/core'
 30 | import { ActionResponse } from './ActionResponse'
 31 | 
 32 | export default () => {
 33 |   const [response, setResponse] = useState('')
 34 |   const form = useMemo(
 35 |     () =>
 36 |       createForm({
 37 |         effects() {
 38 |           onFieldInit('target', () => {
 39 |             setResponse('target has been initialized')
 40 |           })
 41 |         },
 42 |       }),
 43 |     []
 44 |   )
 45 |   return (
 46 |     <ActionResponse response={response}>
 47 |       <button
 48 |         onClick={() => {
 49 |           form.createField({ name: 'target' })
 50 |         }}
 51 |       >
 52 |         Create field
 53 |       </button>
 54 |     </ActionResponse>
 55 |   )
 56 | }
 57 | ```
 58 | 
 59 | ## onFieldMount
 60 | 
 61 | #### Description
 62 | 
 63 | Used to monitor the side-effect hook of a field that has been mounted, we will trigger the field mount event when we call onMount
 64 | 
 65 | #### Signature
 66 | 
 67 | ```ts
 68 | interface onFieldMount {
 69 |   (pattern: FormPathPattern, callback: (field: Field, form: Form) => void)
 70 | }
 71 | ```
 72 | 
 73 | #### Example
 74 | 
 75 | ```tsx
 76 | import React, { useMemo, useState } from 'react'
 77 | import { createForm, onFieldMount } from '@formily/core'
 78 | import { ActionResponse } from './ActionResponse'
 79 | 
 80 | export default () => {
 81 |   const [response, setResponse] = useState('')
 82 |   const form = useMemo(
 83 |     () =>
 84 |       createForm({
 85 |         effects() {
 86 |           onFieldMount('target', () => {
 87 |             setResponse('target is mounted')
 88 |           })
 89 |         },
 90 |       }),
 91 |     []
 92 |   )
 93 |   return (
 94 |     <ActionResponse response={response}>
 95 |       <button
 96 |         onClick={() => {
 97 |           form.createField({ name: 'target' }).onMount()
 98 |         }}
 99 |       >
100 |         Create and mount fields
101 |       </button>
102 |     </ActionResponse>
103 |   )
104 | }
105 | ```
106 | 
107 | ## onFieldUnmount
108 | 
109 | #### Description
110 | 
111 | It is used to monitor the side effect hook that a field has been unloaded. When we call onUnmount, the unmount event will be triggered
112 | 
113 | #### Signature
114 | 
115 | ```ts
116 | interface onFieldUnmount {
117 |   (pattern: FormPathPattern, callback: (field: Field, form: Form) => void)
118 | }
119 | ```
120 | 
121 | #### Example
122 | 
123 | ```tsx
124 | import React, { useMemo, useState } from 'react'
125 | import { createForm, onFieldMount, onFieldUnmount } from '@formily/core'
126 | import { ActionResponse } from './ActionResponse'
127 | 
128 | export default () => {
129 |   const [response, setResponse] = useState('')
130 |   const form = useMemo(
131 |     () =>
132 |       createForm({
133 |         effects() {
134 |           onFieldMount('target', () => {
135 |             setResponse('target is mounted')
136 |           })
137 |           onFieldUnmount('target', () => {
138 |             setResponse('target has been uninstalled')
139 |           })
140 |         },
141 |       }),
142 |     []
143 |   )
144 |   return (
145 |     <ActionResponse response={response}>
146 |       <button
147 |         onClick={() => {
148 |           form.createField({ name: 'target' }).onMount()
149 |         }}
150 |       >
151 |         Create and mount fields
152 |       </button>
153 |       <button
154 |         onClick={() => {
155 |           form.createField({ name: 'target' }).onUnmount()
156 |         }}
157 |       >
158 |         Unload field
159 |       </button>
160 |     </ActionResponse>
161 |   )
162 | }
163 | ```
164 | 
165 | ## onFieldReact
166 | 
167 | A side-effect hook used to implement field reactive logic. Its core principle is that the callback function will be executed when the field is initialized, and the dependency will be automatically tracked at the same time. The callback function will be executed repeatedly when the dependent data changes.
168 | 
169 | #### Signature
170 | 
171 | ```ts
172 | interface onFieldReact {
173 |   (pattern: FormPathPattern, callback: (field: Field, form: Form) => void)
174 | }
175 | ```
176 | 
177 | #### Example
178 | 
179 | ```tsx
180 | import React, { useMemo, useState } from 'react'
181 | import { createForm, onFieldReact } from '@formily/core'
182 | import { ActionResponse } from './ActionResponse'
183 | 
184 | export default () => {
185 |   const [response, setResponse] = useState('')
186 |   const form = useMemo(
187 |     () =>
188 |       createForm({
189 |         effects(form) {
190 |           onFieldReact('target', () => {
191 |             setResponse(
192 |               'target ' + (form.values.other === 123 ? 'display' : 'hide')
193 |             )
194 |           })
195 |         },
196 |       }),
197 |     []
198 |   )
199 |   return (
200 |     <ActionResponse response={response}>
201 |       <button
202 |         onClick={() => {
203 |           form.createField({ name: 'target' })
204 |         }}
205 |       >
206 |         Initialize target
207 |       </button>
208 |       <button
209 |         onClick={() => {
210 |           const field = form.createField({ name: 'other' })
211 |           field.setValue(123)
212 |         }}
213 |       >
214 |         Assign other = 123
215 |       </button>
216 |       <button
217 |         onClick={() => {
218 |           const field = form.createField({ name: 'other' })
219 |           field.setValue(null)
220 |         }}
221 |       >
222 |         Assign other = null
223 |       </button>
224 |     </ActionResponse>
225 |   )
226 | }
227 | ```
228 | 
229 | > This example will track the changes of values.other, if it is equal to 123, it will control the display of the target, otherwise it will be hidden
230 | 
231 | ## onFieldChange
232 | 
233 | #### Description
234 | 
235 | Side effect hook used to monitor the property changes of a field
236 | 
237 | #### Signature
238 | 
239 | ```ts
240 | interface onFieldChange {
241 |   (
242 |     pattern: FormPathPattern,
243 |     watches?: string[],
244 |     callback: (field: Field, form: Form) => void
245 |   )
246 |   (pattern: FormPathPattern, callback: (field: Field, form: Form) => void)
247 | }
248 | ```
249 | 
250 | You can pass in the specific set of attributes you want to monitor, or you can leave it alone, the default is to monitor value changes
251 | 
252 | #### Example
253 | 
254 | ```tsx
255 | import React, { useMemo, useState } from 'react'
256 | import { createForm, onFieldChange } from '@formily/core'
257 | import { ActionResponse } from './ActionResponse'
258 | 
259 | export default () => {
260 |   const [response, setResponse] = useState('')
261 |   const form = useMemo(
262 |     () =>
263 |       createForm({
264 |         effects() {
265 |           onFieldChange('target', (field) => {
266 |             setResponse('target value change:' + field.value)
267 |           })
268 |           onFieldChange('target', ['component'], () => {
269 |             setResponse('target component change')
270 |           })
271 |         },
272 |       }),
273 |     []
274 |   )
275 |   return (
276 |     <ActionResponse response={response}>
277 |       <button
278 |         onClick={() => {
279 |           const field = form.createField({ name: 'target' })
280 |           field.setValue(field.value ? field.value + 1 : 1)
281 |         }}
282 |       >
283 |         Settings
284 |       </button>
285 |       <button
286 |         onClick={() => {
287 |           const field = form.createField({ name: 'target' })
288 |           field.setComponent('Input')
289 |         }}
290 |       >
291 |         Set up components
292 |       </button>
293 |     </ActionResponse>
294 |   )
295 | }
296 | ```
297 | 
298 | ## onFieldValueChange
299 | 
300 | Side effect hooks used to monitor changes in a field value
301 | 
302 | #### Signature
303 | 
304 | ```ts
305 | interface onFieldValueChange {
306 |   (pattern: FormPathPattern, callback: (field: Field, form: Form) => void)
307 | }
308 | ```
309 | 
310 | #### Example
311 | 
312 | ```tsx
313 | import React, { useMemo, useState } from 'react'
314 | import { createForm, onFieldValueChange } from '@formily/core'
315 | import { ActionResponse } from './ActionResponse'
316 | 
317 | export default () => {
318 |   const [response, setResponse] = useState('')
319 |   const form = useMemo(
320 |     () =>
321 |       createForm({
322 |         effects() {
323 |           onFieldValueChange('target', (field) => {
324 |             setResponse('target value change:' + field.value)
325 |           })
326 |         },
327 |       }),
328 |     []
329 |   )
330 |   return (
331 |     <ActionResponse response={response}>
332 |       <button
333 |         onClick={() => {
334 |           const field = form.createField({ name: 'target' })
335 |           field.setValue(field.value ? field.value + 1 : 1)
336 |         }}
337 |       >
338 |         Settings
339 |       </button>
340 |     </ActionResponse>
341 |   )
342 | }
343 | ```
344 | 
345 | ## onFieldInitialValueChange
346 | 
347 | Side-effect hooks used to monitor changes in the default value of a field
348 | 
349 | #### Signature
350 | 
351 | ```ts
352 | interface onFieldInitialValueChange {
353 |   (pattern: FormPathPattern, callback: (field: Field, form: Form) => void)
354 | }
355 | ```
356 | 
357 | #### Example
358 | 
359 | ```tsx
360 | import React, { useMemo, useState } from 'react'
361 | import { createForm, onFieldInitialValueChange } from '@formily/core'
362 | import { ActionResponse } from './ActionResponse'
363 | 
364 | export default () => {
365 |   const [response, setResponse] = useState('')
366 |   const form = useMemo(
367 |     () =>
368 |       createForm({
369 |         effects() {
370 |           onFieldInitialValueChange('target', (field) => {
371 |             setResponse('target default value change:' + field.value)
372 |           })
373 |         },
374 |       }),
375 |     []
376 |   )
377 |   return (
378 |     <ActionResponse response={response}>
379 |       <button
380 |         onClick={() => {
381 |           const field = form.createField({ name: 'target' })
382 |           field.setInitialValue(field.value ? field.value + 1 : 1)
383 |         }}
384 |       >
385 |         Settings
386 |       </button>
387 |     </ActionResponse>
388 |   )
389 | }
390 | ```
391 | 
392 | ## onFieldInputValueChange
393 | 
394 | Used to monitor the side effect hook triggered by a field onInput
395 | 
396 | #### Signature
397 | 
398 | ```ts
399 | interface onFieldInputValueChange {
400 |   (pattern: FormPathPattern, callback: (field: Field, form: Form) => void)
401 | }
402 | ```
403 | 
404 | #### Example
405 | 
406 | ```tsx
407 | import React, { useMemo, useState } from 'react'
408 | import { createForm, onFieldInputValueChange } from '@formily/core'
409 | import { ActionResponse } from './ActionResponse'
410 | 
411 | export default () => {
412 |   const [response, setResponse] = useState('')
413 |   const form = useMemo(
414 |     () =>
415 |       createForm({
416 |         effects() {
417 |           onFieldInputValueChange('target', (field) => {
418 |             setResponse('target value change:' + field.value)
419 |           })
420 |         },
421 |       }),
422 |     []
423 |   )
424 |   return (
425 |     <ActionResponse response={response}>
426 |       <button
427 |         onClick={() => {
428 |           const field = form.createField({ name: 'target' })
429 |           field.onInput(field.value ? field.value + 1 : 1)
430 |         }}
431 |       >
432 |         Call onInput
433 |       </button>
434 |     </ActionResponse>
435 |   )
436 | }
437 | ```
438 | 
439 | ## onFieldValidateStart
440 | 
441 | #### Description
442 | 
443 | Monitor the side effect hook that triggers the start of a certain field verification
444 | 
445 | #### Signature
446 | 
447 | ```ts
448 | interface onFieldValidateStart {
449 |   (pattern: FormPathPattern, callback: (field: Field, form: Form) => void)
450 | }
451 | ```
452 | 
453 | #### Example
454 | 
455 | ```tsx
456 | import React, { useMemo, useState } from 'react'
457 | import { createForm, onFieldValidateStart } from '@formily/core'
458 | import { ActionResponse } from './ActionResponse'
459 | 
460 | export default () => {
461 |   const [response, setResponse] = useState('')
462 |   const form = useMemo(
463 |     () =>
464 |       createForm({
465 |         effects() {
466 |           onFieldValidateStart('target', () => {
467 |             setResponse('target verification start')
468 |           })
469 |         },
470 |       }),
471 |     []
472 |   )
473 |   return (
474 |     <ActionResponse response={response}>
475 |       <button
476 |         onClick={() => {
477 |           const field = form.createField({ name: 'target', required: true })
478 |           field.onInput('')
479 |         }}
480 |       >
481 |         Trigger verification
482 |       </button>
483 |     </ActionResponse>
484 |   )
485 | }
486 | ```
487 | 
488 | ## onFieldValidateEnd
489 | 
490 | #### Description
491 | 
492 | Monitor the side effect hook that triggers the end of a certain field verification
493 | 
494 | #### Signature
495 | 
496 | ```ts
497 | interface onFieldValidateEnd {
498 |   (pattern: FormPathPattern, callback: (field: Field, form: Form) => void)
499 | }
500 | ```
501 | 
502 | #### Example
503 | 
504 | ```tsx
505 | import React, { useMemo, useState } from 'react'
506 | import { createForm, onFieldValidateEnd } from '@formily/core'
507 | import { ActionResponse } from './ActionResponse'
508 | 
509 | export default () => {
510 |   const [response, setResponse] = useState('')
511 |   const form = useMemo(
512 |     () =>
513 |       createForm({
514 |         effects() {
515 |           onFieldValidateEnd('target', () => {
516 |             setResponse('target verification is over')
517 |           })
518 |         },
519 |       }),
520 |     []
521 |   )
522 |   return (
523 |     <ActionResponse response={response}>
524 |       <button
525 |         onClick={() => {
526 |           const field = form.createField({ name: 'target', required: true })
527 |           field.onInput('')
528 |         }}
529 |       >
530 |         Trigger verification
531 |       </button>
532 |     </ActionResponse>
533 |   )
534 | }
535 | ```
536 | 
537 | ## onFieldValidateFailed
538 | 
539 | #### Description
540 | 
541 | Listen to the side-effect hook of a field verification trigger failure
542 | 
543 | #### Signature
544 | 
545 | ```ts
546 | interface onFieldValidateFailed {
547 |   (pattern: FormPathPattern, callback: (field: Field, form: Form) => void)
548 | }
549 | ```
550 | 
551 | #### Example
552 | 
553 | ```tsx
554 | import React, { useMemo, useState } from 'react'
555 | import { createForm, onFieldValidateFailed } from '@formily/core'
556 | import { ActionResponse } from './ActionResponse'
557 | 
558 | export default () => {
559 |   const [response, setResponse] = useState('')
560 |   const form = useMemo(
561 |     () =>
562 |       createForm({
563 |         effects() {
564 |           onFieldValidateFailed('target', () => {
565 |             setResponse('target verification failed')
566 |           })
567 |         },
568 |       }),
569 |     []
570 |   )
571 |   return (
572 |     <ActionResponse response={response}>
573 |       <button
574 |         onClick={() => {
575 |           const field = form.createField({ name: 'target', required: true })
576 |           field.onInput('')
577 |         }}
578 |       >
579 |         Trigger verification
580 |       </button>
581 |     </ActionResponse>
582 |   )
583 | }
584 | ```
585 | 
586 | ## onFieldValidateSuccess
587 | 
588 | #### Description
589 | 
590 | Monitor the side effect hook that triggers a successful verification of a certain field
591 | 
592 | #### Signature
593 | 
594 | ```ts
595 | interface onFieldValidateSuccess {
596 |   (pattern: FormPathPattern, callback: (field: Field, form: Form) => void)
597 | }
598 | ```
599 | 
600 | #### Example
601 | 
602 | ```tsx
603 | import React, { useMemo, useState } from 'react'
604 | import {
605 |   createForm,
606 |   onFieldValidateFailed,
607 |   onFieldValidateSuccess,
608 | } from '@formily/core'
609 | import { ActionResponse } from './ActionResponse'
610 | 
611 | export default () => {
612 |   const [response, setResponse] = useState('')
613 |   const form = useMemo(
614 |     () =>
615 |       createForm({
616 |         effects() {
617 |           onFieldValidateFailed('target', () => {
618 |             setResponse('target verification failed')
619 |           })
620 |           onFieldValidateSuccess('target', () => {
621 |             setResponse('target verification succeeded')
622 |           })
623 |         },
624 |       }),
625 |     []
626 |   )
627 |   return (
628 |     <ActionResponse response={response}>
629 |       <button
630 |         onClick={() => {
631 |           const field = form.createField({ name: 'target', required: true })
632 |           field.onInput('')
633 |         }}
634 |       >
635 |         Trigger failed
636 |       </button>
637 |       <button
638 |         onClick={() => {
639 |           const field = form.createField({ name: 'target', required: true })
640 |           field.onInput('123')
641 |         }}
642 |       >
643 |         Triggered successfully
644 |       </button>
645 |     </ActionResponse>
646 |   )
647 | }
648 | ```
649 | 
```
Page 30/52FirstPrevNextLast