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

# Directory Structure

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

# Files

--------------------------------------------------------------------------------
/packages/core/docs/guide/field.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Field model
  2 | 
  3 | Formily's field model core contains two types of field models:
  4 | 
  5 | - Data type field
  6 | - Dummy data type field
  7 | 
  8 | Data type field (Field), the core is responsible for maintaining the form data (the value when the form is submitted).
  9 | 
 10 | VoidField, you can understand that it is a Field that has castrated data maintenance capabilities, so it is more of a UI form that maintains a batch of fields as a container.
 11 | 
 12 | Let's analyze these two types of fields in detail.
 13 | 
 14 | ## Data field
 15 | 
 16 | There are 3 data type fields in the field model:
 17 | 
 18 | - Field
 19 | - ArrayField
 20 | - ObjectField
 21 | 
 22 | ArrayField and ObjectField are both inherited from Field. The positioning of Field is to maintain non-incremental data fields. Compared with ArrayField/Object, it does not mean that Field cannot store data of array type or object type. Field can store data of any data type. However, if the user expects to realize the interaction of adding, deleting, and moving arrays, they need to use ArrayField, and for the interaction of adding and deleting object properties, they need to use ObjectField. If there is no such requirement, all data types can be unified with Field.
 23 | 
 24 | Then let's look at the specific Field rules:
 25 | 
 26 | - Path rules
 27 | - Explicit and implicit rules
 28 | - Data read and write rules
 29 | - Data source rules
 30 | - Field component rules
 31 | - Field decorator rules
 32 | - Validation rules
 33 | 
 34 | ### Path Rules
 35 | 
 36 | Because the form structure of our actual business itself is a tree structure, in Formily, each field will have an absolute path in the form model. This absolute path roughly describes the position of the field in the form data (why use roughly, later I will talk about it), any field can be found through the absolute path, and at the same time the parent-child relationship between the fields can be expressed. Therefore, in the field model, we define the address attribute to express the absolute path of the field, which is mainly described by dot syntax, such as abc The path of represents that the father of field c is field b, and the father of field b is a.
 37 | 
 38 | Of course, things are not that simple, because we also have a VoidField, which is a dummy data field, and it also has its own absolute path, because it can be the father of the data field. If we only have an absolute path, we cannot make a data field correct. Write field data to the form data. Reading data will also read the wrong position.
 39 | 
 40 | Therefore, we actually need a data path as a dedicated data field for writing data and reading data. Here we use path to describe the data path of the field. You can look at this picture for general rules:
 41 | 
 42 | ![](//img.alicdn.com/imgextra/i1/O1CN01cdzULJ1et4PBak8si_!!6000000003928-2-tps-3506-2042.png)
 43 | 
 44 | In summary, Address is always the absolute path representing the node, and Path is the node path that skips the VoidField, but if it is the Path of the VoidField, it will retain its own path position.
 45 | 
 46 | Therefore, whether it is a Field or a VoidField, it will have its Address and Path, so when we use the query method to query the field, we can either use the Address rule to query, or use the Path rule to query, such as `query("bc")` The c field can be queried, and the c field can also be queried with `query("abc")`.
 47 | 
 48 | ### Explicit and Implicit Rules
 49 | 
 50 | The display and hiding of the fields are mainly expressed by the display attribute:
 51 | 
 52 | - If display is none, it means that the field UI is hidden and the field data is not retained
 53 | - display is hidden, which means that the field UI is hidden and the field data is preserved
 54 | - display is visible, which means the field UI is displayed, and the field data is restored at the same time
 55 | 
 56 | On top of the display property, we also provide two convenient properties
 57 | 
 58 | 1. visible, if true, display is equal to visible, if false, display is equal to none
 59 | 2. hidden, if true, display is equal to hidden, if false, display is equal to visible
 60 | 
 61 | The above is about the writing rules of explicit and implicit attributes. The reading rules will be more complicated. Here is a default inheritance logic:
 62 | 
 63 | If the parent node actively sets the display property, and the child node does not actively set the display property, then the child node will inherit the display of the parent node
 64 | 
 65 | So what is the active setting of display? mainly includes:
 66 | 
 67 | - Configure the initial attributes display/visible/hidden for the field
 68 | - If there is no configuration during initialization, but display/visible/hidden is set to the field later
 69 | 
 70 | So what if you want to change from no inheritance to inheritance? Just set display to null.
 71 | 
 72 | ### Data read and write rules
 73 | 
 74 | Because Field is a data-type field, it is responsible for maintaining the data of a certain node of the form data. The reading here is actually the form data read directly, which is addressed through the path attribute, which also guarantees the form data and field data. Absolutely idempotent, just read value/initialValue directly.
 75 | 
 76 | The data writing rules are consistent with the reading rules. Field does not independently maintain a copy of data. It directly operates on the data of the specific form, which is addressed through the path attribute. The main writing methods are:
 77 | 
 78 | - Modify the value/initialValue attribute directly
 79 | - Calling onInput will write data, and at the same time, set the inputValue of the field as input parameter data, inputValues as multi-parameter data, and then set the modified attribute to true, which means that the field has been manually modified, and finally trigger the verification rule that triggerType is onInput
 80 | - Call the setValue method
 81 | 
 82 | ### Data source rules
 83 | 
 84 | Considering that the value source of the field is not only input through the Input input box, but also selected from a data source, such as a drop-down box, the field model adds a data source attribute dataSource, which is dedicated to reading data source. Only a layer of mapping needs to be done on the component consumer side. The method of writing to the data source can directly modify the dataSource property, or call the setDataSource method
 85 | 
 86 | ### Component Rules
 87 | 
 88 | Field model, if there is no proxy UI component information, then more refined linkage control cannot be achieved. For example, if the value of A field changes to control the placeholder of B field, then the field attributes must be proxyed, so formily provides The component property is used to proxy UI component information. The component is an array `[Component,ComponentProps]`. The first element represents which component it is, and the second represents the properties of the component. Why use an array? This is convenient for type prompting, and the writing method is relatively simple.
 89 | 
 90 | The way to read component information is to read the component property directly.
 91 | 
 92 | The main ways to write component information are:
 93 | 
 94 | - Modify the component property directly and pass in the array
 95 | - Call the setComponent method, the first parameter is the component, the second is the component property
 96 | - Call the setComponentProps method to directly set the component properties
 97 | 
 98 | ### Decorator rules
 99 | 
100 | Similar to the field component rules, the field decorator is mainly used to maintain the package container of the field, such as FormItem, which is more partial to the control of the UI layout. Here we use the decorator attribute to describe the field decorator.
101 | 
102 | The way to read the decorator information is to directly read the decorator attribute.
103 | 
104 | The main ways to write decorator information are:
105 | 
106 | - Modify the decorator property directly and pass in an array
107 | - Call the setDecorator method, the first parameter is the component, and the second is the component property
108 | - Call the setDecoratorProps method to directly set the component properties
109 | 
110 | ### Validation rules
111 | 
112 | The verification rules mainly include:
113 | 
114 | - Verifier
115 | - Timing of calibration
116 | - Verification strategy
117 | - Verification result
118 | 
119 | #### Validator
120 | 
121 | The validator in the field model is mainly described by the validator attribute. The validator can be passed to the field when the field is initialized, and the validator can be modified again after initialization.
122 | 
123 | A validator mainly has the following forms:
124 | 
125 | - Pure string format verification, such as `"phone" | validator = "url" | validator= "email"`. This format verification is a short form of regular rules. Formily provides some standard regular rules. Of course Users can also manually create rules through registerValidateFormats to facilitate reuse
126 | - Custom function verification, there are 3 return value modes:
127 |   - `(value)=>"message"`, a string returned means there is an error, and no string means no error
128 |   - `(value)=>({type:"error",message:"message"})`, return object form, you can specify type as error or warning or success
129 |   - `{validator:()=>false,message:"message"}`, returns a boolean form, the error message will reuse the message field of the object structure
130 | - Object structure verification is a more complete expression, such as:
131 |   - `{format:"url"}` This can specify the regular format
132 |   - `{required:true}` This can specify required fields
133 |   - There are more rule attributes can refer to the API documentation, and we can also register similar validation rules through registerValidateRules
134 | - Object array structure verification is a combination of the previous three types. In fact, the first three types will all be converted into object array structures, such as:
135 |   - `["url",{required:true},(value)=>"message"]` is actually equivalent to `[{format:"url"},{required:true},{validator:(value)=> "message"}]`
136 | 
137 | #### Check timing
138 | 
139 | Sometimes, we want certain verification rules to be triggered only when focusing or out of focus. We can add a triggerType to each verification rule object, such as `{validator:(value)=>"message",triggerType: "onBlur"}` In this way, you can precisely control a verification rule to perform verification only in a certain event. The triggerType here mainly includes `"onInput" | "onBlur" | "onFocus"`, if you call `form. validate` is a rule that verifies all triggerTypes at once. If you manually call `field.validate`, you can specify the triggerType in the input parameters, and all triggerTypes will be verified if you don’t pass them.
140 | 
141 | #### Verification Strategy
142 | 
143 | Sometimes, we hope that the verification strategy of a certain field is that when all the verification rules are executed, if a verification rule fails, the result will be returned immediately. We only need to pass the parameter validateFirst to true when the field is initialized. That is, the default is false, that is, the verification will continue if the verification fails, and the verification result obtained is an array.
144 | 
145 | #### Read the verification result
146 | 
147 | The verification results are mainly stored in the feedbacks property in the field model. Feedbacks is an array of Feedback objects. The structure of each Feedback is:
148 | 
149 | ```ts
150 | interface Feedback {
151 |   path: string //Field data path
152 |   address: string //field absolute path
153 |   type: 'error' | 'success' | 'warning' //Verification result type
154 |   code: //Check result code
155 |   | 'ValidateError'
156 |     | 'ValidateSuccess'
157 |     | 'ValidateWarning'
158 |     | 'EffectError'
159 |     | 'EffectSuccess'
160 |     | 'EffectWarning'
161 |   messages: string[] //Check the message
162 | }
163 | ```
164 | 
165 | There are four main ways to read:
166 | 
167 | - Read feedbacks properties directly
168 | - Reading the errors attribute is equivalent to filtering out all verification results with type error from feedbacks
169 | - Reading the warnings attribute is equivalent to filtering out all the verification results whose type is warning from feedbacks
170 | - Reading the successes attribute is equivalent to filtering out all verification results with type success from feedbacks
171 | 
172 | #### Write verification result
173 | 
174 | There are 3 ways to write:
175 | 
176 | - Call the validate method to trigger the field validator to perform the validation action, and the code of the validation result is uniformly Validate\*`
177 |   - Calling onInput will trigger validate
178 |   - Calling onFocus will trigger validate
179 |   - Calling onBlur will trigger validate
180 |   - Call reset and specify validate as true to trigger validate
181 | - Modify the feedbacks attribute directly
182 | - Modify the errors property directly, it will be converted into an array of feedbacks objects, and the code of Feedback will be forcibly overwritten as EffectError
183 | - Modify the warnings attribute directly, it will be converted into an array of feedbacks objects, and the code of Feedback will be forcibly overwritten as EffectWarning
184 | - Modify the successes property directly, it will be converted into an array of feedbacks objects, and the code of Feedback will be forcibly overwritten as EffectSuccess
185 | 
186 | Such writing logic is mainly to prevent users from modifying the verification results from polluting the verification results of their own verifiers, strictly separating them, and easy to restore the scene.
187 | 
188 | #### Verification result query
189 | 
190 | The query of the verification result is mainly queried through queryFeedbacks. The query has the same participating Feedback objects, which can be filtered by type or code, or by path.
191 | 
192 | ## ArrayField
193 | 
194 | Compared with Field, ArrayField only extends array-related methods on the basis of inheriting Field, such as push/pop/insert/move. Why should these methods be provided? Its ability is not only to process the field data, it It also provides internal state transposition processing for the sub-nodes of ArrayField mainly to ensure that the order of the fields is consistent with the order of the data. Can cite an example:
195 | 
196 | ![](//img.alicdn.com/imgextra/i3/O1CN01mpGugu1QFlnfQ4qfo_!!6000000001947-2-tps-3506-1794.png)
197 | 
198 | This is a move call process, the value of the array element will move, and the state of the corresponding field will also move.
199 | 
200 | ## ObjectField
201 | 
202 | Because the object type is disordered, there is no state transposition, so ObjectField provides addProperty/removeProperty/existProperty three APIs for users to use.
203 | 
204 | ## VoidField
205 | 
206 | Compared with Field, VoidField mainly castrates data read and write rules, data source rules, and verification rules. When users use it, they mainly use explicit and implicit rules, components, and decorator rules.
207 | 
208 | <Alert>
209 | 
210 | The series of field rules mentioned above did not mention the detailed API usage details. It is more to help users sort out formily from the perspective of ideas. If you are not familiar with the API, it is best to read the API documentation first.
211 | 
212 | </Alert>
213 | 
```

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

```markdown
  1 | # FormGrid
  2 | 
  3 | > FormGrid 组件
  4 | 
  5 | ## Markup Schema 案例
  6 | 
  7 | ```tsx
  8 | import React from 'react'
  9 | import { FormItem, Input, FormGrid } from '@formily/antd'
 10 | import { FormProvider, createSchemaField } from '@formily/react'
 11 | import { createForm } from '@formily/core'
 12 | 
 13 | const SchemaField = createSchemaField({
 14 |   components: {
 15 |     FormItem,
 16 |     Input,
 17 |     FormGrid,
 18 |   },
 19 | })
 20 | 
 21 | const form = createForm()
 22 | 
 23 | export default () => {
 24 |   return (
 25 |     <FormProvider form={form}>
 26 |       <SchemaField>
 27 |         <SchemaField.Void
 28 |           x-component="FormGrid"
 29 |           x-component-props={{
 30 |             maxColumns: 3,
 31 |             minColumns: 2,
 32 |           }}
 33 |         >
 34 |           <SchemaField.String
 35 |             name="aaa"
 36 |             title="aaa"
 37 |             x-decorator="FormItem"
 38 |             x-decorator-props={{ gridSpan: 2 }}
 39 |             x-component="Input"
 40 |           />
 41 |           <SchemaField.String
 42 |             name="bbb"
 43 |             title="bbb"
 44 |             x-decorator="FormItem"
 45 |             x-component="Input"
 46 |           />
 47 |           <SchemaField.String
 48 |             name="ccc"
 49 |             title="ccc"
 50 |             x-decorator="FormItem"
 51 |             x-component="Input"
 52 |           />
 53 |           <SchemaField.String
 54 |             name="ddd"
 55 |             title="ddd"
 56 |             x-decorator="FormItem"
 57 |             x-component="Input"
 58 |           />
 59 |           <SchemaField.String
 60 |             name="eee"
 61 |             title="eee"
 62 |             x-decorator="FormItem"
 63 |             x-component="Input"
 64 |           />
 65 |           <SchemaField.String
 66 |             name="fff"
 67 |             title="fff"
 68 |             x-decorator="FormItem"
 69 |             x-component="Input"
 70 |           />
 71 |           <SchemaField.String
 72 |             name="ggg"
 73 |             title="ggg"
 74 |             x-decorator="FormItem"
 75 |             x-component="Input"
 76 |           />
 77 |         </SchemaField.Void>
 78 |       </SchemaField>
 79 |     </FormProvider>
 80 |   )
 81 | }
 82 | ```
 83 | 
 84 | ## JSON Schema 案例
 85 | 
 86 | ```tsx
 87 | import React from 'react'
 88 | import { FormItem, Input, FormGrid } from '@formily/antd'
 89 | import { FormProvider, createSchemaField } from '@formily/react'
 90 | import { createForm } from '@formily/core'
 91 | 
 92 | const SchemaField = createSchemaField({
 93 |   components: {
 94 |     FormItem,
 95 |     Input,
 96 |     FormGrid,
 97 |   },
 98 | })
 99 | 
100 | const form = createForm()
101 | 
102 | const schema = {
103 |   type: 'object',
104 |   properties: {
105 |     grid: {
106 |       type: 'void',
107 |       'x-component': 'FormGrid',
108 |       'x-component-props': {
109 |         minColumns: [4, 6, 10],
110 |       },
111 |       properties: {
112 |         aaa: {
113 |           type: 'string',
114 |           title: 'AAA',
115 |           'x-decorator': 'FormItem',
116 |           'x-component': 'Input',
117 |         },
118 |         bbb: {
119 |           type: 'string',
120 |           title: 'BBB',
121 |           'x-decorator': 'FormItem',
122 |           'x-component': 'Input',
123 |         },
124 |         ccc: {
125 |           type: 'string',
126 |           title: 'CCC',
127 |           'x-decorator': 'FormItem',
128 |           'x-component': 'Input',
129 |         },
130 |         ddd: {
131 |           type: 'string',
132 |           title: 'DDD',
133 |           'x-decorator': 'FormItem',
134 |           'x-component': 'Input',
135 |         },
136 |         eee: {
137 |           type: 'string',
138 |           title: 'EEE',
139 |           'x-decorator': 'FormItem',
140 |           'x-component': 'Input',
141 |         },
142 |         fff: {
143 |           type: 'string',
144 |           title: 'FFF',
145 |           'x-decorator': 'FormItem',
146 |           'x-component': 'Input',
147 |         },
148 |         ggg: {
149 |           type: 'string',
150 |           title: 'GGG',
151 |           'x-decorator': 'FormItem',
152 |           'x-component': 'Input',
153 |         },
154 |       },
155 |     },
156 |   },
157 | }
158 | 
159 | export default () => {
160 |   return (
161 |     <FormProvider form={form}>
162 |       <SchemaField schema={schema} />
163 |     </FormProvider>
164 |   )
165 | }
166 | ```
167 | 
168 | ## 原生 案例
169 | 
170 | ```tsx
171 | import React from 'react'
172 | import { FormGrid } from '@formily/antd'
173 | 
174 | const { GridColumn } = FormGrid
175 | const Cell = ({ children }) => {
176 |   return (
177 |     <div
178 |       style={{
179 |         backgroundColor: '#AAA',
180 |         color: '#FFF',
181 |         height: 30,
182 |         display: 'flex',
183 |         alignItems: 'center',
184 |         padding: '0 10px',
185 |       }}
186 |     >
187 |       {children}
188 |     </div>
189 |   )
190 | }
191 | export default () => {
192 |   return (
193 |     <React.Fragment>
194 |       <p>maxColumns 3 + minColumns 2</p>
195 |       <FormGrid maxColumns={3} minColumns={2} columnGap={4}>
196 |         <GridColumn gridSpan={4}>
197 |           <Cell>1</Cell>
198 |         </GridColumn>
199 |         <GridColumn>
200 |           <Cell>2</Cell>
201 |         </GridColumn>
202 |         <GridColumn>
203 |           <Cell>3</Cell>
204 |         </GridColumn>
205 |         <GridColumn>
206 |           <Cell>4</Cell>
207 |         </GridColumn>
208 |         <GridColumn>
209 |           <Cell>5</Cell>
210 |         </GridColumn>
211 |         <GridColumn>
212 |           <Cell>6</Cell>
213 |         </GridColumn>
214 |       </FormGrid>
215 |       <p>maxColumns 3</p>
216 |       <FormGrid maxColumns={3} columnGap={4}>
217 |         <GridColumn gridSpan={2}>
218 |           <Cell>1</Cell>
219 |         </GridColumn>
220 |         <GridColumn>
221 |           <Cell>2</Cell>
222 |         </GridColumn>
223 |         <GridColumn>
224 |           <Cell>3</Cell>
225 |         </GridColumn>
226 |         <GridColumn>
227 |           <Cell>4</Cell>
228 |         </GridColumn>
229 |         <GridColumn>
230 |           <Cell>5</Cell>
231 |         </GridColumn>
232 |         <GridColumn>
233 |           <Cell>6</Cell>
234 |         </GridColumn>
235 |       </FormGrid>
236 |       <p>minColumns 2</p>
237 |       <FormGrid minColumns={2} columnGap={4}>
238 |         <GridColumn gridSpan={2}>
239 |           <Cell>1</Cell>
240 |         </GridColumn>
241 |         <GridColumn>
242 |           <Cell>2</Cell>
243 |         </GridColumn>
244 |         <GridColumn>
245 |           <Cell>3</Cell>
246 |         </GridColumn>
247 |         <GridColumn>
248 |           <Cell>4</Cell>
249 |         </GridColumn>
250 |         <GridColumn>
251 |           <Cell>5</Cell>
252 |         </GridColumn>
253 |         <GridColumn>
254 |           <Cell>6</Cell>
255 |         </GridColumn>
256 |       </FormGrid>
257 |       <p>Null</p>
258 |       <FormGrid columnGap={4}>
259 |         <GridColumn gridSpan={2}>
260 |           <Cell>1</Cell>
261 |         </GridColumn>
262 |         <GridColumn>
263 |           <Cell>2</Cell>
264 |         </GridColumn>
265 |         <GridColumn>
266 |           <Cell>3</Cell>
267 |         </GridColumn>
268 |         <GridColumn>
269 |           <Cell>4</Cell>
270 |         </GridColumn>
271 |         <GridColumn>
272 |           <Cell>5</Cell>
273 |         </GridColumn>
274 |         <GridColumn>
275 |           <Cell>6</Cell>
276 |         </GridColumn>
277 |       </FormGrid>
278 |       <p>minWidth 150 +maxColumns 3</p>
279 |       <FormGrid minWidth={150} maxColumns={3} columnGap={4}>
280 |         <GridColumn gridSpan={2}>
281 |           <Cell>1</Cell>
282 |         </GridColumn>
283 |         <GridColumn>
284 |           <Cell>2</Cell>
285 |         </GridColumn>
286 |         <GridColumn>
287 |           <Cell>3</Cell>
288 |         </GridColumn>
289 |         <GridColumn>
290 |           <Cell>4</Cell>
291 |         </GridColumn>
292 |         <GridColumn>
293 |           <Cell>5</Cell>
294 |         </GridColumn>
295 |         <GridColumn>
296 |           <Cell>6</Cell>
297 |         </GridColumn>
298 |       </FormGrid>
299 |       <p>maxWidth 120+minColumns 2</p>
300 |       <FormGrid maxWidth={120} minColumns={2} columnGap={4}>
301 |         <GridColumn gridSpan={2}>
302 |           <Cell>1</Cell>
303 |         </GridColumn>
304 |         <GridColumn>
305 |           <Cell>2</Cell>
306 |         </GridColumn>
307 |         <GridColumn>
308 |           <Cell>3</Cell>
309 |         </GridColumn>
310 |         <GridColumn>
311 |           <Cell>4</Cell>
312 |         </GridColumn>
313 |         <GridColumn>
314 |           <Cell>5</Cell>
315 |         </GridColumn>
316 |         <GridColumn>
317 |           <Cell>6</Cell>
318 |         </GridColumn>
319 |       </FormGrid>
320 |       <p>maxWidth 120 + gridSpan -1</p>
321 |       <FormGrid maxWidth={120} columnGap={4}>
322 |         <GridColumn gridSpan={2}>
323 |           <Cell>1</Cell>
324 |         </GridColumn>
325 |         <GridColumn>
326 |           <Cell>2</Cell>
327 |         </GridColumn>
328 |         <GridColumn gridSpan={-1}>
329 |           <Cell>3</Cell>
330 |         </GridColumn>
331 |       </FormGrid>
332 |     </React.Fragment>
333 |   )
334 | }
335 | ```
336 | 
337 | ## 查询表单实现案例
338 | 
339 | ```tsx
340 | import React, { useMemo, Fragment } from 'react'
341 | import { createForm } from '@formily/core'
342 | import { createSchemaField, FormProvider, observer } from '@formily/react'
343 | import {
344 |   Form,
345 |   Input,
346 |   Select,
347 |   DatePicker,
348 |   FormItem,
349 |   FormGrid,
350 |   Submit,
351 |   Reset,
352 |   FormButtonGroup,
353 | } from '@formily/antd'
354 | 
355 | const useCollapseGrid = (maxRows: number) => {
356 |   const grid = useMemo(
357 |     () =>
358 |       FormGrid.createFormGrid({
359 |         maxColumns: 4,
360 |         maxWidth: 240,
361 |         maxRows: maxRows,
362 |         shouldVisible: (node, grid) => {
363 |           if (node.index === grid.childSize - 1) return true
364 |           if (grid.maxRows === Infinity) return true
365 |           return node.shadowRow < maxRows + 1
366 |         },
367 |       }),
368 |     []
369 |   )
370 |   const expanded = grid.maxRows === Infinity
371 |   const realRows = grid.shadowRows
372 |   const computeRows = grid.fullnessLastColumn
373 |     ? grid.shadowRows - 1
374 |     : grid.shadowRows
375 | 
376 |   const toggle = () => {
377 |     if (grid.maxRows === Infinity) {
378 |       grid.maxRows = maxRows
379 |     } else {
380 |       grid.maxRows = Infinity
381 |     }
382 |   }
383 |   const takeType = () => {
384 |     if (realRows < maxRows + 1) return 'incomplete-wrap'
385 |     if (computeRows > maxRows) return 'collapsible'
386 |     return 'complete-wrap'
387 |   }
388 |   return {
389 |     grid,
390 |     expanded,
391 |     toggle,
392 |     type: takeType(),
393 |   }
394 | }
395 | 
396 | const QueryForm: React.FC = observer((props) => {
397 |   const { grid, expanded, toggle, type } = useCollapseGrid(1)
398 | 
399 |   const renderActions = () => {
400 |     return (
401 |       <Fragment>
402 |         <Submit onSubmit={console.log}>查询</Submit>
403 |         <Reset>重置</Reset>
404 |       </Fragment>
405 |     )
406 |   }
407 | 
408 |   const renderButtonGroup = () => {
409 |     if (type === 'incomplete-wrap') {
410 |       return (
411 |         <FormButtonGroup.FormItem>
412 |           <FormButtonGroup>{renderActions()}</FormButtonGroup>
413 |         </FormButtonGroup.FormItem>
414 |       )
415 |     }
416 |     if (type === 'collapsible') {
417 |       return (
418 |         <Fragment>
419 |           <FormButtonGroup>
420 |             <a
421 |               href=""
422 |               onClick={(e) => {
423 |                 e.preventDefault()
424 |                 toggle()
425 |               }}
426 |             >
427 |               {expanded ? '收起' : '展开'}
428 |             </a>
429 |           </FormButtonGroup>
430 |           <FormButtonGroup align="right">{renderActions()}</FormButtonGroup>
431 |         </Fragment>
432 |       )
433 |     }
434 |     return (
435 |       <FormButtonGroup align="right" style={{ display: 'flex', width: '100%' }}>
436 |         {renderActions()}
437 |       </FormButtonGroup>
438 |     )
439 |   }
440 | 
441 |   return (
442 |     <Form {...props} layout="vertical" feedbackLayout="terse">
443 |       <FormGrid grid={grid}>
444 |         {props.children}
445 |         <FormGrid.GridColumn
446 |           gridSpan={-1}
447 |           style={{ display: 'flex', justifyContent: 'space-between' }}
448 |         >
449 |           {renderButtonGroup()}
450 |         </FormGrid.GridColumn>
451 |       </FormGrid>
452 |     </Form>
453 |   )
454 | })
455 | 
456 | const SchemaField = createSchemaField({
457 |   components: {
458 |     QueryForm,
459 |     Input,
460 |     Select,
461 |     DatePicker,
462 |     FormItem,
463 |   },
464 | })
465 | 
466 | export default () => {
467 |   const form = useMemo(() => createForm(), [])
468 |   return (
469 |     <FormProvider form={form}>
470 |       <SchemaField>
471 |         <SchemaField.Object x-component="QueryForm">
472 |           <SchemaField.String
473 |             name="input1"
474 |             title="Input 1"
475 |             x-component="Input"
476 |             x-decorator="FormItem"
477 |           />
478 |           <SchemaField.String
479 |             name="input2"
480 |             title="Input 2"
481 |             x-component="Input"
482 |             x-decorator="FormItem"
483 |           />
484 | 
485 |           <SchemaField.String
486 |             name="select1"
487 |             title="Select 1"
488 |             x-component="Select"
489 |             x-decorator="FormItem"
490 |           />
491 |           <SchemaField.String
492 |             name="select2"
493 |             title="Select 2"
494 |             x-component="Select"
495 |             x-decorator="FormItem"
496 |           />
497 |           <SchemaField.String
498 |             name="date"
499 |             title="DatePicker"
500 |             x-component="DatePicker"
501 |             x-decorator="FormItem"
502 |           />
503 |           <SchemaField.String
504 |             name="dateRange"
505 |             title="DatePicker.RangePicker"
506 |             x-component="DatePicker.RangePicker"
507 |             x-decorator="FormItem"
508 |             x-decorator-props={{
509 |               gridSpan: 2,
510 |             }}
511 |           />
512 |           <SchemaField.String
513 |             name="select3"
514 |             title="Select 3"
515 |             x-component="Select"
516 |             x-decorator="FormItem"
517 |           />
518 |         </SchemaField.Object>
519 |       </SchemaField>
520 |     </FormProvider>
521 |   )
522 | }
523 | ```
524 | 
525 | ## API
526 | 
527 | ### FormGrid
528 | 
529 | | 属性名        | 类型                   | 描述                                                           | 默认值            |
530 | | ------------- | ---------------------- | -------------------------------------------------------------- | ----------------- |
531 | | minWidth      | `number \| number[]`   | 元素最小宽度                                                   | 100               |
532 | | maxWidth      | `number \| number[]`   | 元素最大宽度                                                   | -                 |
533 | | minColumns    | `number \| number[]`   | 最小列数                                                       | 0                 |
534 | | maxColumns    | `number \| number[]`   | 最大列数                                                       | -                 |
535 | | breakpoints   | number[]               | 容器尺寸断点                                                   | `[720,1280,1920]` |
536 | | columnGap     | number                 | 列间距                                                         | 8                 |
537 | | rowGap        | number                 | 行间距                                                         | 4                 |
538 | | colWrap       | boolean                | 自动换行                                                       | true              |
539 | | strictAutoFit | boolean                | GridItem 宽度是否严格受限于 maxWidth,不受限的话会自动占满容器 | false             |
540 | | shouldVisible | `(node,grid)=>boolean` | 是否需要显示当前节点                                           | `()=>true`        |
541 | | grid          | `Grid`                 | 外部传入 Grid 实例,用于实现更复杂的布局逻辑                   | -                 |
542 | 
543 | 注意:
544 | 
545 | - minWidth 生效优先级高于 minColumn
546 | - maxWidth 优先级高于 maxColumn
547 | - minWidth/maxWidth/minColumns/maxColumns 的数组格式代表与断点数组映射
548 | 
549 | ### FormGrid.GridColumn
550 | 
551 | | 属性名   | 类型   | 描述                                                 | 默认值 |
552 | | -------- | ------ | ---------------------------------------------------- | ------ |
553 | | gridSpan | number | 元素所跨列数,如果为-1,那么会自动反向跨列填补单元格 | 1      |
554 | 
555 | ### FormGrid.createFormGrid
556 | 
557 | 从上下文中读取 Grid 实例
558 | 
559 | ```ts
560 | interface createFormGrid {
561 |   (props: IGridProps): Grid
562 | }
563 | ```
564 | 
565 | - IGridProps 参考 FormGrid 属性
566 | - Grid 实例属性方法参考 https://github.com/alibaba/formily/tree/formily_next/packages/grid
567 | 
568 | ### FormGrid.useFormGrid
569 | 
570 | 从上下文中读取 Grid 实例
571 | 
572 | ```ts
573 | interface useFormGrid {
574 |   (): Grid
575 | }
576 | ```
577 | 
578 | - Grid 实例属性方法参考 https://github.com/alibaba/formily/tree/formily_next/packages/grid
579 | 
```

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

```markdown
  1 | # FormGrid
  2 | 
  3 | > FormGrid 组件
  4 | 
  5 | ## Markup Schema 案例
  6 | 
  7 | ```tsx
  8 | import React from 'react'
  9 | import { FormItem, Input, FormGrid } from '@formily/next'
 10 | import { FormProvider, createSchemaField } from '@formily/react'
 11 | import { createForm } from '@formily/core'
 12 | 
 13 | const SchemaField = createSchemaField({
 14 |   components: {
 15 |     FormItem,
 16 |     Input,
 17 |     FormGrid,
 18 |   },
 19 | })
 20 | 
 21 | const form = createForm()
 22 | 
 23 | export default () => {
 24 |   return (
 25 |     <FormProvider form={form}>
 26 |       <SchemaField>
 27 |         <SchemaField.Void
 28 |           x-component="FormGrid"
 29 |           x-component-props={{
 30 |             maxColumns: 3,
 31 |             minColumns: 2,
 32 |           }}
 33 |         >
 34 |           <SchemaField.String
 35 |             name="aaa"
 36 |             title="aaa"
 37 |             x-decorator="FormItem"
 38 |             x-decorator-props={{ gridSpan: 2 }}
 39 |             x-component="Input"
 40 |           />
 41 |           <SchemaField.String
 42 |             name="bbb"
 43 |             title="bbb"
 44 |             x-decorator="FormItem"
 45 |             x-component="Input"
 46 |           />
 47 |           <SchemaField.String
 48 |             name="ccc"
 49 |             title="ccc"
 50 |             x-decorator="FormItem"
 51 |             x-component="Input"
 52 |           />
 53 |           <SchemaField.String
 54 |             name="ddd"
 55 |             title="ddd"
 56 |             x-decorator="FormItem"
 57 |             x-component="Input"
 58 |           />
 59 |           <SchemaField.String
 60 |             name="eee"
 61 |             title="eee"
 62 |             x-decorator="FormItem"
 63 |             x-component="Input"
 64 |           />
 65 |           <SchemaField.String
 66 |             name="fff"
 67 |             title="fff"
 68 |             x-decorator="FormItem"
 69 |             x-component="Input"
 70 |           />
 71 |           <SchemaField.String
 72 |             name="ggg"
 73 |             title="ggg"
 74 |             x-decorator="FormItem"
 75 |             x-component="Input"
 76 |           />
 77 |         </SchemaField.Void>
 78 |       </SchemaField>
 79 |     </FormProvider>
 80 |   )
 81 | }
 82 | ```
 83 | 
 84 | ## JSON Schema 案例
 85 | 
 86 | ```tsx
 87 | import React from 'react'
 88 | import { FormItem, Input, FormGrid } from '@formily/next'
 89 | import { FormProvider, createSchemaField } from '@formily/react'
 90 | import { createForm } from '@formily/core'
 91 | 
 92 | const SchemaField = createSchemaField({
 93 |   components: {
 94 |     FormItem,
 95 |     Input,
 96 |     FormGrid,
 97 |   },
 98 | })
 99 | 
100 | const form = createForm()
101 | 
102 | const schema = {
103 |   type: 'object',
104 |   properties: {
105 |     grid: {
106 |       type: 'void',
107 |       'x-component': 'FormGrid',
108 |       'x-component-props': {
109 |         minColumns: [4, 6, 10],
110 |       },
111 |       properties: {
112 |         aaa: {
113 |           type: 'string',
114 |           title: 'AAA',
115 |           'x-decorator': 'FormItem',
116 |           'x-component': 'Input',
117 |         },
118 |         bbb: {
119 |           type: 'string',
120 |           title: 'BBB',
121 |           'x-decorator': 'FormItem',
122 |           'x-component': 'Input',
123 |         },
124 |         ccc: {
125 |           type: 'string',
126 |           title: 'CCC',
127 |           'x-decorator': 'FormItem',
128 |           'x-component': 'Input',
129 |         },
130 |         ddd: {
131 |           type: 'string',
132 |           title: 'DDD',
133 |           'x-decorator': 'FormItem',
134 |           'x-component': 'Input',
135 |         },
136 |         eee: {
137 |           type: 'string',
138 |           title: 'EEE',
139 |           'x-decorator': 'FormItem',
140 |           'x-component': 'Input',
141 |         },
142 |         fff: {
143 |           type: 'string',
144 |           title: 'FFF',
145 |           'x-decorator': 'FormItem',
146 |           'x-component': 'Input',
147 |         },
148 |         ggg: {
149 |           type: 'string',
150 |           title: 'GGG',
151 |           'x-decorator': 'FormItem',
152 |           'x-component': 'Input',
153 |         },
154 |       },
155 |     },
156 |   },
157 | }
158 | 
159 | export default () => {
160 |   return (
161 |     <FormProvider form={form}>
162 |       <SchemaField schema={schema} />
163 |     </FormProvider>
164 |   )
165 | }
166 | ```
167 | 
168 | ## 原生 案例
169 | 
170 | ```tsx
171 | import React from 'react'
172 | import { FormGrid } from '@formily/next'
173 | 
174 | const { GridColumn } = FormGrid
175 | const Cell = ({ children }) => {
176 |   return (
177 |     <div
178 |       style={{
179 |         backgroundColor: '#AAA',
180 |         color: '#FFF',
181 |         height: 30,
182 |         display: 'flex',
183 |         alignItems: 'center',
184 |         padding: '0 10px',
185 |       }}
186 |     >
187 |       {children}
188 |     </div>
189 |   )
190 | }
191 | export default () => {
192 |   return (
193 |     <React.Fragment>
194 |       <p>maxColumns 3 + minColumns 2</p>
195 |       <FormGrid maxColumns={3} minColumns={2} columnGap={4}>
196 |         <GridColumn gridSpan={4}>
197 |           <Cell>1</Cell>
198 |         </GridColumn>
199 |         <GridColumn>
200 |           <Cell>2</Cell>
201 |         </GridColumn>
202 |         <GridColumn>
203 |           <Cell>3</Cell>
204 |         </GridColumn>
205 |         <GridColumn>
206 |           <Cell>4</Cell>
207 |         </GridColumn>
208 |         <GridColumn>
209 |           <Cell>5</Cell>
210 |         </GridColumn>
211 |         <GridColumn>
212 |           <Cell>6</Cell>
213 |         </GridColumn>
214 |       </FormGrid>
215 |       <p>maxColumns 3</p>
216 |       <FormGrid maxColumns={3} columnGap={4}>
217 |         <GridColumn gridSpan={2}>
218 |           <Cell>1</Cell>
219 |         </GridColumn>
220 |         <GridColumn>
221 |           <Cell>2</Cell>
222 |         </GridColumn>
223 |         <GridColumn>
224 |           <Cell>3</Cell>
225 |         </GridColumn>
226 |         <GridColumn>
227 |           <Cell>4</Cell>
228 |         </GridColumn>
229 |         <GridColumn>
230 |           <Cell>5</Cell>
231 |         </GridColumn>
232 |         <GridColumn>
233 |           <Cell>6</Cell>
234 |         </GridColumn>
235 |       </FormGrid>
236 |       <p>minColumns 2</p>
237 |       <FormGrid minColumns={2} columnGap={4}>
238 |         <GridColumn gridSpan={2}>
239 |           <Cell>1</Cell>
240 |         </GridColumn>
241 |         <GridColumn>
242 |           <Cell>2</Cell>
243 |         </GridColumn>
244 |         <GridColumn>
245 |           <Cell>3</Cell>
246 |         </GridColumn>
247 |         <GridColumn>
248 |           <Cell>4</Cell>
249 |         </GridColumn>
250 |         <GridColumn>
251 |           <Cell>5</Cell>
252 |         </GridColumn>
253 |         <GridColumn>
254 |           <Cell>6</Cell>
255 |         </GridColumn>
256 |       </FormGrid>
257 |       <p>Null</p>
258 |       <FormGrid columnGap={4}>
259 |         <GridColumn gridSpan={2}>
260 |           <Cell>1</Cell>
261 |         </GridColumn>
262 |         <GridColumn>
263 |           <Cell>2</Cell>
264 |         </GridColumn>
265 |         <GridColumn>
266 |           <Cell>3</Cell>
267 |         </GridColumn>
268 |         <GridColumn>
269 |           <Cell>4</Cell>
270 |         </GridColumn>
271 |         <GridColumn>
272 |           <Cell>5</Cell>
273 |         </GridColumn>
274 |         <GridColumn>
275 |           <Cell>6</Cell>
276 |         </GridColumn>
277 |       </FormGrid>
278 |       <p>minWidth 150 +maxColumns 3</p>
279 |       <FormGrid minWidth={150} maxColumns={3} columnGap={4}>
280 |         <GridColumn gridSpan={2}>
281 |           <Cell>1</Cell>
282 |         </GridColumn>
283 |         <GridColumn>
284 |           <Cell>2</Cell>
285 |         </GridColumn>
286 |         <GridColumn>
287 |           <Cell>3</Cell>
288 |         </GridColumn>
289 |         <GridColumn>
290 |           <Cell>4</Cell>
291 |         </GridColumn>
292 |         <GridColumn>
293 |           <Cell>5</Cell>
294 |         </GridColumn>
295 |         <GridColumn>
296 |           <Cell>6</Cell>
297 |         </GridColumn>
298 |       </FormGrid>
299 |       <p>maxWidth 120+minColumns 2</p>
300 |       <FormGrid maxWidth={120} minColumns={2} columnGap={4}>
301 |         <GridColumn gridSpan={2}>
302 |           <Cell>1</Cell>
303 |         </GridColumn>
304 |         <GridColumn>
305 |           <Cell>2</Cell>
306 |         </GridColumn>
307 |         <GridColumn>
308 |           <Cell>3</Cell>
309 |         </GridColumn>
310 |         <GridColumn>
311 |           <Cell>4</Cell>
312 |         </GridColumn>
313 |         <GridColumn>
314 |           <Cell>5</Cell>
315 |         </GridColumn>
316 |         <GridColumn>
317 |           <Cell>6</Cell>
318 |         </GridColumn>
319 |       </FormGrid>
320 |       <p>maxWidth 120 + gridSpan -1</p>
321 |       <FormGrid maxWidth={120} columnGap={4}>
322 |         <GridColumn gridSpan={2}>
323 |           <Cell>1</Cell>
324 |         </GridColumn>
325 |         <GridColumn>
326 |           <Cell>2</Cell>
327 |         </GridColumn>
328 |         <GridColumn gridSpan={-1}>
329 |           <Cell>3</Cell>
330 |         </GridColumn>
331 |       </FormGrid>
332 |     </React.Fragment>
333 |   )
334 | }
335 | ```
336 | 
337 | ## 查询表单实现案例
338 | 
339 | ```tsx
340 | import React, { useMemo, Fragment } from 'react'
341 | import { createForm } from '@formily/core'
342 | import { createSchemaField, FormProvider, observer } from '@formily/react'
343 | import {
344 |   Form,
345 |   Input,
346 |   Select,
347 |   DatePicker,
348 |   FormItem,
349 |   FormGrid,
350 |   Submit,
351 |   Reset,
352 |   FormButtonGroup,
353 | } from '@formily/next'
354 | 
355 | const useCollapseGrid = (maxRows: number) => {
356 |   const grid = useMemo(
357 |     () =>
358 |       FormGrid.createFormGrid({
359 |         maxColumns: 4,
360 |         maxWidth: 240,
361 |         maxRows: maxRows,
362 |         shouldVisible: (node, grid) => {
363 |           if (node.index === grid.childSize - 1) return true
364 |           if (grid.maxRows === Infinity) return true
365 |           return node.shadowRow < maxRows + 1
366 |         },
367 |       }),
368 |     []
369 |   )
370 |   const expanded = grid.maxRows === Infinity
371 |   const realRows = grid.shadowRows
372 |   const computeRows = grid.fullnessLastColumn
373 |     ? grid.shadowRows - 1
374 |     : grid.shadowRows
375 | 
376 |   const toggle = () => {
377 |     if (grid.maxRows === Infinity) {
378 |       grid.maxRows = maxRows
379 |     } else {
380 |       grid.maxRows = Infinity
381 |     }
382 |   }
383 |   const takeType = () => {
384 |     if (realRows < maxRows + 1) return 'incomplete-wrap'
385 |     if (computeRows > maxRows) return 'collapsible'
386 |     return 'complete-wrap'
387 |   }
388 |   return {
389 |     grid,
390 |     expanded,
391 |     toggle,
392 |     type: takeType(),
393 |   }
394 | }
395 | 
396 | const QueryForm: React.FC = observer((props) => {
397 |   const { grid, expanded, toggle, type } = useCollapseGrid(1)
398 | 
399 |   const renderActions = () => {
400 |     return (
401 |       <Fragment>
402 |         <Submit onSubmit={console.log}>查询</Submit>
403 |         <Reset>重置</Reset>
404 |       </Fragment>
405 |     )
406 |   }
407 | 
408 |   const renderButtonGroup = () => {
409 |     if (type === 'incomplete-wrap') {
410 |       return (
411 |         <FormButtonGroup.FormItem>
412 |           <FormButtonGroup>{renderActions()}</FormButtonGroup>
413 |         </FormButtonGroup.FormItem>
414 |       )
415 |     }
416 |     if (type === 'collapsible') {
417 |       return (
418 |         <Fragment>
419 |           <FormButtonGroup>
420 |             <a
421 |               href=""
422 |               onClick={(e) => {
423 |                 e.preventDefault()
424 |                 toggle()
425 |               }}
426 |             >
427 |               {expanded ? '收起' : '展开'}
428 |             </a>
429 |           </FormButtonGroup>
430 |           <FormButtonGroup align="right">{renderActions()}</FormButtonGroup>
431 |         </Fragment>
432 |       )
433 |     }
434 |     return (
435 |       <FormButtonGroup align="right" style={{ display: 'flex', width: '100%' }}>
436 |         {renderActions()}
437 |       </FormButtonGroup>
438 |     )
439 |   }
440 | 
441 |   return (
442 |     <Form {...props} layout="vertical" feedbackLayout="terse">
443 |       <FormGrid grid={grid}>
444 |         {props.children}
445 |         <FormGrid.GridColumn
446 |           gridSpan={-1}
447 |           style={{ display: 'flex', justifyContent: 'space-between' }}
448 |         >
449 |           {renderButtonGroup()}
450 |         </FormGrid.GridColumn>
451 |       </FormGrid>
452 |     </Form>
453 |   )
454 | })
455 | 
456 | const SchemaField = createSchemaField({
457 |   components: {
458 |     QueryForm,
459 |     Input,
460 |     Select,
461 |     DatePicker,
462 |     FormItem,
463 |   },
464 | })
465 | 
466 | export default () => {
467 |   const form = useMemo(() => createForm(), [])
468 |   return (
469 |     <FormProvider form={form}>
470 |       <SchemaField>
471 |         <SchemaField.Object x-component="QueryForm">
472 |           <SchemaField.String
473 |             name="input1"
474 |             title="Input 1"
475 |             x-component="Input"
476 |             x-decorator="FormItem"
477 |           />
478 |           <SchemaField.String
479 |             name="input2"
480 |             title="Input 2"
481 |             x-component="Input"
482 |             x-decorator="FormItem"
483 |           />
484 | 
485 |           <SchemaField.String
486 |             name="select1"
487 |             title="Select 1"
488 |             x-component="Select"
489 |             x-decorator="FormItem"
490 |           />
491 |           <SchemaField.String
492 |             name="select2"
493 |             title="Select 2"
494 |             x-component="Select"
495 |             x-decorator="FormItem"
496 |           />
497 |           <SchemaField.String
498 |             name="date"
499 |             title="DatePicker"
500 |             x-component="DatePicker"
501 |             x-decorator="FormItem"
502 |           />
503 |           <SchemaField.String
504 |             name="dateRange"
505 |             title="DatePicker.RangePicker"
506 |             x-component="DatePicker.RangePicker"
507 |             x-decorator="FormItem"
508 |             x-decorator-props={{
509 |               gridSpan: 2,
510 |             }}
511 |           />
512 |           <SchemaField.String
513 |             name="select3"
514 |             title="Select 3"
515 |             x-component="Select"
516 |             x-decorator="FormItem"
517 |           />
518 |         </SchemaField.Object>
519 |       </SchemaField>
520 |     </FormProvider>
521 |   )
522 | }
523 | ```
524 | 
525 | ## API
526 | 
527 | ### FormGrid
528 | 
529 | | 属性名        | 类型                   | 描述                                                           | 默认值            |
530 | | ------------- | ---------------------- | -------------------------------------------------------------- | ----------------- |
531 | | minWidth      | `number \| number[]`   | 元素最小宽度                                                   | 100               |
532 | | maxWidth      | `number \| number[]`   | 元素最大宽度                                                   | -                 |
533 | | minColumns    | `number \| number[]`   | 最小列数                                                       | 0                 |
534 | | maxColumns    | `number \| number[]`   | 最大列数                                                       | -                 |
535 | | breakpoints   | number[]               | 容器尺寸断点                                                   | `[720,1280,1920]` |
536 | | columnGap     | number                 | 列间距                                                         | 8                 |
537 | | rowGap        | number                 | 行间距                                                         | 4                 |
538 | | colWrap       | boolean                | 自动换行                                                       | true              |
539 | | strictAutoFit | boolean                | GridItem 宽度是否严格受限于 maxWidth,不受限的话会自动占满容器 | false             |
540 | | shouldVisible | `(node,grid)=>boolean` | 是否需要显示当前节点                                           | `()=>true`        |
541 | | grid          | `Grid`                 | 外部传入 Grid 实例,用于实现更复杂的布局逻辑                   | -                 |
542 | 
543 | 注意:
544 | 
545 | - minWidth 生效优先级高于 minColumn
546 | - maxWidth 优先级高于 maxColumn
547 | - minWidth/maxWidth/minColumns/maxColumns 的数组格式代表与断点数组映射
548 | 
549 | ### FormGrid.GridColumn
550 | 
551 | | 属性名   | 类型   | 描述                                                 | 默认值 |
552 | | -------- | ------ | ---------------------------------------------------- | ------ |
553 | | gridSpan | number | 元素所跨列数,如果为-1,那么会自动反向跨列填补单元格 | 1      |
554 | 
555 | ### FormGrid.createFormGrid
556 | 
557 | 从上下文中读取 Grid 实例
558 | 
559 | ```ts
560 | interface createFormGrid {
561 |   (props: IGridProps): Grid
562 | }
563 | ```
564 | 
565 | - IGridProps 参考 FormGrid 属性
566 | - Grid 实例属性方法参考 https://github.com/alibaba/formily/tree/formily_next/packages/grid
567 | 
568 | ### FormGrid.useFormGrid
569 | 
570 | 从上下文中读取 Grid 实例
571 | 
572 | ```ts
573 | interface useFormGrid {
574 |   (): Grid
575 | }
576 | ```
577 | 
578 | - Grid 实例属性方法参考 https://github.com/alibaba/formily/tree/formily_next/packages/grid
579 | 
```

--------------------------------------------------------------------------------
/packages/vue/src/__tests__/field.spec.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import Vue, { FunctionalComponentOptions } from 'vue'
  2 | import { render, fireEvent, waitFor } from '@testing-library/vue'
  3 | import { defineComponent, h, ref } from '@vue/composition-api'
  4 | import {
  5 |   createForm,
  6 |   Field as FieldType,
  7 |   isField,
  8 |   isVoidField,
  9 |   onFieldChange,
 10 | } from '@formily/core'
 11 | import { useField, useFormEffects, connect, mapProps, mapReadPretty } from '../'
 12 | import {
 13 |   FormProvider,
 14 |   ArrayField,
 15 |   ObjectField,
 16 |   VoidField,
 17 |   Field,
 18 | } from '../vue2-components'
 19 | import ReactiveField from '../components/ReactiveField'
 20 | // import { expectThrowError } from './shared'
 21 | 
 22 | Vue.component('FormProvider', FormProvider)
 23 | Vue.component('ArrayField', ArrayField)
 24 | Vue.component('ObjectField', ObjectField)
 25 | Vue.component('VoidField', VoidField)
 26 | Vue.component('Field', Field)
 27 | Vue.component('ReactiveField', ReactiveField as unknown as Vue)
 28 | 
 29 | const Decorator = defineComponent({
 30 |   props: ['label'],
 31 |   render(h) {
 32 |     return h(
 33 |       'div',
 34 |       {
 35 |         attrs: this.$attrs,
 36 |       },
 37 |       [this.label, this.$slots.default]
 38 |     )
 39 |   },
 40 | })
 41 | 
 42 | const Input = defineComponent({
 43 |   props: ['value'],
 44 |   setup(props, { attrs, listeners }) {
 45 |     const fieldRef = useField()
 46 |     return () => {
 47 |       const field = fieldRef.value
 48 |       return h('input', {
 49 |         class: 'test-input',
 50 |         attrs: {
 51 |           ...attrs,
 52 |           value: props.value,
 53 |           'data-testid': field.path.toString(),
 54 |         },
 55 |         on: {
 56 |           ...listeners,
 57 |           input: listeners.change,
 58 |         },
 59 |       })
 60 |     }
 61 |   },
 62 | })
 63 | 
 64 | const Normal: FunctionalComponentOptions = {
 65 |   functional: true,
 66 |   render(h) {
 67 |     return h('div')
 68 |   },
 69 | }
 70 | 
 71 | test('render field', async () => {
 72 |   const form = createForm()
 73 |   const onChange = jest.fn()
 74 |   const atChange = jest.fn()
 75 |   const atBlur = jest.fn()
 76 |   const atFocus = jest.fn()
 77 | 
 78 |   const { getByTestId, queryByTestId, queryByText } = render(
 79 |     defineComponent({
 80 |       name: 'TestComponent',
 81 |       setup() {
 82 |         return {
 83 |           form,
 84 |           Normal,
 85 |           Input,
 86 |           Decorator,
 87 |           onChange,
 88 |           atChange,
 89 |           atFocus,
 90 |           atBlur,
 91 |         }
 92 |       },
 93 |       template: `<FormProvider :form="form">
 94 |       <Field
 95 |         name="aa"
 96 |         :decorator="[Decorator, {label: 'aa-decorator'}]"
 97 |         :component="[Input, { onChange }]"
 98 |       />
 99 |       <ArrayField name="bb" :decorator="[Decorator]">
100 |         <div data-testid="bb-children"></div>
101 |       </ArrayField>
102 |       <ObjectField name="cc" :decorator="[Decorator]">
103 |         <Field name="mm" :decorator="[Decorator]" :component="[Input]" />
104 |         <ObjectField name="pp" :decorator="[Decorator]" />
105 |         <ArrayField name="tt" :decorator="[Decorator]" />
106 |         <VoidField name="ww" />
107 |       </ObjectField>
108 |       <VoidField name="dd" :decorator="[Decorator]">
109 |         <div data-testid="dd-children">
110 |           <Field name="oo" :decorator="[Decorator]" :component="[Input]" />
111 |         </div>
112 |       </VoidField>
113 |       <VoidField name="xx" :decorator="[Decorator]" :component="[Normal]" />
114 |       <Field
115 |         name="ee"
116 |         :visible="false"
117 |         :decorator="[Decorator]"
118 |         :component="[Input]"
119 |       />
120 |       <Field name="ff" :decorator="[]" :component="[]" />
121 |       <Field name="gg" :decorator="null" :component="null" />
122 |       <Field name="hh" :decorator="[null]" :component="[null, null]" />
123 |       <Field
124 |         name="kk"
125 |         :decorator="[Decorator]"
126 |         :component="[Input, { onChange: null }]"
127 |       />
128 |       <Field
129 |         name="ll"
130 |         :decorator="[Decorator]"
131 |         :component="[Input, { '@change': atChange, '@focus': atFocus, '@blur': atBlur }]"
132 |       />
133 |       <Field
134 |         name="mm"
135 |         :decorator="[Decorator]"
136 |       ><div data-testid="mm-children"></div></Field>
137 |     </FormProvider>`,
138 |     })
139 |   )
140 |   expect(form.mounted).toBeTruthy()
141 |   expect(form.query('aa').take().mounted).toBeTruthy()
142 |   expect(form.query('bb').take().mounted).toBeTruthy()
143 |   expect(form.query('cc').take().mounted).toBeTruthy()
144 |   expect(form.query('dd').take().mounted).toBeTruthy()
145 |   await fireEvent.update(getByTestId('aa'), '123')
146 |   await fireEvent.update(getByTestId('kk'), '123')
147 |   await fireEvent.focus(getByTestId('ll'))
148 |   await fireEvent.blur(getByTestId('ll'))
149 |   await fireEvent.update(getByTestId('ll'), '123')
150 |   expect(onChange).toBeCalledTimes(1)
151 |   expect(atChange).toBeCalledTimes(1)
152 |   expect(atFocus).toBeCalledTimes(1)
153 |   expect(atBlur).toBeCalledTimes(1)
154 |   expect(getByTestId('bb-children')).not.toBeUndefined()
155 |   expect(getByTestId('dd-children')).not.toBeUndefined()
156 |   expect(queryByTestId('ee')).toBeNull()
157 |   expect(form.query('aa').get('value')).toEqual('123')
158 |   expect(form.query('kk').get('value')).toEqual('123')
159 |   expect(getByTestId('mm-children')).not.toBeUndefined()
160 |   expect(queryByText('aa-decorator')).not.toBeNull()
161 | })
162 | 
163 | const InputWithSlot = defineComponent({
164 |   props: ['value'],
165 |   setup(props, { attrs, listeners, slots }) {
166 |     const fieldRef = useField()
167 |     return () => {
168 |       const field = fieldRef.value
169 |       return h('div', {}, [
170 |         h('input', {
171 |           class: 'test-input',
172 |           attrs: {
173 |             ...attrs,
174 |             value: props.value,
175 |             'data-testid': field.path.toString(),
176 |           },
177 |           on: {
178 |             ...listeners,
179 |             input: listeners.change,
180 |           },
181 |         }),
182 |         [slots['append']?.({ path: field.path.toString() })],
183 |       ])
184 |     }
185 |   },
186 | })
187 | 
188 | test('render in nesting slots with (ObjectField/ArrayField) no decorator', async () => {
189 |   const form = createForm()
190 | 
191 |   const { getByTestId } = render(
192 |     defineComponent({
193 |       name: 'TestComponent',
194 |       setup() {
195 |         return {
196 |           form,
197 |           Normal,
198 |           InputWithSlot,
199 |           Decorator,
200 |         }
201 |       },
202 |       template: `<FormProvider :form="form">
203 |       <ObjectField name="cc" :component="['div']">
204 |         <Field name="mm" :decorator="[Decorator]" :component="[InputWithSlot]">
205 |           <template #append="{ path }">
206 |             <span :data-testid="'slot-prop-' +path"></span>
207 |           </template>
208 |         </Field>
209 |       </ObjectField>
210 |       <VoidField name="dd" :component="['div']">
211 |         <Field name="oo" :decorator="[Decorator]" :component="[InputWithSlot]" />
212 |       </VoidField>
213 |       
214 |     </FormProvider>`,
215 |     })
216 |   )
217 | 
218 |   expect(getByTestId('oo')).not.toBeUndefined()
219 |   expect(getByTestId('cc.mm')).not.toBeUndefined()
220 |   expect(getByTestId('slot-prop-cc.mm')).not.toBeUndefined()
221 | })
222 | 
223 | test('render field with html attrs', async () => {
224 |   const form = createForm()
225 | 
226 |   const { getByTestId, container } = render(
227 |     defineComponent({
228 |       name: 'TestComponent',
229 |       setup() {
230 |         return {
231 |           form,
232 |           Input,
233 |           Decorator,
234 |         }
235 |       },
236 |       template: `<FormProvider :form="form">
237 |       <Field
238 |         name="aa"
239 |         :decorator="[Decorator, {
240 |           'data-testid': 'decorator',
241 |           class: {
242 |             'test-class': true
243 |           },
244 |           style: {
245 |             marginRight: '10px'
246 |           }
247 |         }]"
248 |         :component="[Input, {
249 |           class: {
250 |             'test-class': true
251 |           },
252 |           style: {
253 |             marginLeft: '10px'
254 |           }
255 |         }]"
256 |       />
257 |     </FormProvider>`,
258 |     })
259 |   )
260 |   expect(form.mounted).toBeTruthy()
261 |   expect(form.query('aa').take().mounted).toBeTruthy()
262 |   expect(getByTestId('aa').className.indexOf('test-input') !== -1).toBeTruthy()
263 |   expect(getByTestId('aa').className.indexOf('test-class') !== -1).toBeTruthy()
264 |   expect(getByTestId('aa').style.marginLeft).toEqual('10px')
265 |   expect(
266 |     getByTestId('decorator').className.indexOf('test-class') !== -1
267 |   ).toBeTruthy()
268 |   expect(getByTestId('decorator').style.marginRight).toEqual('10px')
269 | })
270 | 
271 | test('ReactiveField', () => {
272 |   render({
273 |     template: `<ReactiveField />`,
274 |   })
275 |   render({
276 |     template: `<ReactiveField>
277 |       <div></div>
278 |     </ReactiveField>`,
279 |   })
280 | })
281 | 
282 | test('useAttch', async () => {
283 |   const form1 = createForm()
284 |   const MyComponent = defineComponent({
285 |     props: ['form', 'name1', 'name2', 'name3', 'name4'],
286 |     data() {
287 |       return { Input, Decorator }
288 |     },
289 |     template: `<FormProvider :form="form">
290 |       <Field :name="name1" :decorator="[Decorator]" :component="[Input]" />
291 |       <ArrayField :name="name2" :decorator="[Decorator]" :component="[Input]" />
292 |       <ObjectField :name="name3" :decorator="[Decorator]" :component="[Input]" />
293 |       <VoidField :name="name4" :decorator="[Decorator]" :component="[Input]" />
294 |     </FormProvider>`,
295 |   })
296 |   const { updateProps } = render(MyComponent, {
297 |     props: {
298 |       form: form1,
299 |       name1: 'aa',
300 |       name2: 'bb',
301 |       name3: 'cc',
302 |       name4: 'dd',
303 |     },
304 |   })
305 |   expect(form1.mounted).toBeTruthy()
306 |   expect(form1.query('aa').take().mounted).toBeTruthy()
307 |   expect(form1.query('bb').take().mounted).toBeTruthy()
308 |   expect(form1.query('cc').take().mounted).toBeTruthy()
309 |   expect(form1.query('dd').take().mounted).toBeTruthy()
310 |   await updateProps({
311 |     name1: 'aaa',
312 |     name2: 'bbb',
313 |     name3: 'ccc',
314 |     name4: 'ddd',
315 |   })
316 |   await Vue.nextTick()
317 |   expect(form1.query('aa').take().mounted).toBeFalsy()
318 |   expect(form1.query('bb').take().mounted).toBeFalsy()
319 |   expect(form1.query('cc').take().mounted).toBeFalsy()
320 |   expect(form1.query('dd').take().mounted).toBeFalsy()
321 |   expect(form1.query('aaa').take().mounted).toBeTruthy()
322 |   expect(form1.query('bbb').take().mounted).toBeTruthy()
323 |   expect(form1.query('ccc').take().mounted).toBeTruthy()
324 |   expect(form1.query('ddd').take().mounted).toBeTruthy()
325 |   const form2 = createForm()
326 |   await updateProps({
327 |     form: form2,
328 |   })
329 |   await Vue.nextTick()
330 |   expect(form1.unmounted).toBeTruthy()
331 |   expect(form2.mounted).toBeTruthy()
332 | })
333 | 
334 | test('useFormEffects', async () => {
335 |   const form = createForm()
336 |   const CustomField = defineComponent({
337 |     props: ['value'],
338 |     setup(props) {
339 |       const fieldRef = useField<FieldType>()
340 |       useFormEffects(() => {
341 |         onFieldChange('aa', ['value'], (target) => {
342 |           if (isVoidField(target)) return
343 |           fieldRef.value.setValue(target.value)
344 |         })
345 |       })
346 |       return () => {
347 |         return h('div', { attrs: { 'data-testid': 'custom-value' } }, [
348 |           props.value,
349 |         ])
350 |       }
351 |     },
352 |   })
353 |   const { queryByTestId } = render({
354 |     data() {
355 |       return { form, Decorator, Input, CustomField }
356 |     },
357 |     template: `<FormProvider :form="form">
358 |       <Field name="aa" :decorator="[Decorator]" :component="[Input]" />
359 |       <Field name="bb" :component="[CustomField]" />
360 |     </FormProvider>`,
361 |   })
362 |   expect(queryByTestId('custom-value').textContent).toEqual('')
363 |   form.query('aa').take((aa) => {
364 |     if (isField(aa)) {
365 |       const value = '123' as any
366 |       aa.setValue(value)
367 |     }
368 |   })
369 |   await waitFor(() => {
370 |     expect(queryByTestId('custom-value').textContent).toEqual('123')
371 |   })
372 | })
373 | 
374 | test('useFormEffects: should be reregister when formRef change', async () => {
375 |   const CustomField = defineComponent({
376 |     setup() {
377 |       const reactiveText = ref()
378 |       useFormEffects(() => {
379 |         onFieldChange('aa', ['value'], (target) => {
380 |           if (isVoidField(target)) return
381 |           reactiveText.value = target.value
382 |         })
383 |       })
384 |       return () =>
385 |         h('div', { attrs: { 'data-testid': 'custom-value' } }, [
386 |           reactiveText.value,
387 |         ])
388 |     },
389 |   })
390 | 
391 |   const { queryByTestId } = render({
392 |     setup() {
393 |       const formRef = ref(createForm())
394 |       return {
395 |         formRef,
396 |         Input,
397 |         CustomField,
398 |         changeForm() {
399 |           // form change
400 |           formRef.value = createForm()
401 |           formRef.value.setValues({ aa: 'text' })
402 |         },
403 |       }
404 |     },
405 |     template: `<FormProvider :form="formRef">
406 |       <Field name="aa" :decorator="[Decorator]" :component="[Input]" />
407 |       <VoidField name="bb" :component="[CustomField]" />
408 |       <button data-testid="btn" @click="changeForm()">Change</button>
409 |     </FormProvider>`,
410 |   })
411 | 
412 |   expect(queryByTestId('custom-value').textContent).toEqual('')
413 |   queryByTestId('btn').click()
414 |   await waitFor(() => {
415 |     expect(queryByTestId('custom-value').textContent).toEqual('text')
416 |   })
417 | })
418 | 
419 | test('connect', async () => {
420 |   const CustomField = connect(
421 |     {
422 |       functional: true,
423 |       props: ['list'],
424 |       render(h, context) {
425 |         return h('div', [context.props.list])
426 |       },
427 |     },
428 |     mapProps({ value: 'list', loading: true }, (props, field) => {
429 |       return {
430 |         ...props,
431 |         mounted: field.mounted ? 1 : 2,
432 |       }
433 |     }),
434 |     mapReadPretty({
435 |       render(h) {
436 |         return h('div', 'read pretty')
437 |       },
438 |     })
439 |   )
440 |   const BaseComponent = {
441 |     functional: true,
442 |     name: 'BaseComponent',
443 |     render(h, context) {
444 |       return h('div', [context.props.value])
445 |     },
446 |   } as FunctionalComponentOptions
447 |   const CustomField2 = connect(
448 |     BaseComponent,
449 |     mapProps({ value: true, loading: true }),
450 |     mapReadPretty({
451 |       render(h) {
452 |         return h('div', 'read pretty')
453 |       },
454 |     })
455 |   )
456 | 
457 |   const CustomField3 = connect(
458 |     Input,
459 |     mapProps(),
460 |     mapReadPretty({
461 |       render(h) {
462 |         return h('div', 'read pretty')
463 |       },
464 |     })
465 |   )
466 | 
467 |   const CustomFormItem = connect(
468 |     {
469 |       functional: true,
470 |       render(h, context) {
471 |         return h('div', context.data, context.children)
472 |       },
473 |     },
474 |     mapProps(),
475 |     mapReadPretty({
476 |       render(h) {
477 |         return h('div', 'read pretty')
478 |       },
479 |     })
480 |   )
481 | 
482 |   const form = createForm()
483 |   const { queryByText, getByTestId } = render({
484 |     data() {
485 |       return {
486 |         form,
487 |         Decorator,
488 |         CustomField,
489 |         CustomField2,
490 |         CustomField3,
491 |         CustomFormItem,
492 |       }
493 |     },
494 |     template: `<FormProvider :form="form">
495 |       <Field name="aa" :decorator="[Decorator]" :component="[CustomField]" />
496 |       <Field name="bb" :decorator="[Decorator]" :component="[CustomField2]" />
497 |       <Field name="cc" :decorator="[Decorator]" :component="[CustomField3]" />
498 |       <component :is="CustomFormItem">dd</component>
499 |     </FormProvider>`,
500 |   })
501 |   form.query('aa').take((field) => {
502 |     field.setState((state) => {
503 |       state.value = '123'
504 |     })
505 |   })
506 | 
507 |   expect(queryByText('dd')).toBeVisible()
508 |   await waitFor(() => {
509 |     expect(queryByText('123')).toBeVisible()
510 |   })
511 | 
512 |   fireEvent.update(getByTestId('cc'), '123')
513 |   expect(queryByText('123')).toBeVisible()
514 |   expect(form.query('cc').get('value')).toEqual('123')
515 | 
516 |   form.query('aa').take((field) => {
517 |     if (!isField(field)) return
518 |     field.readPretty = true
519 |   })
520 |   await waitFor(() => {
521 |     expect(queryByText('123')).toBeNull()
522 |     expect(queryByText('read pretty')).toBeVisible()
523 |   })
524 | })
525 | 
```

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

```markdown
  1 | # FormGrid
  2 | 
  3 | > FormGrid component
  4 | 
  5 | ## Markup Schema example
  6 | 
  7 | ```tsx
  8 | import React from 'react'
  9 | import { FormItem, Input, FormGrid } from '@formily/antd'
 10 | import { FormProvider, createSchemaField } from '@formily/react'
 11 | import { createForm } from '@formily/core'
 12 | 
 13 | const SchemaField = createSchemaField({
 14 |   components: {
 15 |     FormItem,
 16 |     Input,
 17 |     FormGrid,
 18 |   },
 19 | })
 20 | 
 21 | const form = createForm()
 22 | 
 23 | export default () => {
 24 |   return (
 25 |     <FormProvider form={form}>
 26 |       <SchemaField>
 27 |         <SchemaField.Void
 28 |           x-component="FormGrid"
 29 |           x-component-props={{
 30 |             maxColumns: 3,
 31 |             minColumns: 2,
 32 |           }}
 33 |         >
 34 |           <SchemaField.String
 35 |             name="aaa"
 36 |             title="aaa"
 37 |             x-decorator="FormItem"
 38 |             x-decorator-props={{ gridSpan: 2 }}
 39 |             x-component="Input"
 40 |           />
 41 |           <SchemaField.String
 42 |             name="bbb"
 43 |             title="bbb"
 44 |             x-decorator="FormItem"
 45 |             x-component="Input"
 46 |           />
 47 |           <SchemaField.String
 48 |             name="ccc"
 49 |             title="ccc"
 50 |             x-decorator="FormItem"
 51 |             x-component="Input"
 52 |           />
 53 |           <SchemaField.String
 54 |             name="ddd"
 55 |             title="ddd"
 56 |             x-decorator="FormItem"
 57 |             x-component="Input"
 58 |           />
 59 |           <SchemaField.String
 60 |             name="eee"
 61 |             title="eee"
 62 |             x-decorator="FormItem"
 63 |             x-component="Input"
 64 |           />
 65 |           <SchemaField.String
 66 |             name="fff"
 67 |             title="fff"
 68 |             x-decorator="FormItem"
 69 |             x-component="Input"
 70 |           />
 71 |           <SchemaField.String
 72 |             name="ggg"
 73 |             title="ggg"
 74 |             x-decorator="FormItem"
 75 |             x-component="Input"
 76 |           />
 77 |         </SchemaField.Void>
 78 |       </SchemaField>
 79 |     </FormProvider>
 80 |   )
 81 | }
 82 | ```
 83 | 
 84 | ## JSON Schema case
 85 | 
 86 | ```tsx
 87 | import React from 'react'
 88 | import { FormItem, Input, FormGrid } from '@formily/antd'
 89 | import { FormProvider, createSchemaField } from '@formily/react'
 90 | import { createForm } from '@formily/core'
 91 | 
 92 | const SchemaField = createSchemaField({
 93 |   components: {
 94 |     FormItem,
 95 |     Input,
 96 |     FormGrid,
 97 |   },
 98 | })
 99 | 
100 | const form = createForm()
101 | 
102 | const schema = {
103 |   type: 'object',
104 |   properties: {
105 |     grid: {
106 |       type: 'void',
107 |       'x-component': 'FormGrid',
108 |       'x-component-props': {
109 |         minColumns: [4, 6, 10],
110 |       },
111 |       properties: {
112 |         aaa: {
113 |           type: 'string',
114 |           title: 'AAA',
115 |           'x-decorator': 'FormItem',
116 |           'x-component': 'Input',
117 |         },
118 |         bbb: {
119 |           type: 'string',
120 |           title: 'BBB',
121 |           'x-decorator': 'FormItem',
122 |           'x-component': 'Input',
123 |         },
124 |         ccc: {
125 |           type: 'string',
126 |           title: 'CCC',
127 |           'x-decorator': 'FormItem',
128 |           'x-component': 'Input',
129 |         },
130 |         ddd: {
131 |           type: 'string',
132 |           title: 'DDD',
133 |           'x-decorator': 'FormItem',
134 |           'x-component': 'Input',
135 |         },
136 |         eee: {
137 |           type: 'string',
138 |           title: 'EEE',
139 |           'x-decorator': 'FormItem',
140 |           'x-component': 'Input',
141 |         },
142 |         fff: {
143 |           type: 'string',
144 |           title: 'FFF',
145 |           'x-decorator': 'FormItem',
146 |           'x-component': 'Input',
147 |         },
148 |         ggg: {
149 |           type: 'string',
150 |           title: 'GGG',
151 |           'x-decorator': 'FormItem',
152 |           'x-component': 'Input',
153 |         },
154 |       },
155 |     },
156 |   },
157 | }
158 | 
159 | export default () => {
160 |   return (
161 |     <FormProvider form={form}>
162 |       <SchemaField schema={schema} />
163 |     </FormProvider>
164 |   )
165 | }
166 | ```
167 | 
168 | ## Native case
169 | 
170 | ```tsx
171 | import React from 'react'
172 | import { FormGrid } from '@formily/antd'
173 | 
174 | const { GridColumn } = FormGrid
175 | const Cell = ({ children }) => {
176 |   return (
177 |     <div
178 |       style={{
179 |         backgroundColor: '#AAA',
180 |         color: '#FFF',
181 |         height: 30,
182 |         display: 'flex',
183 |         alignItems: 'center',
184 |         padding: '0 10px',
185 |       }}
186 |     >
187 |       {children}
188 |     </div>
189 |   )
190 | }
191 | export default () => {
192 |   return (
193 |     <React.Fragment>
194 |       <p>maxColumns 3 + minColumns 2</p>
195 |       <FormGrid maxColumns={3} minColumns={2} columnGap={4}>
196 |         <GridColumn gridSpan={4}>
197 |           <Cell>1</Cell>
198 |         </GridColumn>
199 |         <GridColumn>
200 |           <Cell>2</Cell>
201 |         </GridColumn>
202 |         <GridColumn>
203 |           <Cell>3</Cell>
204 |         </GridColumn>
205 |         <GridColumn>
206 |           <Cell>4</Cell>
207 |         </GridColumn>
208 |         <GridColumn>
209 |           <Cell>5</Cell>
210 |         </GridColumn>
211 |         <GridColumn>
212 |           <Cell>6</Cell>
213 |         </GridColumn>
214 |       </FormGrid>
215 |       <p>maxColumns 3</p>
216 |       <FormGrid maxColumns={3} columnGap={4}>
217 |         <GridColumn gridSpan={2}>
218 |           <Cell>1</Cell>
219 |         </GridColumn>
220 |         <GridColumn>
221 |           <Cell>2</Cell>
222 |         </GridColumn>
223 |         <GridColumn>
224 |           <Cell>3</Cell>
225 |         </GridColumn>
226 |         <GridColumn>
227 |           <Cell>4</Cell>
228 |         </GridColumn>
229 |         <GridColumn>
230 |           <Cell>5</Cell>
231 |         </GridColumn>
232 |         <GridColumn>
233 |           <Cell>6</Cell>
234 |         </GridColumn>
235 |       </FormGrid>
236 |       <p>minColumns 2</p>
237 |       <FormGrid minColumns={2} columnGap={4}>
238 |         <GridColumn gridSpan={2}>
239 |           <Cell>1</Cell>
240 |         </GridColumn>
241 |         <GridColumn>
242 |           <Cell>2</Cell>
243 |         </GridColumn>
244 |         <GridColumn>
245 |           <Cell>3</Cell>
246 |         </GridColumn>
247 |         <GridColumn>
248 |           <Cell>4</Cell>
249 |         </GridColumn>
250 |         <GridColumn>
251 |           <Cell>5</Cell>
252 |         </GridColumn>
253 |         <GridColumn>
254 |           <Cell>6</Cell>
255 |         </GridColumn>
256 |       </FormGrid>
257 |       <p>Null</p>
258 |       <FormGrid columnGap={4}>
259 |         <GridColumn gridSpan={2}>
260 |           <Cell>1</Cell>
261 |         </GridColumn>
262 |         <GridColumn>
263 |           <Cell>2</Cell>
264 |         </GridColumn>
265 |         <GridColumn>
266 |           <Cell>3</Cell>
267 |         </GridColumn>
268 |         <GridColumn>
269 |           <Cell>4</Cell>
270 |         </GridColumn>
271 |         <GridColumn>
272 |           <Cell>5</Cell>
273 |         </GridColumn>
274 |         <GridColumn>
275 |           <Cell>6</Cell>
276 |         </GridColumn>
277 |       </FormGrid>
278 |       <p>minWidth 150 +maxColumns 3</p>
279 |       <FormGrid minWidth={150} maxColumns={3} columnGap={4}>
280 |         <GridColumn gridSpan={2}>
281 |           <Cell>1</Cell>
282 |         </GridColumn>
283 |         <GridColumn>
284 |           <Cell>2</Cell>
285 |         </GridColumn>
286 |         <GridColumn>
287 |           <Cell>3</Cell>
288 |         </GridColumn>
289 |         <GridColumn>
290 |           <Cell>4</Cell>
291 |         </GridColumn>
292 |         <GridColumn>
293 |           <Cell>5</Cell>
294 |         </GridColumn>
295 |         <GridColumn>
296 |           <Cell>6</Cell>
297 |         </GridColumn>
298 |       </FormGrid>
299 |       <p>maxWidth 120+minColumns 2</p>
300 |       <FormGrid maxWidth={120} minColumns={2} columnGap={4}>
301 |         <GridColumn gridSpan={2}>
302 |           <Cell>1</Cell>
303 |         </GridColumn>
304 |         <GridColumn>
305 |           <Cell>2</Cell>
306 |         </GridColumn>
307 |         <GridColumn>
308 |           <Cell>3</Cell>
309 |         </GridColumn>
310 |         <GridColumn>
311 |           <Cell>4</Cell>
312 |         </GridColumn>
313 |         <GridColumn>
314 |           <Cell>5</Cell>
315 |         </GridColumn>
316 |         <GridColumn>
317 |           <Cell>6</Cell>
318 |         </GridColumn>
319 |       </FormGrid>
320 |       <p>maxWidth 120 + gridSpan -1</p>
321 |       <FormGrid maxWidth={120} columnGap={4}>
322 |         <GridColumn gridSpan={2}>
323 |           <Cell>1</Cell>
324 |         </GridColumn>
325 |         <GridColumn>
326 |           <Cell>2</Cell>
327 |         </GridColumn>
328 |         <GridColumn gridSpan={-1}>
329 |           <Cell>3</Cell>
330 |         </GridColumn>
331 |       </FormGrid>
332 |     </React.Fragment>
333 |   )
334 | }
335 | ```
336 | 
337 | ## Query Form case
338 | 
339 | ```tsx
340 | import React, { useMemo, Fragment } from 'react'
341 | import { createForm } from '@formily/core'
342 | import { createSchemaField, FormProvider, observer } from '@formily/react'
343 | import {
344 |   Form,
345 |   Input,
346 |   Select,
347 |   DatePicker,
348 |   FormItem,
349 |   FormGrid,
350 |   Submit,
351 |   Reset,
352 |   FormButtonGroup,
353 | } from '@formily/antd'
354 | 
355 | const useCollapseGrid = (maxRows: number) => {
356 |   const grid = useMemo(
357 |     () =>
358 |       FormGrid.createFormGrid({
359 |         maxColumns: 4,
360 |         maxWidth: 240,
361 |         maxRows: maxRows,
362 |         shouldVisible: (node, grid) => {
363 |           if (node.index === grid.childSize - 1) return true
364 |           if (grid.maxRows === Infinity) return true
365 |           return node.shadowRow < maxRows + 1
366 |         },
367 |       }),
368 |     []
369 |   )
370 |   const expanded = grid.maxRows === Infinity
371 |   const realRows = grid.shadowRows
372 |   const computeRows = grid.fullnessLastColumn
373 |     ? grid.shadowRows - 1
374 |     : grid.shadowRows
375 | 
376 |   const toggle = () => {
377 |     if (grid.maxRows === Infinity) {
378 |       grid.maxRows = maxRows
379 |     } else {
380 |       grid.maxRows = Infinity
381 |     }
382 |   }
383 |   const takeType = () => {
384 |     if (realRows < maxRows + 1) return 'incomplete-wrap'
385 |     if (computeRows > maxRows) return 'collapsible'
386 |     return 'complete-wrap'
387 |   }
388 |   return {
389 |     grid,
390 |     expanded,
391 |     toggle,
392 |     type: takeType(),
393 |   }
394 | }
395 | 
396 | const QueryForm: React.FC = observer((props) => {
397 |   const { grid, expanded, toggle, type } = useCollapseGrid(1)
398 | 
399 |   const renderActions = () => {
400 |     return (
401 |       <Fragment>
402 |         <Submit onSubmit={console.log}>Query</Submit>
403 |         <Reset>Reset</Reset>
404 |       </Fragment>
405 |     )
406 |   }
407 | 
408 |   const renderButtonGroup = () => {
409 |     if (type === 'incomplete-wrap') {
410 |       return (
411 |         <FormButtonGroup.FormItem>
412 |           <FormButtonGroup>{renderActions()}</FormButtonGroup>
413 |         </FormButtonGroup.FormItem>
414 |       )
415 |     }
416 |     if (type === 'collapsible') {
417 |       return (
418 |         <Fragment>
419 |           <FormButtonGroup>
420 |             <a
421 |               href=""
422 |               onClick={(e) => {
423 |                 e.preventDefault()
424 |                 toggle()
425 |               }}
426 |             >
427 |               {expanded ? 'Fold' : 'UnFold'}
428 |             </a>
429 |           </FormButtonGroup>
430 |           <FormButtonGroup align="right">{renderActions()}</FormButtonGroup>
431 |         </Fragment>
432 |       )
433 |     }
434 |     return (
435 |       <FormButtonGroup align="right" style={{ display: 'flex', width: '100%' }}>
436 |         {renderActions()}
437 |       </FormButtonGroup>
438 |     )
439 |   }
440 | 
441 |   return (
442 |     <Form {...props} layout="vertical" feedbackLayout="terse">
443 |       <FormGrid grid={grid}>
444 |         {props.children}
445 |         <FormGrid.GridColumn
446 |           gridSpan={-1}
447 |           style={{ display: 'flex', justifyContent: 'space-between' }}
448 |         >
449 |           {renderButtonGroup()}
450 |         </FormGrid.GridColumn>
451 |       </FormGrid>
452 |     </Form>
453 |   )
454 | })
455 | 
456 | const SchemaField = createSchemaField({
457 |   components: {
458 |     QueryForm,
459 |     Input,
460 |     Select,
461 |     DatePicker,
462 |     FormItem,
463 |   },
464 | })
465 | 
466 | export default () => {
467 |   const form = useMemo(() => createForm(), [])
468 |   return (
469 |     <FormProvider form={form}>
470 |       <SchemaField>
471 |         <SchemaField.Object x-component="QueryForm">
472 |           <SchemaField.String
473 |             name="input1"
474 |             title="Input 1"
475 |             x-component="Input"
476 |             x-decorator="FormItem"
477 |           />
478 |           <SchemaField.String
479 |             name="input2"
480 |             title="Input 2"
481 |             x-component="Input"
482 |             x-decorator="FormItem"
483 |           />
484 | 
485 |           <SchemaField.String
486 |             name="select1"
487 |             title="Select 1"
488 |             x-component="Select"
489 |             x-decorator="FormItem"
490 |           />
491 |           <SchemaField.String
492 |             name="select2"
493 |             title="Select 2"
494 |             x-component="Select"
495 |             x-decorator="FormItem"
496 |           />
497 |           <SchemaField.String
498 |             name="date"
499 |             title="DatePicker"
500 |             x-component="DatePicker"
501 |             x-decorator="FormItem"
502 |           />
503 |           <SchemaField.String
504 |             name="dateRange"
505 |             title="DatePicker.RangePicker"
506 |             x-component="DatePicker.RangePicker"
507 |             x-decorator="FormItem"
508 |             x-decorator-props={{
509 |               gridSpan: 2,
510 |             }}
511 |           />
512 |           <SchemaField.String
513 |             name="select3"
514 |             title="Select 3"
515 |             x-component="Select"
516 |             x-decorator="FormItem"
517 |           />
518 |         </SchemaField.Object>
519 |       </SchemaField>
520 |     </FormProvider>
521 |   )
522 | }
523 | ```
524 | 
525 | ## API
526 | 
527 | ### FormGrid
528 | 
529 | | Property name | Type                   | Description                                                                       | Default value     |
530 | | ------------- | ---------------------- | --------------------------------------------------------------------------------- | ----------------- |
531 | | minWidth      | `number \| number[]`   | Minimum element width                                                             | 100               |
532 | | maxWidth      | `number \| number[]`   | Maximum element width                                                             | -                 |
533 | | minColumns    | `number \| number[]`   | Minimum number of columns                                                         | 0                 |
534 | | maxColumns    | `number \| number[]`   | Maximum number of columns                                                         | -                 |
535 | | breakpoints   | number[]               | Container size breakpoints                                                        | `[720,1280,1920]` |
536 | | columnGap     | number                 | Column spacing                                                                    | 8                 |
537 | | rowGap        | number                 | Row spacing                                                                       | 4                 |
538 | | colWrap       | boolean                | Wrap                                                                              | true              |
539 | | strictAutoFit | boolean                | Is width strictly limited by maxWidth                                             | false             |
540 | | shouldVisible | `(node,grid)=>boolean` | Whether to show the current node                                                  | `()=>true`        |
541 | | grid          | `Grid`                 | Grid instance passed in from outside, used to implement more complex layout logic | -                 |
542 | 
543 | note:
544 | 
545 | - minWidth takes priority over minColumn
546 | - maxWidth has priority over maxColumn
547 | - The array format of minWidth/maxWidth/minColumns/maxColumns represents the mapping with the breakpoint array
548 | 
549 | ### FormGrid.GridColumn
550 | 
551 | | Property name | Type   | Description                                                                                                              | Default value |
552 | | ------------- | ------ | ------------------------------------------------------------------------------------------------------------------------ | ------------- |
553 | | gridSpan      | number | The number of columns spanned by the element, if it is -1, it will automatically fill the cell across columns in reverse | 1             |
554 | 
555 | ### FormGrid.createFormGrid
556 | 
557 | Read the Grid instance from the context
558 | 
559 | ```ts
560 | interface createFormGrid {
561 |   (props: IGridProps): Grid
562 | }
563 | ```
564 | 
565 | - IGridProps reference FormGrid properties
566 | - Grid instance attribute method reference https://github.com/alibaba/formily/tree/formily_next/packages/grid
567 | 
568 | ### FormGrid.useFormGrid
569 | 
570 | Read the Grid instance from the context
571 | 
572 | ```ts
573 | interface useFormGrid {
574 |   (): Grid
575 | }
576 | ```
577 | 
578 | - Grid instance attribute method reference https://github.com/alibaba/formily/tree/formily_next/packages/grid
579 | 
```

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

```markdown
  1 | # FormGrid
  2 | 
  3 | > FormGrid component
  4 | 
  5 | ## Markup Schema example
  6 | 
  7 | ```tsx
  8 | import React from 'react'
  9 | import { FormItem, Input, FormGrid } from '@formily/next'
 10 | import { FormProvider, createSchemaField } from '@formily/react'
 11 | import { createForm } from '@formily/core'
 12 | 
 13 | const SchemaField = createSchemaField({
 14 |   components: {
 15 |     FormItem,
 16 |     Input,
 17 |     FormGrid,
 18 |   },
 19 | })
 20 | 
 21 | const form = createForm()
 22 | 
 23 | export default () => {
 24 |   return (
 25 |     <FormProvider form={form}>
 26 |       <SchemaField>
 27 |         <SchemaField.Void
 28 |           x-component="FormGrid"
 29 |           x-component-props={{
 30 |             maxColumns: 3,
 31 |             minColumns: 2,
 32 |           }}
 33 |         >
 34 |           <SchemaField.String
 35 |             name="aaa"
 36 |             title="aaa"
 37 |             x-decorator="FormItem"
 38 |             x-decorator-props={{ gridSpan: 2 }}
 39 |             x-component="Input"
 40 |           />
 41 |           <SchemaField.String
 42 |             name="bbb"
 43 |             title="bbb"
 44 |             x-decorator="FormItem"
 45 |             x-component="Input"
 46 |           />
 47 |           <SchemaField.String
 48 |             name="ccc"
 49 |             title="ccc"
 50 |             x-decorator="FormItem"
 51 |             x-component="Input"
 52 |           />
 53 |           <SchemaField.String
 54 |             name="ddd"
 55 |             title="ddd"
 56 |             x-decorator="FormItem"
 57 |             x-component="Input"
 58 |           />
 59 |           <SchemaField.String
 60 |             name="eee"
 61 |             title="eee"
 62 |             x-decorator="FormItem"
 63 |             x-component="Input"
 64 |           />
 65 |           <SchemaField.String
 66 |             name="fff"
 67 |             title="fff"
 68 |             x-decorator="FormItem"
 69 |             x-component="Input"
 70 |           />
 71 |           <SchemaField.String
 72 |             name="ggg"
 73 |             title="ggg"
 74 |             x-decorator="FormItem"
 75 |             x-component="Input"
 76 |           />
 77 |         </SchemaField.Void>
 78 |       </SchemaField>
 79 |     </FormProvider>
 80 |   )
 81 | }
 82 | ```
 83 | 
 84 | ## JSON Schema case
 85 | 
 86 | ```tsx
 87 | import React from 'react'
 88 | import { FormItem, Input, FormGrid } from '@formily/next'
 89 | import { FormProvider, createSchemaField } from '@formily/react'
 90 | import { createForm } from '@formily/core'
 91 | 
 92 | const SchemaField = createSchemaField({
 93 |   components: {
 94 |     FormItem,
 95 |     Input,
 96 |     FormGrid,
 97 |   },
 98 | })
 99 | 
100 | const form = createForm()
101 | 
102 | const schema = {
103 |   type: 'object',
104 |   properties: {
105 |     grid: {
106 |       type: 'void',
107 |       'x-component': 'FormGrid',
108 |       'x-component-props': {
109 |         minColumns: [4, 6, 10],
110 |       },
111 |       properties: {
112 |         aaa: {
113 |           type: 'string',
114 |           title: 'AAA',
115 |           'x-decorator': 'FormItem',
116 |           'x-component': 'Input',
117 |         },
118 |         bbb: {
119 |           type: 'string',
120 |           title: 'BBB',
121 |           'x-decorator': 'FormItem',
122 |           'x-component': 'Input',
123 |         },
124 |         ccc: {
125 |           type: 'string',
126 |           title: 'CCC',
127 |           'x-decorator': 'FormItem',
128 |           'x-component': 'Input',
129 |         },
130 |         ddd: {
131 |           type: 'string',
132 |           title: 'DDD',
133 |           'x-decorator': 'FormItem',
134 |           'x-component': 'Input',
135 |         },
136 |         eee: {
137 |           type: 'string',
138 |           title: 'EEE',
139 |           'x-decorator': 'FormItem',
140 |           'x-component': 'Input',
141 |         },
142 |         fff: {
143 |           type: 'string',
144 |           title: 'FFF',
145 |           'x-decorator': 'FormItem',
146 |           'x-component': 'Input',
147 |         },
148 |         ggg: {
149 |           type: 'string',
150 |           title: 'GGG',
151 |           'x-decorator': 'FormItem',
152 |           'x-component': 'Input',
153 |         },
154 |       },
155 |     },
156 |   },
157 | }
158 | 
159 | export default () => {
160 |   return (
161 |     <FormProvider form={form}>
162 |       <SchemaField schema={schema} />
163 |     </FormProvider>
164 |   )
165 | }
166 | ```
167 | 
168 | ## Native case
169 | 
170 | ```tsx
171 | import React from 'react'
172 | import { FormGrid } from '@formily/next'
173 | 
174 | const { GridColumn } = FormGrid
175 | const Cell = ({ children }) => {
176 |   return (
177 |     <div
178 |       style={{
179 |         backgroundColor: '#AAA',
180 |         color: '#FFF',
181 |         height: 30,
182 |         display: 'flex',
183 |         alignItems: 'center',
184 |         padding: '0 10px',
185 |       }}
186 |     >
187 |       {children}
188 |     </div>
189 |   )
190 | }
191 | export default () => {
192 |   return (
193 |     <React.Fragment>
194 |       <p>maxColumns 3 + minColumns 2</p>
195 |       <FormGrid maxColumns={3} minColumns={2} columnGap={4}>
196 |         <GridColumn gridSpan={4}>
197 |           <Cell>1</Cell>
198 |         </GridColumn>
199 |         <GridColumn>
200 |           <Cell>2</Cell>
201 |         </GridColumn>
202 |         <GridColumn>
203 |           <Cell>3</Cell>
204 |         </GridColumn>
205 |         <GridColumn>
206 |           <Cell>4</Cell>
207 |         </GridColumn>
208 |         <GridColumn>
209 |           <Cell>5</Cell>
210 |         </GridColumn>
211 |         <GridColumn>
212 |           <Cell>6</Cell>
213 |         </GridColumn>
214 |       </FormGrid>
215 |       <p>maxColumns 3</p>
216 |       <FormGrid maxColumns={3} columnGap={4}>
217 |         <GridColumn gridSpan={2}>
218 |           <Cell>1</Cell>
219 |         </GridColumn>
220 |         <GridColumn>
221 |           <Cell>2</Cell>
222 |         </GridColumn>
223 |         <GridColumn>
224 |           <Cell>3</Cell>
225 |         </GridColumn>
226 |         <GridColumn>
227 |           <Cell>4</Cell>
228 |         </GridColumn>
229 |         <GridColumn>
230 |           <Cell>5</Cell>
231 |         </GridColumn>
232 |         <GridColumn>
233 |           <Cell>6</Cell>
234 |         </GridColumn>
235 |       </FormGrid>
236 |       <p>minColumns 2</p>
237 |       <FormGrid minColumns={2} columnGap={4}>
238 |         <GridColumn gridSpan={2}>
239 |           <Cell>1</Cell>
240 |         </GridColumn>
241 |         <GridColumn>
242 |           <Cell>2</Cell>
243 |         </GridColumn>
244 |         <GridColumn>
245 |           <Cell>3</Cell>
246 |         </GridColumn>
247 |         <GridColumn>
248 |           <Cell>4</Cell>
249 |         </GridColumn>
250 |         <GridColumn>
251 |           <Cell>5</Cell>
252 |         </GridColumn>
253 |         <GridColumn>
254 |           <Cell>6</Cell>
255 |         </GridColumn>
256 |       </FormGrid>
257 |       <p>Null</p>
258 |       <FormGrid columnGap={4}>
259 |         <GridColumn gridSpan={2}>
260 |           <Cell>1</Cell>
261 |         </GridColumn>
262 |         <GridColumn>
263 |           <Cell>2</Cell>
264 |         </GridColumn>
265 |         <GridColumn>
266 |           <Cell>3</Cell>
267 |         </GridColumn>
268 |         <GridColumn>
269 |           <Cell>4</Cell>
270 |         </GridColumn>
271 |         <GridColumn>
272 |           <Cell>5</Cell>
273 |         </GridColumn>
274 |         <GridColumn>
275 |           <Cell>6</Cell>
276 |         </GridColumn>
277 |       </FormGrid>
278 |       <p>minWidth 150 +maxColumns 3</p>
279 |       <FormGrid minWidth={150} maxColumns={3} columnGap={4}>
280 |         <GridColumn gridSpan={2}>
281 |           <Cell>1</Cell>
282 |         </GridColumn>
283 |         <GridColumn>
284 |           <Cell>2</Cell>
285 |         </GridColumn>
286 |         <GridColumn>
287 |           <Cell>3</Cell>
288 |         </GridColumn>
289 |         <GridColumn>
290 |           <Cell>4</Cell>
291 |         </GridColumn>
292 |         <GridColumn>
293 |           <Cell>5</Cell>
294 |         </GridColumn>
295 |         <GridColumn>
296 |           <Cell>6</Cell>
297 |         </GridColumn>
298 |       </FormGrid>
299 |       <p>maxWidth 120+minColumns 2</p>
300 |       <FormGrid maxWidth={120} minColumns={2} columnGap={4}>
301 |         <GridColumn gridSpan={2}>
302 |           <Cell>1</Cell>
303 |         </GridColumn>
304 |         <GridColumn>
305 |           <Cell>2</Cell>
306 |         </GridColumn>
307 |         <GridColumn>
308 |           <Cell>3</Cell>
309 |         </GridColumn>
310 |         <GridColumn>
311 |           <Cell>4</Cell>
312 |         </GridColumn>
313 |         <GridColumn>
314 |           <Cell>5</Cell>
315 |         </GridColumn>
316 |         <GridColumn>
317 |           <Cell>6</Cell>
318 |         </GridColumn>
319 |       </FormGrid>
320 |       <p>maxWidth 120 + gridSpan -1</p>
321 |       <FormGrid maxWidth={120} columnGap={4}>
322 |         <GridColumn gridSpan={2}>
323 |           <Cell>1</Cell>
324 |         </GridColumn>
325 |         <GridColumn>
326 |           <Cell>2</Cell>
327 |         </GridColumn>
328 |         <GridColumn gridSpan={-1}>
329 |           <Cell>3</Cell>
330 |         </GridColumn>
331 |       </FormGrid>
332 |     </React.Fragment>
333 |   )
334 | }
335 | ```
336 | 
337 | ## Query Form case
338 | 
339 | ```tsx
340 | import React, { useMemo, Fragment } from 'react'
341 | import { createForm } from '@formily/core'
342 | import { createSchemaField, FormProvider, observer } from '@formily/react'
343 | import {
344 |   Form,
345 |   Input,
346 |   Select,
347 |   DatePicker,
348 |   FormItem,
349 |   FormGrid,
350 |   Submit,
351 |   Reset,
352 |   FormButtonGroup,
353 | } from '@formily/next'
354 | 
355 | const useCollapseGrid = (maxRows: number) => {
356 |   const grid = useMemo(
357 |     () =>
358 |       FormGrid.createFormGrid({
359 |         maxColumns: 4,
360 |         maxWidth: 240,
361 |         maxRows: maxRows,
362 |         shouldVisible: (node, grid) => {
363 |           if (node.index === grid.childSize - 1) return true
364 |           if (grid.maxRows === Infinity) return true
365 |           return node.shadowRow < maxRows + 1
366 |         },
367 |       }),
368 |     []
369 |   )
370 |   const expanded = grid.maxRows === Infinity
371 |   const realRows = grid.shadowRows
372 |   const computeRows = grid.fullnessLastColumn
373 |     ? grid.shadowRows - 1
374 |     : grid.shadowRows
375 | 
376 |   const toggle = () => {
377 |     if (grid.maxRows === Infinity) {
378 |       grid.maxRows = maxRows
379 |     } else {
380 |       grid.maxRows = Infinity
381 |     }
382 |   }
383 |   const takeType = () => {
384 |     if (realRows < maxRows + 1) return 'incomplete-wrap'
385 |     if (computeRows > maxRows) return 'collapsible'
386 |     return 'complete-wrap'
387 |   }
388 |   return {
389 |     grid,
390 |     expanded,
391 |     toggle,
392 |     type: takeType(),
393 |   }
394 | }
395 | 
396 | const QueryForm: React.FC = observer((props) => {
397 |   const { grid, expanded, toggle, type } = useCollapseGrid(1)
398 | 
399 |   const renderActions = () => {
400 |     return (
401 |       <Fragment>
402 |         <Submit onSubmit={console.log}>Query</Submit>
403 |         <Reset>Reset</Reset>
404 |       </Fragment>
405 |     )
406 |   }
407 | 
408 |   const renderButtonGroup = () => {
409 |     if (type === 'incomplete-wrap') {
410 |       return (
411 |         <FormButtonGroup.FormItem>
412 |           <FormButtonGroup>{renderActions()}</FormButtonGroup>
413 |         </FormButtonGroup.FormItem>
414 |       )
415 |     }
416 |     if (type === 'collapsible') {
417 |       return (
418 |         <Fragment>
419 |           <FormButtonGroup>
420 |             <a
421 |               href=""
422 |               onClick={(e) => {
423 |                 e.preventDefault()
424 |                 toggle()
425 |               }}
426 |             >
427 |               {expanded ? 'Fold' : 'UnFold'}
428 |             </a>
429 |           </FormButtonGroup>
430 |           <FormButtonGroup align="right">{renderActions()}</FormButtonGroup>
431 |         </Fragment>
432 |       )
433 |     }
434 |     return (
435 |       <FormButtonGroup align="right" style={{ display: 'flex', width: '100%' }}>
436 |         {renderActions()}
437 |       </FormButtonGroup>
438 |     )
439 |   }
440 | 
441 |   return (
442 |     <Form {...props} layout="vertical" feedbackLayout="terse">
443 |       <FormGrid grid={grid}>
444 |         {props.children}
445 |         <FormGrid.GridColumn
446 |           gridSpan={-1}
447 |           style={{ display: 'flex', justifyContent: 'space-between' }}
448 |         >
449 |           {renderButtonGroup()}
450 |         </FormGrid.GridColumn>
451 |       </FormGrid>
452 |     </Form>
453 |   )
454 | })
455 | 
456 | const SchemaField = createSchemaField({
457 |   components: {
458 |     QueryForm,
459 |     Input,
460 |     Select,
461 |     DatePicker,
462 |     FormItem,
463 |   },
464 | })
465 | 
466 | export default () => {
467 |   const form = useMemo(() => createForm(), [])
468 |   return (
469 |     <FormProvider form={form}>
470 |       <SchemaField>
471 |         <SchemaField.Object x-component="QueryForm">
472 |           <SchemaField.String
473 |             name="input1"
474 |             title="Input 1"
475 |             x-component="Input"
476 |             x-decorator="FormItem"
477 |           />
478 |           <SchemaField.String
479 |             name="input2"
480 |             title="Input 2"
481 |             x-component="Input"
482 |             x-decorator="FormItem"
483 |           />
484 | 
485 |           <SchemaField.String
486 |             name="select1"
487 |             title="Select 1"
488 |             x-component="Select"
489 |             x-decorator="FormItem"
490 |           />
491 |           <SchemaField.String
492 |             name="select2"
493 |             title="Select 2"
494 |             x-component="Select"
495 |             x-decorator="FormItem"
496 |           />
497 |           <SchemaField.String
498 |             name="date"
499 |             title="DatePicker"
500 |             x-component="DatePicker"
501 |             x-decorator="FormItem"
502 |           />
503 |           <SchemaField.String
504 |             name="dateRange"
505 |             title="DatePicker.RangePicker"
506 |             x-component="DatePicker.RangePicker"
507 |             x-decorator="FormItem"
508 |             x-decorator-props={{
509 |               gridSpan: 2,
510 |             }}
511 |           />
512 |           <SchemaField.String
513 |             name="select3"
514 |             title="Select 3"
515 |             x-component="Select"
516 |             x-decorator="FormItem"
517 |           />
518 |         </SchemaField.Object>
519 |       </SchemaField>
520 |     </FormProvider>
521 |   )
522 | }
523 | ```
524 | 
525 | ## API
526 | 
527 | ### FormGrid
528 | 
529 | | Property name | Type                   | Description                                                                       | Default value     |
530 | | ------------- | ---------------------- | --------------------------------------------------------------------------------- | ----------------- |
531 | | minWidth      | `number \| number[]`   | Minimum element width                                                             | 100               |
532 | | maxWidth      | `number \| number[]`   | Maximum element width                                                             | -                 |
533 | | minColumns    | `number \| number[]`   | Minimum number of columns                                                         | 0                 |
534 | | maxColumns    | `number \| number[]`   | Maximum number of columns                                                         | -                 |
535 | | breakpoints   | number[]               | Container size breakpoints                                                        | `[720,1280,1920]` |
536 | | columnGap     | number                 | Column spacing                                                                    | 8                 |
537 | | rowGap        | number                 | Row spacing                                                                       | 4                 |
538 | | colWrap       | boolean                | Wrap                                                                              | true              |
539 | | strictAutoFit | boolean                | Is width strictly limited by maxWidth                                             | false             |
540 | | shouldVisible | `(node,grid)=>boolean` | Whether to show the current node                                                  | `()=>true`        |
541 | | grid          | `Grid`                 | Grid instance passed in from outside, used to implement more complex layout logic | -                 |
542 | 
543 | note:
544 | 
545 | - minWidth takes priority over minColumn
546 | - maxWidth has priority over maxColumn
547 | - The array format of minWidth/maxWidth/minColumns/maxColumns represents the mapping with the breakpoint array
548 | 
549 | ### FormGrid.GridColumn
550 | 
551 | | Property name | Type   | Description                                                                                                              | Default value |
552 | | ------------- | ------ | ------------------------------------------------------------------------------------------------------------------------ | ------------- |
553 | | gridSpan      | number | The number of columns spanned by the element, if it is -1, it will automatically fill the cell across columns in reverse | 1             |
554 | 
555 | ### FormGrid.createFormGrid
556 | 
557 | Read the Grid instance from the context
558 | 
559 | ```ts
560 | interface createFormGrid {
561 |   (props: IGridProps): Grid
562 | }
563 | ```
564 | 
565 | - IGridProps reference FormGrid properties
566 | - Grid instance attribute method reference https://github.com/alibaba/formily/tree/formily_next/packages/grid
567 | 
568 | ### FormGrid.useFormGrid
569 | 
570 | Read the Grid instance from the context
571 | 
572 | ```ts
573 | interface useFormGrid {
574 |   (): Grid
575 | }
576 | ```
577 | 
578 | - Grid instance attribute method reference https://github.com/alibaba/formily/tree/formily_next/packages/grid
579 | 
```
Page 31/52FirstPrevNextLast