#
tokens: 47190/50000 6/1152 files (page 29/52)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 29 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/grid/src/index.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { define, observable, batch, reaction } from '@formily/reactive'
  2 | import { ChildListMutationObserver } from './observer'
  3 | import { ResizeObserver } from '@juggle/resize-observer'
  4 | export interface IGridOptions {
  5 |   maxRows?: number
  6 |   maxColumns?: number | number[]
  7 |   minColumns?: number | number[]
  8 |   maxWidth?: number | number[]
  9 |   minWidth?: number | number[]
 10 |   breakpoints?: number[]
 11 |   columnGap?: number
 12 |   rowGap?: number
 13 |   colWrap?: boolean
 14 |   strictAutoFit?: boolean
 15 |   shouldVisible?: (node: GridNode, grid: Grid<HTMLElement>) => boolean
 16 |   onDigest?: (grid: Grid<HTMLElement>) => void
 17 |   onInitialized?: (grid: Grid<HTMLElement>) => void
 18 | }
 19 | 
 20 | const SpanRegExp = /span\s*(\d+)/
 21 | 
 22 | const isValid = (value: any) => value !== undefined && value !== null
 23 | 
 24 | const calcBreakpointIndex = (breakpoints: number[], width: number) => {
 25 |   if (Array.isArray(breakpoints)) {
 26 |     for (let i = 0; i < breakpoints.length; i++) {
 27 |       if (width <= breakpoints[i]) {
 28 |         return i
 29 |       }
 30 |     }
 31 |   }
 32 |   return -1
 33 | }
 34 | 
 35 | const calcFactor = <T>(value: T | T[], breakpointIndex: number): T => {
 36 |   if (Array.isArray(value)) {
 37 |     if (breakpointIndex === -1) return value[0]
 38 |     return value[breakpointIndex] ?? value[value.length - 1]
 39 |   } else {
 40 |     return value
 41 |   }
 42 | }
 43 | 
 44 | const parseGridNode = (elements: HTMLCollection): GridNode[] => {
 45 |   return Array.from(elements).reduce((buf, element: HTMLElement, index) => {
 46 |     const style = getComputedStyle(element)
 47 |     const visible = !(style.display === 'none')
 48 |     const origin = element.getAttribute('data-grid-span')
 49 |     const span = parseSpan(style.gridColumnStart) ?? 1
 50 |     const originSpan = Number(origin ?? span)
 51 |     const node: GridNode = {
 52 |       index,
 53 |       span,
 54 |       visible,
 55 |       originSpan,
 56 |       element,
 57 |     }
 58 |     if (!origin) {
 59 |       element.setAttribute('data-grid-span', String(span))
 60 |     }
 61 |     return buf.concat(node)
 62 |   }, [])
 63 | }
 64 | 
 65 | const calcChildTotalColumns = (nodes: GridNode[], shadow = false) =>
 66 |   nodes.reduce((buf, node) => {
 67 |     if (!shadow) {
 68 |       if (!node.visible) return buf
 69 |     }
 70 |     if (node.originSpan === -1) return buf + (node.span ?? 1)
 71 |     return buf + node.span
 72 |   }, 0)
 73 | 
 74 | const calcChildOriginTotalColumns = (nodes: GridNode[], shadow = false) =>
 75 |   nodes.reduce((buf, node) => {
 76 |     if (!shadow) {
 77 |       if (!node.visible) return buf
 78 |     }
 79 |     if (node.originSpan === -1) return buf + (node.span ?? 1)
 80 |     return buf + node.originSpan
 81 |   }, 0)
 82 | 
 83 | const calcSatisfyColumns = (
 84 |   width: number,
 85 |   maxColumns: number,
 86 |   minColumns: number,
 87 |   maxWidth: number,
 88 |   minWidth: number,
 89 |   gap: number
 90 | ) => {
 91 |   const results = []
 92 |   for (let columns = minColumns; columns <= maxColumns; columns++) {
 93 |     const innerWidth = width - (columns - 1) * gap
 94 |     const columnWidth = innerWidth / columns
 95 |     if (columnWidth >= minWidth && columnWidth <= maxWidth) {
 96 |       results.push(columns)
 97 |     } else if (columnWidth < minWidth) {
 98 |       results.push(Math.min(Math.floor(innerWidth / minWidth), maxColumns))
 99 |     } else if (columnWidth > maxWidth) {
100 |       results.push(Math.min(Math.floor(innerWidth / maxWidth), maxColumns))
101 |     }
102 |   }
103 |   return Math.max(...results)
104 | }
105 | 
106 | const parseSpan = (gridColumnStart: string) => {
107 |   return Number(String(gridColumnStart).match(SpanRegExp)?.[1] ?? 1)
108 | }
109 | 
110 | const factor = <T>(value: T | T[], grid: Grid<HTMLElement>): T =>
111 |   isValid(value) ? calcFactor(value as any, grid.breakpoint) : value
112 | 
113 | const resolveChildren = (grid: Grid<HTMLElement>) => {
114 |   let walked = 0,
115 |     shadowWalked = 0,
116 |     rowIndex = 0,
117 |     shadowRowIndex = 0
118 |   if (!grid.ready) return
119 |   grid.children = grid.children.map((node) => {
120 |     const columnIndex = walked % grid.columns
121 |     const shadowColumnIndex = shadowWalked % grid.columns
122 |     const remainColumns = grid.columns - columnIndex
123 |     const originSpan = node.originSpan
124 |     const targetSpan = originSpan > grid.columns ? grid.columns : originSpan
125 |     const span = grid.options.strictAutoFit
126 |       ? targetSpan
127 |       : targetSpan > remainColumns
128 |       ? remainColumns
129 |       : targetSpan
130 |     const gridColumn =
131 |       originSpan === -1 ? `span ${remainColumns} / -1` : `span ${span} / auto`
132 |     if (node.element.style.gridColumn !== gridColumn) {
133 |       node.element.style.gridColumn = gridColumn
134 |     }
135 |     if (node.visible) {
136 |       walked += span
137 |     }
138 |     shadowWalked += span
139 |     if (columnIndex === 0) {
140 |       rowIndex++
141 |     }
142 |     if (shadowColumnIndex == 0) {
143 |       shadowRowIndex++
144 |     }
145 |     node.shadowRow = shadowRowIndex
146 |     node.shadowColumn = shadowColumnIndex + 1
147 |     if (node.visible) {
148 |       node.row = rowIndex
149 |       node.column = columnIndex + 1
150 |     }
151 |     if (grid.options?.shouldVisible) {
152 |       if (!grid.options.shouldVisible(node, grid)) {
153 |         if (node.visible) {
154 |           node.element.style.display = 'none'
155 |         }
156 |         node.visible = false
157 |       } else {
158 |         if (!node.visible) {
159 |           node.element.style.display = ''
160 |         }
161 |         node.visible = true
162 |       }
163 |     }
164 |     return node
165 |   })
166 | }
167 | 
168 | const nextTick = (callback?: () => void) => Promise.resolve(0).then(callback)
169 | 
170 | export type GridNode = {
171 |   index?: number
172 |   visible?: boolean
173 |   column?: number
174 |   shadowColumn?: number
175 |   row?: number
176 |   shadowRow?: number
177 |   span?: number
178 |   originSpan?: number
179 |   element?: HTMLElement
180 | }
181 | export class Grid<Container extends HTMLElement> {
182 |   options: IGridOptions
183 |   width = 0
184 |   height = 0
185 |   container: Container
186 |   children: GridNode[] = []
187 |   childTotalColumns = 0
188 |   shadowChildTotalColumns = 0
189 |   childOriginTotalColumns = 0
190 |   shadowChildOriginTotalColumns = 0
191 |   ready = false
192 |   constructor(options?: IGridOptions) {
193 |     this.options = {
194 |       breakpoints: [720, 1280, 1920],
195 |       columnGap: 8,
196 |       rowGap: 4,
197 |       minWidth: 100,
198 |       colWrap: true,
199 |       strictAutoFit: false,
200 |       ...options,
201 |     }
202 |     define(this, {
203 |       options: observable.shallow,
204 |       width: observable.ref,
205 |       height: observable.ref,
206 |       ready: observable.ref,
207 |       children: observable.ref,
208 |       childOriginTotalColumns: observable.ref,
209 |       shadowChildOriginTotalColumns: observable.ref,
210 |       shadowChildTotalColumns: observable.ref,
211 |       childTotalColumns: observable.ref,
212 |       columns: observable.computed,
213 |       templateColumns: observable.computed,
214 |       gap: observable.computed,
215 |       maxColumns: observable.computed,
216 |       minColumns: observable.computed,
217 |       maxWidth: observable.computed,
218 |       minWidth: observable.computed,
219 |       breakpoints: observable.computed,
220 |       breakpoint: observable.computed,
221 |       rowGap: observable.computed,
222 |       columnGap: observable.computed,
223 |       colWrap: observable.computed,
224 |     })
225 |   }
226 | 
227 |   set breakpoints(breakpoints) {
228 |     this.options.breakpoints = breakpoints
229 |   }
230 | 
231 |   get breakpoints() {
232 |     return this.options.breakpoints
233 |   }
234 | 
235 |   get breakpoint() {
236 |     return calcBreakpointIndex(this.options.breakpoints, this.width)
237 |   }
238 | 
239 |   set maxWidth(maxWidth) {
240 |     this.options.maxWidth = maxWidth
241 |   }
242 | 
243 |   get maxWidth() {
244 |     return factor(this.options.maxWidth, this) ?? Infinity
245 |   }
246 | 
247 |   set minWidth(minWidth) {
248 |     this.options.minWidth = minWidth
249 |   }
250 | 
251 |   get minWidth() {
252 |     return factor(this.options.minWidth, this) ?? 100
253 |   }
254 | 
255 |   set maxColumns(maxColumns) {
256 |     this.options.maxColumns = maxColumns
257 |   }
258 | 
259 |   get maxColumns() {
260 |     return factor(this.options.maxColumns, this) ?? Infinity
261 |   }
262 | 
263 |   set maxRows(maxRows) {
264 |     this.options.maxRows = maxRows
265 |   }
266 | 
267 |   get maxRows() {
268 |     return this.options.maxRows ?? Infinity
269 |   }
270 | 
271 |   set minColumns(minColumns) {
272 |     this.options.minColumns = minColumns
273 |   }
274 | 
275 |   get minColumns() {
276 |     return factor(this.options.minColumns, this) ?? 1
277 |   }
278 | 
279 |   set rowGap(rowGap) {
280 |     this.options.rowGap = rowGap
281 |   }
282 | 
283 |   get rowGap() {
284 |     return factor(this.options.rowGap, this) ?? 5
285 |   }
286 | 
287 |   set columnGap(columnGap) {
288 |     this.options.columnGap = columnGap
289 |   }
290 | 
291 |   get columnGap() {
292 |     return factor(this.options.columnGap, this) ?? 10
293 |   }
294 | 
295 |   set colWrap(colWrap) {
296 |     this.options.colWrap = colWrap
297 |   }
298 | 
299 |   get colWrap() {
300 |     return factor(this.options.colWrap, this) ?? true
301 |   }
302 | 
303 |   get columns() {
304 |     if (!this.ready) return 0
305 | 
306 |     const originTotalColumns = this.childOriginTotalColumns
307 | 
308 |     if (this.colWrap === false) {
309 |       return originTotalColumns
310 |     }
311 | 
312 |     const baseColumns = this.childSize
313 | 
314 |     const strictMaxWidthColumns = Math.round(
315 |       this.width / (this.maxWidth + this.columnGap)
316 |     )
317 | 
318 |     const looseMaxWidthColumns = Math.min(
319 |       originTotalColumns,
320 |       strictMaxWidthColumns
321 |     )
322 | 
323 |     const maxWidthColumns = this.options.strictAutoFit
324 |       ? strictMaxWidthColumns
325 |       : looseMaxWidthColumns
326 | 
327 |     const strictMinWidthColumns = Math.round(
328 |       this.width / (this.minWidth + this.columnGap)
329 |     )
330 | 
331 |     const looseMinWidthColumns = Math.min(
332 |       originTotalColumns,
333 |       strictMinWidthColumns
334 |     )
335 | 
336 |     const minWidthColumns = this.options.strictAutoFit
337 |       ? strictMinWidthColumns
338 |       : looseMinWidthColumns
339 | 
340 |     const minCalculatedColumns = Math.min(
341 |       baseColumns,
342 |       originTotalColumns,
343 |       maxWidthColumns,
344 |       minWidthColumns
345 |     )
346 | 
347 |     const maxCalculatedColumns = Math.max(
348 |       baseColumns,
349 |       originTotalColumns,
350 |       maxWidthColumns,
351 |       minWidthColumns
352 |     )
353 | 
354 |     const finalColumns = calcSatisfyColumns(
355 |       this.width,
356 |       maxCalculatedColumns,
357 |       minCalculatedColumns,
358 |       this.maxWidth,
359 |       this.minWidth,
360 |       this.columnGap
361 |     )
362 |     if (finalColumns >= this.maxColumns) {
363 |       return this.maxColumns
364 |     }
365 |     if (finalColumns <= this.minColumns) {
366 |       return this.minColumns
367 |     }
368 |     return finalColumns
369 |   }
370 | 
371 |   get rows() {
372 |     return Math.ceil(this.childTotalColumns / this.columns)
373 |   }
374 | 
375 |   get shadowRows() {
376 |     return Math.ceil(this.shadowChildTotalColumns / this.columns)
377 |   }
378 | 
379 |   get templateColumns() {
380 |     if (!this.width) return ''
381 |     if (this.maxWidth === Infinity) {
382 |       return `repeat(${this.columns},minmax(0,1fr))`
383 |     }
384 |     if (this.options.strictAutoFit !== true) {
385 |       const columnWidth =
386 |         (this.width - (this.columns - 1) * this.columnGap) / this.columns
387 |       if (columnWidth < this.minWidth || columnWidth > this.maxWidth) {
388 |         return `repeat(${this.columns},minmax(0,1fr))`
389 |       }
390 |     }
391 |     return `repeat(${this.columns},minmax(${this.minWidth}px,${this.maxWidth}px))`
392 |   }
393 | 
394 |   get gap() {
395 |     return `${this.rowGap}px ${this.columnGap}px`
396 |   }
397 | 
398 |   get childSize() {
399 |     return this.children.length
400 |   }
401 | 
402 |   get fullnessLastColumn() {
403 |     return this.columns === this.children[this.childSize - 1]?.span
404 |   }
405 | 
406 |   connect = (container: Container) => {
407 |     if (container) {
408 |       this.container = container
409 |       const initialize = batch.bound(() => {
410 |         digest()
411 |         this.ready = true
412 |       })
413 |       const digest = batch.bound(() => {
414 |         this.children = parseGridNode(this.container.children)
415 |         this.childTotalColumns = calcChildTotalColumns(this.children)
416 |         this.shadowChildTotalColumns = calcChildTotalColumns(
417 |           this.children,
418 |           true
419 |         )
420 |         this.childOriginTotalColumns = calcChildOriginTotalColumns(
421 |           this.children
422 |         )
423 |         this.shadowChildOriginTotalColumns = calcChildOriginTotalColumns(
424 |           this.children,
425 |           true
426 |         )
427 |         const rect = this.container.getBoundingClientRect()
428 |         if (rect.width && rect.height) {
429 |           this.width = rect.width
430 |           this.height = rect.height
431 |         }
432 |         resolveChildren(this)
433 |         nextTick(() => {
434 |           this.options?.onDigest?.(this)
435 |         })
436 |         if (!this.ready) {
437 |           nextTick(() => {
438 |             this.options?.onInitialized?.(this)
439 |           })
440 |         }
441 |       })
442 |       const mutationObserver = new ChildListMutationObserver(digest)
443 |       // add requestAnimationFrame to smooth digest
444 |       const smoothDigest = () => {
445 |         requestAnimationFrame(() => {
446 |           digest()
447 |         })
448 |       }
449 |       const resizeObserver = new ResizeObserver(smoothDigest)
450 |       const dispose = reaction(() => ({ ...this.options }), digest)
451 |       resizeObserver.observe(this.container)
452 |       mutationObserver.observe(this.container, {
453 |         attributeFilter: ['data-grid-span'],
454 |         attributes: true,
455 |       })
456 |       initialize()
457 |       return () => {
458 |         resizeObserver.unobserve(this.container)
459 |         resizeObserver.disconnect()
460 |         mutationObserver.disconnect()
461 |         dispose()
462 |         this.children = []
463 |       }
464 |     }
465 | 
466 |     return () => {}
467 |   }
468 | 
469 |   static id = (options: IGridOptions = {}) =>
470 |     JSON.stringify(
471 |       [
472 |         'maxRows',
473 |         'maxColumns',
474 |         'minColumns',
475 |         'maxWidth',
476 |         'minWidth',
477 |         'breakpoints',
478 |         'columnGap',
479 |         'rowGap',
480 |         'colWrap',
481 |         'strictAutoFit',
482 |       ].map((key) => options[key])
483 |     )
484 | }
485 | 
```

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

```markdown
  1 | # ArrayCards
  2 | 
  3 | > 卡片列表,对于每行字段数量较多,联动较多的场景比较适合使用 ArrayCards
  4 | >
  5 | > 注意:该组件只适用于 Schema 场景
  6 | 
  7 | ## Markup Schema 案例
  8 | 
  9 | ```tsx
 10 | import React from 'react'
 11 | import {
 12 |   FormItem,
 13 |   Input,
 14 |   ArrayCards,
 15 |   FormButtonGroup,
 16 |   Submit,
 17 | } from '@formily/antd'
 18 | import { createForm } from '@formily/core'
 19 | import { FormProvider, createSchemaField } from '@formily/react'
 20 | 
 21 | const SchemaField = createSchemaField({
 22 |   components: {
 23 |     FormItem,
 24 |     Input,
 25 |     ArrayCards,
 26 |   },
 27 | })
 28 | 
 29 | const form = createForm()
 30 | 
 31 | export default () => {
 32 |   return (
 33 |     <FormProvider form={form}>
 34 |       <SchemaField>
 35 |         <SchemaField.Array
 36 |           name="string_array"
 37 |           maxItems={3}
 38 |           x-decorator="FormItem"
 39 |           x-component="ArrayCards"
 40 |           x-component-props={{
 41 |             title: '字符串数组',
 42 |           }}
 43 |         >
 44 |           <SchemaField.Void>
 45 |             <SchemaField.Void x-component="ArrayCards.Index" />
 46 |             <SchemaField.String
 47 |               name="input"
 48 |               x-decorator="FormItem"
 49 |               title="Input"
 50 |               required
 51 |               x-component="Input"
 52 |             />
 53 |             <SchemaField.Void x-component="ArrayCards.Remove" />
 54 |             <SchemaField.Void x-component="ArrayCards.Copy" />
 55 |             <SchemaField.Void x-component="ArrayCards.MoveUp" />
 56 |             <SchemaField.Void x-component="ArrayCards.MoveDown" />
 57 |           </SchemaField.Void>
 58 |           <SchemaField.Void
 59 |             x-component="ArrayCards.Addition"
 60 |             title="添加条目"
 61 |           />
 62 |         </SchemaField.Array>
 63 |         <SchemaField.Array
 64 |           name="array"
 65 |           maxItems={3}
 66 |           x-decorator="FormItem"
 67 |           x-component="ArrayCards"
 68 |           x-component-props={{
 69 |             title: '对象数组',
 70 |           }}
 71 |         >
 72 |           <SchemaField.Object>
 73 |             <SchemaField.Void x-component="ArrayCards.Index" />
 74 |             <SchemaField.String
 75 |               name="input"
 76 |               x-decorator="FormItem"
 77 |               title="Input"
 78 |               required
 79 |               x-component="Input"
 80 |             />
 81 |             <SchemaField.Void x-component="ArrayCards.Remove" />
 82 |             <SchemaField.Void x-component="ArrayCards.MoveUp" />
 83 |             <SchemaField.Void x-component="ArrayCards.MoveDown" />
 84 |           </SchemaField.Object>
 85 |           <SchemaField.Void
 86 |             x-component="ArrayCards.Addition"
 87 |             title="添加条目"
 88 |           />
 89 |         </SchemaField.Array>
 90 |       </SchemaField>
 91 |       <FormButtonGroup>
 92 |         <Submit onSubmit={console.log}>提交</Submit>
 93 |       </FormButtonGroup>
 94 |     </FormProvider>
 95 |   )
 96 | }
 97 | ```
 98 | 
 99 | ## JSON Schema 案例
100 | 
101 | ```tsx
102 | import React from 'react'
103 | import {
104 |   FormItem,
105 |   Input,
106 |   ArrayCards,
107 |   FormButtonGroup,
108 |   Submit,
109 | } from '@formily/antd'
110 | import { createForm } from '@formily/core'
111 | import { FormProvider, createSchemaField } from '@formily/react'
112 | 
113 | const SchemaField = createSchemaField({
114 |   components: {
115 |     FormItem,
116 |     Input,
117 |     ArrayCards,
118 |   },
119 | })
120 | 
121 | const form = createForm()
122 | 
123 | const schema = {
124 |   type: 'object',
125 |   properties: {
126 |     string_array: {
127 |       type: 'array',
128 |       'x-component': 'ArrayCards',
129 |       maxItems: 3,
130 |       'x-decorator': 'FormItem',
131 |       'x-component-props': {
132 |         title: '字符串数组',
133 |       },
134 |       items: {
135 |         type: 'void',
136 |         properties: {
137 |           index: {
138 |             type: 'void',
139 |             'x-component': 'ArrayCards.Index',
140 |           },
141 |           input: {
142 |             type: 'string',
143 |             'x-decorator': 'FormItem',
144 |             title: 'Input',
145 |             required: true,
146 |             'x-component': 'Input',
147 |           },
148 |           remove: {
149 |             type: 'void',
150 |             'x-component': 'ArrayCards.Remove',
151 |           },
152 |           moveUp: {
153 |             type: 'void',
154 |             'x-component': 'ArrayCards.MoveUp',
155 |           },
156 |           moveDown: {
157 |             type: 'void',
158 |             'x-component': 'ArrayCards.MoveDown',
159 |           },
160 |         },
161 |       },
162 |       properties: {
163 |         addition: {
164 |           type: 'void',
165 |           title: '添加条目',
166 |           'x-component': 'ArrayCards.Addition',
167 |         },
168 |       },
169 |     },
170 |     array: {
171 |       type: 'array',
172 |       'x-component': 'ArrayCards',
173 |       maxItems: 3,
174 |       'x-decorator': 'FormItem',
175 |       'x-component-props': {
176 |         title: '对象数组',
177 |       },
178 |       items: {
179 |         type: 'object',
180 |         properties: {
181 |           index: {
182 |             type: 'void',
183 |             'x-component': 'ArrayCards.Index',
184 |           },
185 |           input: {
186 |             type: 'string',
187 |             'x-decorator': 'FormItem',
188 |             title: 'Input',
189 |             required: true,
190 |             'x-component': 'Input',
191 |           },
192 |           remove: {
193 |             type: 'void',
194 |             'x-component': 'ArrayCards.Remove',
195 |           },
196 |           moveUp: {
197 |             type: 'void',
198 |             'x-component': 'ArrayCards.MoveUp',
199 |           },
200 |           moveDown: {
201 |             type: 'void',
202 |             'x-component': 'ArrayCards.MoveDown',
203 |           },
204 |         },
205 |       },
206 |       properties: {
207 |         addition: {
208 |           type: 'void',
209 |           title: '添加条目',
210 |           'x-component': 'ArrayCards.Addition',
211 |         },
212 |       },
213 |     },
214 |   },
215 | }
216 | 
217 | export default () => {
218 |   return (
219 |     <FormProvider form={form}>
220 |       <SchemaField schema={schema} />
221 |       <FormButtonGroup>
222 |         <Submit onSubmit={console.log}>提交</Submit>
223 |       </FormButtonGroup>
224 |     </FormProvider>
225 |   )
226 | }
227 | ```
228 | 
229 | ## Effects 联动案例
230 | 
231 | ```tsx
232 | import React from 'react'
233 | import {
234 |   FormItem,
235 |   Input,
236 |   ArrayCards,
237 |   FormButtonGroup,
238 |   Submit,
239 | } from '@formily/antd'
240 | import { createForm, onFieldChange, onFieldReact } from '@formily/core'
241 | import { FormProvider, createSchemaField } from '@formily/react'
242 | 
243 | const SchemaField = createSchemaField({
244 |   components: {
245 |     FormItem,
246 |     Input,
247 |     ArrayCards,
248 |   },
249 | })
250 | 
251 | const form = createForm({
252 |   effects: () => {
253 |     //主动联动模式
254 |     onFieldChange('array.*.aa', ['value'], (field, form) => {
255 |       form.setFieldState(field.query('.bb'), (state) => {
256 |         state.visible = field.value != '123'
257 |       })
258 |     })
259 |     //被动联动模式
260 |     onFieldReact('array.*.dd', (field) => {
261 |       field.visible = field.query('.cc').get('value') != '123'
262 |     })
263 |   },
264 | })
265 | 
266 | export default () => {
267 |   return (
268 |     <FormProvider form={form}>
269 |       <SchemaField>
270 |         <SchemaField.Array
271 |           name="array"
272 |           maxItems={3}
273 |           x-component="ArrayCards"
274 |           x-decorator="FormItem"
275 |           x-component-props={{
276 |             title: '对象数组',
277 |           }}
278 |         >
279 |           <SchemaField.Object>
280 |             <SchemaField.Void x-component="ArrayCards.Index" />
281 |             <SchemaField.String
282 |               name="aa"
283 |               x-decorator="FormItem"
284 |               title="AA"
285 |               required
286 |               description="AA输入123时隐藏BB"
287 |               x-component="Input"
288 |             />
289 |             <SchemaField.String
290 |               name="bb"
291 |               x-decorator="FormItem"
292 |               title="BB"
293 |               required
294 |               x-component="Input"
295 |             />
296 |             <SchemaField.String
297 |               name="cc"
298 |               x-decorator="FormItem"
299 |               title="CC"
300 |               required
301 |               description="CC输入123时隐藏DD"
302 |               x-component="Input"
303 |             />
304 |             <SchemaField.String
305 |               name="dd"
306 |               x-decorator="FormItem"
307 |               title="DD"
308 |               required
309 |               x-component="Input"
310 |             />
311 |             <SchemaField.Void x-component="ArrayCards.Remove" />
312 |             <SchemaField.Void x-component="ArrayCards.MoveUp" />
313 |             <SchemaField.Void x-component="ArrayCards.MoveDown" />
314 |           </SchemaField.Object>
315 |           <SchemaField.Void
316 |             x-component="ArrayCards.Addition"
317 |             title="添加条目"
318 |           />
319 |         </SchemaField.Array>
320 |       </SchemaField>
321 |       <FormButtonGroup>
322 |         <Submit onSubmit={console.log}>提交</Submit>
323 |       </FormButtonGroup>
324 |     </FormProvider>
325 |   )
326 | }
327 | ```
328 | 
329 | ## JSON Schema 联动案例
330 | 
331 | ```tsx
332 | import React from 'react'
333 | import {
334 |   FormItem,
335 |   Input,
336 |   ArrayCards,
337 |   FormButtonGroup,
338 |   Submit,
339 | } from '@formily/antd'
340 | import { createForm } from '@formily/core'
341 | import { FormProvider, createSchemaField } from '@formily/react'
342 | 
343 | const SchemaField = createSchemaField({
344 |   components: {
345 |     FormItem,
346 |     Input,
347 |     ArrayCards,
348 |   },
349 | })
350 | 
351 | const form = createForm()
352 | 
353 | const schema = {
354 |   type: 'object',
355 |   properties: {
356 |     array: {
357 |       type: 'array',
358 |       'x-component': 'ArrayCards',
359 |       maxItems: 3,
360 |       title: '对象数组',
361 |       items: {
362 |         type: 'object',
363 |         properties: {
364 |           index: {
365 |             type: 'void',
366 |             'x-component': 'ArrayCards.Index',
367 |           },
368 |           aa: {
369 |             type: 'string',
370 |             'x-decorator': 'FormItem',
371 |             title: 'AA',
372 |             required: true,
373 |             'x-component': 'Input',
374 |             description: '输入123',
375 |           },
376 |           bb: {
377 |             type: 'string',
378 |             title: 'BB',
379 |             required: true,
380 |             'x-decorator': 'FormItem',
381 |             'x-component': 'Input',
382 |             'x-reactions': [
383 |               {
384 |                 dependencies: ['.aa'],
385 |                 when: "{{$deps[0] != '123'}}",
386 |                 fulfill: {
387 |                   schema: {
388 |                     title: 'BB',
389 |                     'x-disabled': true,
390 |                   },
391 |                 },
392 |                 otherwise: {
393 |                   schema: {
394 |                     title: 'Changed',
395 |                     'x-disabled': false,
396 |                   },
397 |                 },
398 |               },
399 |             ],
400 |           },
401 |           remove: {
402 |             type: 'void',
403 |             'x-component': 'ArrayCards.Remove',
404 |           },
405 |           moveUp: {
406 |             type: 'void',
407 |             'x-component': 'ArrayCards.MoveUp',
408 |           },
409 |           moveDown: {
410 |             type: 'void',
411 |             'x-component': 'ArrayCards.MoveDown',
412 |           },
413 |         },
414 |       },
415 |       properties: {
416 |         addition: {
417 |           type: 'void',
418 |           title: '添加条目',
419 |           'x-component': 'ArrayCards.Addition',
420 |         },
421 |       },
422 |     },
423 |   },
424 | }
425 | 
426 | export default () => {
427 |   return (
428 |     <FormProvider form={form}>
429 |       <SchemaField schema={schema} />
430 |       <FormButtonGroup>
431 |         <Submit onSubmit={console.log}>提交</Submit>
432 |       </FormButtonGroup>
433 |     </FormProvider>
434 |   )
435 | }
436 | ```
437 | 
438 | ## API
439 | 
440 | ### ArrayCards
441 | 
442 | 扩展属性
443 | 
444 | | 属性名     | 类型                      | 描述         | 默认值 |
445 | | ---------- | ------------------------- | ------------ | ------ |
446 | | onAdd      | `(index: number) => void` | 增加方法     |        |
447 | | onRemove   | `(index: number) => void` | 删除方法     |        |
448 | | onCopy     | `(index: number) => void` | 复制方法     |        |
449 | | onMoveUp   | `(index: number) => void` | 向上移动方法 |        |
450 | | onMoveDown | `(index: number) => void` | 向下移动方法 |        |
451 | 
452 | 其余参考 https://ant.design/components/card-cn/
453 | 
454 | ### ArrayCards.Addition
455 | 
456 | > 添加按钮
457 | 
458 | 扩展属性
459 | 
460 | | 属性名       | 类型                  | 描述     | 默认值   |
461 | | ------------ | --------------------- | -------- | -------- |
462 | | title        | ReactText             | 文案     |          |
463 | | method       | `'push' \| 'unshift'` | 添加方式 | `'push'` |
464 | | defaultValue | `any`                 | 默认值   |          |
465 | 
466 | 其余参考 https://ant.design/components/button-cn/
467 | 
468 | 注意:title 属性可以接收 Field 模型中的 title 映射,也就是在 Field 上传 title 也是生效的
469 | 
470 | 注意:使用`onClick={e => e.preventDefault()}`可禁用默认行为。
471 | 
472 | ### ArrayCards.Copy
473 | 
474 | > 复制按钮
475 | 
476 | 扩展属性
477 | 
478 | | 属性名 | 类型                  | 描述     | 默认值   |
479 | | ------ | --------------------- | -------- | -------- |
480 | | title  | ReactText             | 文案     |          |
481 | | method | `'push' \| 'unshift'` | 添加方式 | `'push'` |
482 | 
483 | 其余参考 https://ant.design/components/button-cn/
484 | 
485 | 注意:title 属性可以接收 Field 模型中的 title 映射,也就是在 Field 上传 title 也是生效的
486 | 
487 | 注意:使用`onClick={e => e.preventDefault()}`可禁用默认行为。
488 | 
489 | ### ArrayCards.Remove
490 | 
491 | > 删除按钮
492 | 
493 | | 属性名 | 类型      | 描述 | 默认值 |
494 | | ------ | --------- | ---- | ------ |
495 | | title  | ReactText | 文案 |        |
496 | 
497 | 其余参考 https://ant.design/components/icon-cn/
498 | 
499 | 注意:title 属性可以接收 Field 模型中的 title 映射,也就是在 Field 上传 title 也是生效的
500 | 
501 | 注意:使用`onClick={e => e.preventDefault()}`可禁用默认行为。
502 | 
503 | ### ArrayCards.MoveDown
504 | 
505 | > 下移按钮
506 | 
507 | | 属性名 | 类型      | 描述 | 默认值 |
508 | | ------ | --------- | ---- | ------ |
509 | | title  | ReactText | 文案 |        |
510 | 
511 | 其余参考 https://ant.design/components/icon-cn/
512 | 
513 | 注意:title 属性可以接收 Field 模型中的 title 映射,也就是在 Field 上传 title 也是生效的
514 | 
515 | 注意:使用`onClick={e => e.preventDefault()}`可禁用默认行为。
516 | 
517 | ### ArrayCards.MoveUp
518 | 
519 | > 上移按钮
520 | 
521 | | 属性名 | 类型      | 描述 | 默认值 |
522 | | ------ | --------- | ---- | ------ |
523 | | title  | ReactText | 文案 |        |
524 | 
525 | 其余参考 https://ant.design/components/icon-cn/
526 | 
527 | 注意:title 属性可以接收 Field 模型中的 title 映射,也就是在 Field 上传 title 也是生效的
528 | 
529 | 注意:使用`onClick={e => e.preventDefault()}`可禁用默认行为。
530 | 
531 | ### ArrayCards.Index
532 | 
533 | > 索引渲染器
534 | 
535 | 无属性
536 | 
537 | ### ArrayCards.useIndex
538 | 
539 | > 读取当前渲染行索引的 React Hook
540 | 
541 | ### ArrayCards.useRecord
542 | 
543 | > 读取当前渲染记录的 React Hook
544 | 
```

--------------------------------------------------------------------------------
/packages/core/src/__tests__/effects.spec.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import {
  2 |   createForm,
  3 |   createEffectContext,
  4 |   onFieldChange,
  5 |   onFieldInit,
  6 |   onFieldInitialValueChange,
  7 |   onFieldInputValueChange,
  8 |   onFieldMount,
  9 |   onFieldReact,
 10 |   onFieldUnmount,
 11 |   onFieldValidateEnd,
 12 |   onFieldValidateStart,
 13 |   onFieldValidateFailed,
 14 |   onFieldValidateSuccess,
 15 |   onFieldValueChange,
 16 |   onFormInit,
 17 |   onFormInitialValuesChange,
 18 |   onFormInputChange,
 19 |   onFormMount,
 20 |   onFormReact,
 21 |   onFormReset,
 22 |   onFormSubmit,
 23 |   onFormSubmitEnd,
 24 |   onFormSubmitFailed,
 25 |   onFormSubmitStart,
 26 |   onFormSubmitSuccess,
 27 |   onFormSubmitValidateFailed,
 28 |   onFormSubmitValidateStart,
 29 |   onFormSubmitValidateSuccess,
 30 |   onFormSubmitValidateEnd,
 31 |   onFormUnmount,
 32 |   onFormValidateEnd,
 33 |   onFormValidateStart,
 34 |   onFormValidateFailed,
 35 |   onFormValidateSuccess,
 36 |   onFormValuesChange,
 37 |   isVoidField,
 38 | } from '../'
 39 | import { runEffects } from '../shared/effective'
 40 | import { attach, sleep } from './shared'
 41 | 
 42 | test('onFormInit/onFormMount/onFormUnmount', () => {
 43 |   const mount = jest.fn()
 44 |   const init = jest.fn()
 45 |   const unmount = jest.fn()
 46 |   const form = attach(
 47 |     createForm({
 48 |       effects() {
 49 |         onFormInit(init)
 50 |         onFormMount(mount)
 51 |         onFormUnmount(unmount)
 52 |       },
 53 |     })
 54 |   )
 55 |   expect(init).toBeCalled()
 56 |   expect(mount).toBeCalled()
 57 |   expect(unmount).not.toBeCalled()
 58 |   form.onUnmount()
 59 |   expect(unmount).toBeCalled()
 60 | })
 61 | 
 62 | test('onFormValuesChange/onFormInitialValuesChange', () => {
 63 |   const valuesChange = jest.fn()
 64 |   const initialValuesChange = jest.fn()
 65 |   const form = attach(
 66 |     createForm({
 67 |       effects() {
 68 |         onFormValuesChange(valuesChange)
 69 |         onFormInitialValuesChange(initialValuesChange)
 70 |       },
 71 |     })
 72 |   )
 73 |   expect(valuesChange).not.toBeCalled()
 74 |   expect(initialValuesChange).not.toBeCalled()
 75 |   form.setValues({
 76 |     aa: '123',
 77 |   })
 78 |   expect(form.values.aa).toEqual('123')
 79 |   expect(valuesChange).toBeCalled()
 80 |   form.setInitialValues({
 81 |     aa: '321',
 82 |     bb: '123',
 83 |   })
 84 |   expect(form.values.aa).toEqual('321')
 85 |   expect(form.values.bb).toEqual('123')
 86 |   expect(initialValuesChange).toBeCalled()
 87 | })
 88 | 
 89 | test('onFormInputChange', () => {
 90 |   const inputChange = jest.fn()
 91 |   const valuesChange = jest.fn()
 92 |   const form = attach(
 93 |     createForm({
 94 |       effects() {
 95 |         onFormValuesChange(valuesChange)
 96 |         onFormInputChange(inputChange)
 97 |       },
 98 |     })
 99 |   )
100 |   const field = attach(
101 |     form.createField({
102 |       name: 'aa',
103 |     })
104 |   )
105 |   expect(inputChange).not.toBeCalled()
106 |   expect(valuesChange).not.toBeCalled()
107 |   field.setValue('123')
108 |   expect(inputChange).not.toBeCalled()
109 |   expect(valuesChange).toBeCalledTimes(1)
110 |   field.onInput('123')
111 |   expect(inputChange).toBeCalled()
112 |   expect(valuesChange).toBeCalledTimes(1)
113 |   field.onInput('321')
114 |   expect(inputChange).toBeCalledTimes(2)
115 |   expect(valuesChange).toBeCalledTimes(2)
116 | })
117 | 
118 | test('onFormReact', () => {
119 |   const react = jest.fn()
120 |   const form = attach(
121 |     createForm({
122 |       effects() {
123 |         onFormReact((form) => {
124 |           if (form.values.aa) {
125 |             react()
126 |           }
127 |         })
128 |       },
129 |     })
130 |   )
131 |   expect(react).not.toBeCalled()
132 |   form.setValues({ aa: 123 })
133 |   expect(react).toBeCalled()
134 |   form.onUnmount()
135 | 
136 |   // will not throw error
137 |   const form2 = attach(
138 |     createForm({
139 |       effects() {
140 |         onFormReact()
141 |       },
142 |     })
143 |   )
144 | 
145 |   form2.onUnmount()
146 | })
147 | 
148 | test('onFormReset', async () => {
149 |   const reset = jest.fn()
150 |   const form = attach(
151 |     createForm({
152 |       initialValues: {
153 |         aa: 123,
154 |       },
155 |       effects() {
156 |         onFormReset(reset)
157 |       },
158 |     })
159 |   )
160 | 
161 |   const field = attach(
162 |     form.createField({
163 |       name: 'aa',
164 |     })
165 |   )
166 | 
167 |   field.setValue('xxxx')
168 | 
169 |   expect(field.value).toEqual('xxxx')
170 |   expect(form.values.aa).toEqual('xxxx')
171 |   expect(reset).not.toBeCalled()
172 |   await form.reset()
173 |   expect(field.value).toEqual(123)
174 |   expect(form.values.aa).toEqual(123)
175 |   expect(reset).toBeCalled()
176 | })
177 | 
178 | test('onFormSubmit', async () => {
179 |   const submit = jest.fn()
180 |   const submitStart = jest.fn()
181 |   const submitEnd = jest.fn()
182 |   const submitSuccess = jest.fn()
183 |   const submitFailed = jest.fn()
184 |   const submitValidateStart = jest.fn()
185 |   const submitValidateFailed = jest.fn()
186 |   const submitValidateSuccess = jest.fn()
187 |   const submitValidateEnd = jest.fn()
188 |   const form = attach(
189 |     createForm({
190 |       effects() {
191 |         onFormSubmitStart(submitStart)
192 |         onFormSubmit(submit)
193 |         onFormSubmitEnd(submitEnd)
194 |         onFormSubmitFailed(submitFailed)
195 |         onFormSubmitSuccess(submitSuccess)
196 |         onFormSubmitValidateStart(submitValidateStart)
197 |         onFormSubmitValidateFailed(submitValidateFailed)
198 |         onFormSubmitValidateSuccess(submitValidateSuccess)
199 |         onFormSubmitValidateEnd(submitValidateEnd)
200 |       },
201 |     })
202 |   )
203 | 
204 |   const field = attach(
205 |     form.createField({
206 |       name: 'aa',
207 |       required: true,
208 |     })
209 |   )
210 |   try {
211 |     await form.submit()
212 |   } catch {}
213 |   expect(submitStart).toBeCalled()
214 |   expect(submit).toBeCalled()
215 |   expect(submitEnd).toBeCalled()
216 |   expect(submitSuccess).not.toBeCalled()
217 |   expect(submitFailed).toBeCalled()
218 |   expect(submitValidateStart).toBeCalled()
219 |   expect(submitValidateFailed).toBeCalled()
220 |   expect(submitValidateSuccess).not.toBeCalled()
221 |   expect(submitValidateEnd).toBeCalled()
222 |   field.onInput('123')
223 |   try {
224 |     await form.submit()
225 |   } catch (e) {}
226 |   expect(submitStart).toBeCalledTimes(2)
227 |   expect(submit).toBeCalledTimes(2)
228 |   expect(submitEnd).toBeCalledTimes(2)
229 |   expect(submitSuccess).toBeCalledTimes(1)
230 |   expect(submitFailed).toBeCalledTimes(1)
231 |   expect(submitValidateStart).toBeCalledTimes(2)
232 |   expect(submitValidateFailed).toBeCalledTimes(1)
233 |   expect(submitValidateSuccess).toBeCalledTimes(1)
234 |   expect(submitValidateEnd).toBeCalledTimes(2)
235 | })
236 | 
237 | test('onFormValidate', async () => {
238 |   const validateStart = jest.fn()
239 |   const validateEnd = jest.fn()
240 |   const validateFailed = jest.fn()
241 |   const validateSuccess = jest.fn()
242 |   const form = attach(
243 |     createForm({
244 |       effects() {
245 |         onFormValidateStart(validateStart)
246 |         onFormValidateEnd(validateEnd)
247 |         onFormValidateFailed(validateFailed)
248 |         onFormValidateSuccess(validateSuccess)
249 |       },
250 |     })
251 |   )
252 |   const field = attach(
253 |     form.createField({
254 |       name: 'aa',
255 |       required: true,
256 |     })
257 |   )
258 |   try {
259 |     await form.validate()
260 |   } catch {}
261 |   expect(validateStart).toBeCalled()
262 |   expect(validateEnd).toBeCalled()
263 |   expect(validateFailed).toBeCalled()
264 |   expect(validateSuccess).not.toBeCalled()
265 |   field.onInput('123')
266 |   try {
267 |     await form.validate()
268 |   } catch {}
269 |   expect(validateStart).toBeCalledTimes(2)
270 |   expect(validateEnd).toBeCalledTimes(2)
271 |   expect(validateFailed).toBeCalledTimes(1)
272 |   expect(validateSuccess).toBeCalledTimes(1)
273 | })
274 | 
275 | test('onFieldChange', async () => {
276 |   const fieldChange = jest.fn()
277 |   const valueChange = jest.fn()
278 |   const valueChange2 = jest.fn()
279 |   const form = attach(
280 |     createForm({
281 |       effects() {
282 |         onFieldChange(
283 |           'aa',
284 |           [
285 |             'value',
286 |             'disabled',
287 |             'initialized',
288 |             'inputValue',
289 |             'loading',
290 |             'visible',
291 |             'editable',
292 |           ],
293 |           fieldChange
294 |         )
295 |         onFieldChange('aa', valueChange)
296 |         onFieldChange('aa', undefined, valueChange2)
297 |         onFieldChange('aa')
298 |       },
299 |     })
300 |   )
301 |   const field = attach(
302 |     form.createField({
303 |       name: 'aa',
304 |     })
305 |   )
306 |   expect(fieldChange).toBeCalledTimes(1)
307 |   field.setValue('123')
308 |   expect(fieldChange).toBeCalledTimes(2)
309 |   field.onInput('321')
310 |   expect(fieldChange).toBeCalledTimes(3)
311 |   field.setLoading(true)
312 |   expect(fieldChange).toBeCalledTimes(3)
313 |   await sleep()
314 |   expect(fieldChange).toBeCalledTimes(4)
315 |   field.setPattern('disabled')
316 |   expect(fieldChange).toBeCalledTimes(5)
317 |   field.setDisplay('none')
318 |   expect(fieldChange).toBeCalledTimes(6)
319 |   form.onUnmount()
320 |   expect(valueChange).toBeCalledTimes(4)
321 |   expect(valueChange2).toBeCalledTimes(4)
322 | })
323 | 
324 | test('onFieldInit/onFieldMount/onFieldUnmount', () => {
325 |   const fieldInit = jest.fn()
326 |   const fieldMount = jest.fn()
327 |   const fieldUnmount = jest.fn()
328 |   const form = attach(
329 |     createForm({
330 |       effects() {
331 |         onFieldInit('aa', fieldInit)
332 |         onFieldMount('aa', fieldMount)
333 |         onFieldUnmount('aa', fieldUnmount)
334 |       },
335 |     })
336 |   )
337 |   const field = attach(
338 |     form.createField({
339 |       name: 'aa',
340 |     })
341 |   )
342 |   expect(fieldInit).toBeCalledTimes(1)
343 |   expect(fieldMount).toBeCalledTimes(1)
344 |   expect(fieldUnmount).toBeCalledTimes(0)
345 |   field.onUnmount()
346 |   expect(fieldUnmount).toBeCalledTimes(1)
347 | })
348 | 
349 | test('onFieldInitialValueChange/onFieldValueChange/onFieldInputValueChange', () => {
350 |   const fieldValueChange = jest.fn()
351 |   const fieldInitialValueChange = jest.fn()
352 |   const fieldInputValueChange = jest.fn()
353 |   const notTrigger = jest.fn()
354 |   const form = attach(
355 |     createForm({
356 |       effects() {
357 |         onFieldInitialValueChange('aa', fieldInitialValueChange)
358 |         onFieldValueChange('aa', fieldValueChange)
359 |         onFieldInputValueChange('aa', fieldInputValueChange)
360 |         onFieldValueChange('xx', notTrigger)
361 |       },
362 |     })
363 |   )
364 |   const field = attach(
365 |     form.createField({
366 |       name: 'aa',
367 |     })
368 |   )
369 |   field.setValue('123')
370 |   expect(fieldValueChange).toBeCalledTimes(1)
371 |   expect(fieldInitialValueChange).toBeCalledTimes(0)
372 |   expect(fieldInputValueChange).toBeCalledTimes(0)
373 |   field.setInitialValue('xxx')
374 |   expect(fieldValueChange).toBeCalledTimes(2)
375 |   expect(fieldInitialValueChange).toBeCalledTimes(1)
376 |   expect(fieldInputValueChange).toBeCalledTimes(0)
377 |   field.onInput('321')
378 |   expect(fieldValueChange).toBeCalledTimes(3)
379 |   expect(fieldInitialValueChange).toBeCalledTimes(1)
380 |   expect(fieldInputValueChange).toBeCalledTimes(1)
381 |   expect(notTrigger).toBeCalledTimes(0)
382 | })
383 | 
384 | test('onFieldReact', () => {
385 |   const react = jest.fn()
386 |   const form = attach(
387 |     createForm({
388 |       effects() {
389 |         onFieldReact('aa', (field) => {
390 |           if (isVoidField(field)) return
391 |           if (field.value) {
392 |             react()
393 |           }
394 |           if (field.display === 'hidden') {
395 |             react()
396 |           }
397 |         })
398 |         onFieldReact('aa', null)
399 |       },
400 |     })
401 |   )
402 |   const field = attach(
403 |     form.createField({
404 |       name: 'aa',
405 |     })
406 |   )
407 |   expect(react).not.toBeCalled()
408 |   form.setValues({ aa: 123 })
409 |   expect(react).toBeCalledTimes(1)
410 |   field.setDisplay('hidden')
411 |   expect(react).toBeCalledTimes(3)
412 |   form.onUnmount()
413 | })
414 | 
415 | test('onFieldValidate', async () => {
416 |   const validateStart = jest.fn()
417 |   const validateFailed = jest.fn()
418 |   const validateSuccess = jest.fn()
419 |   const validateEnd = jest.fn()
420 |   const form = attach(
421 |     createForm({
422 |       effects() {
423 |         onFieldValidateStart('aa', validateStart)
424 |         onFieldValidateEnd('aa', validateEnd)
425 |         onFieldValidateFailed('aa', validateFailed)
426 |         onFieldValidateSuccess('aa', validateSuccess)
427 |       },
428 |     })
429 |   )
430 |   const field = attach(
431 |     form.createField({
432 |       name: 'aa',
433 |       required: true,
434 |     })
435 |   )
436 |   try {
437 |     await field.validate()
438 |   } catch {}
439 |   expect(validateStart).toBeCalled()
440 |   expect(validateFailed).toBeCalled()
441 |   expect(validateSuccess).not.toBeCalled()
442 |   expect(validateEnd).toBeCalled()
443 |   field.setValue('123')
444 |   try {
445 |     await field.validate()
446 |   } catch {}
447 |   expect(validateStart).toBeCalledTimes(2)
448 |   expect(validateFailed).toBeCalledTimes(1)
449 |   expect(validateSuccess).toBeCalledTimes(1)
450 |   expect(validateEnd).toBeCalledTimes(2)
451 | })
452 | 
453 | test('async use will throw error', async () => {
454 |   const valueChange = jest.fn()
455 |   let error
456 |   const form = attach(
457 |     createForm({
458 |       effects() {
459 |         setTimeout(() => {
460 |           try {
461 |             onFieldValueChange('aa', valueChange)
462 |           } catch (e) {
463 |             error = e
464 |           }
465 |         }, 0)
466 |       },
467 |     })
468 |   )
469 |   const aa = attach(
470 |     form.createField({
471 |       name: 'aa',
472 |     })
473 |   )
474 |   await sleep(10)
475 |   aa.setValue('123')
476 |   expect(valueChange).toBeCalledTimes(0)
477 |   expect(error).not.toBeUndefined()
478 | })
479 | 
480 | test('effect context', async () => {
481 |   const context = createEffectContext<number>()
482 |   const context2 = createEffectContext<number>()
483 |   const context3 = createEffectContext<number>(123)
484 |   let results: any
485 |   let error: any
486 |   let error2: any
487 |   const consumer = () => {
488 |     results = context.consume()
489 |   }
490 |   const consumer2 = () => {
491 |     setTimeout(() => {
492 |       try {
493 |         results = context2.consume()
494 |       } catch (e) {
495 |         error2 = e
496 |       }
497 |     }, 0)
498 |   }
499 |   attach(
500 |     createForm({
501 |       effects() {
502 |         context.provide(123)
503 |         context3.provide()
504 |         consumer()
505 |         setTimeout(() => {
506 |           try {
507 |             context2.provide(123)
508 |           } catch (e) {
509 |             error = e
510 |           }
511 |         }, 0)
512 |         consumer2()
513 |       },
514 |     })
515 |   )
516 |   await sleep(10)
517 |   expect(results).toEqual(123)
518 |   expect(error).not.toBeUndefined()
519 |   expect(error2).not.toBeUndefined()
520 | })
521 | 
522 | test('runEffects', () => {
523 |   expect(
524 |     runEffects(123, () => {
525 |       onFormMount(() => {})
526 |     }).length
527 |   ).toEqual(1)
528 | })
529 | 
```

--------------------------------------------------------------------------------
/packages/path/src/__tests__/accessor.spec.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { Path } from '../'
  2 | 
  3 | const { getIn, setIn } = Path
  4 | 
  5 | test('test getIn null parent', () => {
  6 |   const value = { aa: null }
  7 |   expect(getIn(value, 'aa')).toEqual(null)
  8 |   expect(getIn(value, 'aa.bb.cc')).toEqual(undefined)
  9 | })
 10 | 
 11 | test('test getIn and setIn', () => {
 12 |   const value = { a: { b: { c: 2, d: 333 } } }
 13 |   expect(getIn(value, 'a.b.c')).toEqual(2)
 14 |   setIn(value, 'a.b.c', 1111)
 15 |   expect(getIn(value, 'a.b.c')).toEqual(1111)
 16 | })
 17 | 
 18 | test('test getIn with destructor', () => {
 19 |   const value = { array: [{ aa: 123, bb: 321 }] }
 20 |   expect(getIn(value, 'array.0.[aa,bb]')).toEqual([123, 321])
 21 | })
 22 | 
 23 | test('test setIn auto create array', () => {
 24 |   const value = { array: null }
 25 |   setIn(value, 'array[0].bb[2]', 'hello world')
 26 |   expect(value).toEqual({
 27 |     array: [
 28 |       {
 29 |         bb: [undefined, undefined, 'hello world'],
 30 |       },
 31 |     ],
 32 |   })
 33 |   expect(getIn(undefined, 'aa.bb.cc')).toEqual(undefined)
 34 |   setIn(undefined, 'aa.bb.cc', 123)
 35 | })
 36 | 
 37 | test('map', () => {
 38 |   const value = { map: new Map() }
 39 |   setIn(value, 'map.aa.bb.cc', 123)
 40 |   expect(getIn(value, 'map.aa.bb.cc')).toEqual(123)
 41 | })
 42 | 
 43 | test('test setIn array properties', () => {
 44 |   const value = { array: [] }
 45 |   setIn(value, 'array.xxx', 'hello world')
 46 |   expect(value).toEqual({ array: [] })
 47 | })
 48 | 
 49 | test('test setIn dose not affect other items', () => {
 50 |   const value = {
 51 |     aa: [
 52 |       {
 53 |         dd: [
 54 |           {
 55 |             ee: '是',
 56 |           },
 57 |         ],
 58 |         cc: '1111',
 59 |       },
 60 |     ],
 61 |   }
 62 | 
 63 |   setIn(value, 'aa.1.dd.0.ee', '否')
 64 |   expect(value.aa[0]).toEqual({
 65 |     dd: [
 66 |       {
 67 |         ee: '是',
 68 |       },
 69 |     ],
 70 |     cc: '1111',
 71 |   })
 72 | })
 73 | 
 74 | test('destruct getIn', () => {
 75 |   // getIn 通过解构表达式从扁平数据转为复合嵌套数据
 76 |   const value = { a: { b: { c: 2, d: 333 } } }
 77 |   expect(getIn({ a: { b: { kk: 2, mm: 333 } } }, 'a.b.{c:kk,d:mm}')).toEqual({
 78 |     c: 2,
 79 |     d: 333,
 80 |   })
 81 | 
 82 |   expect(
 83 |     getIn(
 84 |       { kk: 2, mm: 333 },
 85 |       `{
 86 |         a : {
 87 |           b : {
 88 |             c : kk,
 89 |             d : mm
 90 |           }
 91 |         }
 92 |       }`
 93 |     )
 94 |   ).toEqual(value)
 95 |   expect(getIn({ bb: undefined, dd: undefined }, `[{aa:bb,cc:dd}]`)).toEqual([])
 96 |   expect(
 97 |     getIn(
 98 |       { kk: undefined, mm: undefined },
 99 |       `{
100 |         a : {
101 |           b : {
102 |             c : kk,
103 |             d : mm
104 |           }
105 |         }
106 |       }`
107 |     )
108 |   ).toEqual({})
109 | })
110 | 
111 | test('destruct setIn', () => {
112 |   const value = { a: { b: { c: 2, d: 333 } } }
113 |   // setIn 从复杂嵌套结构中解构数据出来对其做赋值处理
114 |   expect(
115 |     setIn(
116 |       {},
117 |       `{
118 |         a : {
119 |           b : {
120 |             c,
121 |             d
122 |           }
123 |         }
124 |       }`,
125 |       value
126 |     )
127 |   ).toEqual({ c: 2, d: 333 })
128 | 
129 |   expect(
130 |     setIn(
131 |       {},
132 |       `
133 |       [aa,bb]
134 |       `,
135 |       [123, 444]
136 |     )
137 |   ).toEqual({ aa: 123, bb: 444 })
138 |   expect(setIn({}, 'aa.bb.ddd.[aa,bb]', [123, 444])).toEqual({
139 |     aa: { bb: { ddd: { aa: 123, bb: 444 } } },
140 |   })
141 | 
142 |   expect(setIn({}, 'aa.bb.ddd.[{cc:aa,bb}]', [{ cc: 123, bb: 444 }])).toEqual({
143 |     aa: { bb: { ddd: { aa: 123, bb: 444 } } },
144 |   })
145 | })
146 | 
147 | test('setIn with a.b.c.{aaa,bbb}', () => {
148 |   expect(Path.setIn({}, 'a.b.c.{aaa,bbb}', { aaa: 123, bbb: 321 })).toEqual({
149 |     a: { b: { c: { aaa: 123, bbb: 321 } } },
150 |   })
151 | })
152 | 
153 | test('getIn with a.b.c.{aaa,bbb}', () => {
154 |   expect(
155 |     Path.getIn({ a: { b: { c: { aaa: 123, bbb: 321 } } } }, 'a.b.c.{aaa,bbb}')
156 |   ).toEqual({ aaa: 123, bbb: 321 })
157 | })
158 | 
159 | test('setIn with a.b.c.{aaa,bbb} source has extra property', () => {
160 |   expect(
161 |     Path.setIn({ a: { b: { c: { kkk: 'ddd' } } } }, 'a.b.c.{aaa,bbb}', {
162 |       aaa: 123,
163 |       bbb: 321,
164 |     })
165 |   ).toEqual({ a: { b: { c: { aaa: 123, bbb: 321, kkk: 'ddd' } } } })
166 | })
167 | 
168 | test('getIn with a.b.c.{aaa,bbb} source has extra property', () => {
169 |   expect(
170 |     Path.getIn(
171 |       { a: { b: { c: { aaa: 123, bbb: 321, kkk: 'ddd' } } } },
172 |       'a.b.c.{aaa,bbb}'
173 |     )
174 |   ).toEqual({ aaa: 123, bbb: 321 })
175 | })
176 | 
177 | test('setIn with a.b.c.{aaa:ooo,bbb}', () => {
178 |   expect(
179 |     Path.setIn({ a: { b: { c: { kkk: 'ddd' } } } }, 'a.b.c.{aaa:ooo,bbb}', {
180 |       aaa: 123,
181 |       bbb: 321,
182 |     })
183 |   ).toEqual({ a: { b: { c: { ooo: 123, bbb: 321, kkk: 'ddd' } } } })
184 | })
185 | 
186 | test('getIn with a.b.c.{aaa:ooo,bbb}', () => {
187 |   expect(
188 |     Path.getIn(
189 |       { a: { b: { c: { ooo: 123, bbb: 321, kkk: 'ddd' } } } },
190 |       'a.b.c.{aaa:ooo,bbb}'
191 |     )
192 |   ).toEqual({ aaa: 123, bbb: 321 })
193 | })
194 | 
195 | test('setIn with a.b.c.[aaa,bbb]', () => {
196 |   expect(Path.setIn({}, 'a.b.c.[aaa,bbb]', [123, 321])).toEqual({
197 |     a: { b: { c: { aaa: 123, bbb: 321 } } },
198 |   })
199 | })
200 | 
201 | test('getIn with a.b.c.[aaa,bbb]', () => {
202 |   expect(
203 |     Path.getIn({ a: { b: { c: { aaa: 123, bbb: 321 } } } }, 'a.b.c.[aaa,bbb]')
204 |   ).toEqual([123, 321])
205 | })
206 | 
207 | test('setIn with a.b.c.[aaa,bbb] source has extra property', () => {
208 |   expect(
209 |     Path.setIn(
210 |       { a: { b: { c: { kkk: 'ddd' } } } },
211 |       'a.b.c.[aaa,bbb]',
212 |       [123, 321]
213 |     )
214 |   ).toEqual({ a: { b: { c: { aaa: 123, bbb: 321, kkk: 'ddd' } } } })
215 | })
216 | 
217 | test('getIn with a.b.c.[aaa,bbb] source has extra property', () => {
218 |   expect(
219 |     Path.getIn(
220 |       { a: { b: { c: { aaa: 123, bbb: 321, kkk: 'ddd' } } } },
221 |       'a.b.c.[aaa,bbb]'
222 |     )
223 |   ).toEqual([123, 321])
224 | })
225 | 
226 | test('setIn with a.b.c.[{ddd,kkk:mmm},bbb]', () => {
227 |   expect(
228 |     Path.setIn({}, 'a.b.c.[{ddd,kkk:mmm},bbb]', [{ ddd: 123, kkk: 'hhh' }, 321])
229 |   ).toEqual({ a: { b: { c: { ddd: 123, bbb: 321, mmm: 'hhh' } } } })
230 | })
231 | 
232 | test('getIn with a.b.c.[{ddd,kkk:mmm},bbb]', () => {
233 |   expect(
234 |     Path.getIn(
235 |       { a: { b: { c: { ddd: 123, bbb: 321, mmm: 'hhh' } } } },
236 |       'a.b.c.[{ddd,kkk:mmm},bbb]'
237 |     )
238 |   ).toEqual([{ ddd: 123, kkk: 'hhh' }, 321])
239 | })
240 | 
241 | test('setIn with a.b.c.{aaa:ooo,bbb:[ccc,ddd]}', () => {
242 |   expect(
243 |     Path.setIn(
244 |       { a: { b: { c: { kkk: 'ddd' } } } },
245 |       'a.b.c.{aaa:ooo,bbb:[ccc,ddd]}',
246 |       { aaa: 123, bbb: [123, 321] }
247 |     )
248 |   ).toEqual({ a: { b: { c: { ooo: 123, ccc: 123, ddd: 321, kkk: 'ddd' } } } })
249 | })
250 | 
251 | test('getIn with a.b.c.{aaa:ooo,bbb:[ccc,ddd]}', () => {
252 |   expect(
253 |     Path.getIn(
254 |       { a: { b: { c: { ooo: 123, ccc: 123, ddd: 321, kkk: 'ddd' } } } },
255 |       'a.b.c.{aaa:ooo,bbb:[ccc,ddd]}'
256 |     )
257 |   ).toEqual({ aaa: 123, bbb: [123, 321] })
258 | })
259 | 
260 | test('existIn with a.b.c', () => {
261 |   expect(Path.existIn({ a: { b: { c: 123123 } } }, 'a.b.c')).toEqual(true)
262 |   expect(Path.existIn({ a: { b: { c: 123123 } } }, 'a.b.c.d')).toEqual(false)
263 |   expect(Path.existIn({ a: 123 }, 'a.b.c.d')).toEqual(false)
264 |   expect(
265 |     Path.existIn(
266 |       { a: { b: { c: { ooo: 123, ccc: 123, ddd: 321, kkk: 'ddd' } } } },
267 |       'a.b.c.{aaa:ooo,bbb:[ccc,ddd]}'
268 |     )
269 |   ).toEqual(true)
270 |   expect(
271 |     Path.existIn(
272 |       { a: { b: { c: { ooo: 123, ccc: 123, kkk: 'ddd' } } } },
273 |       'a.b.c.{aaa:ooo,bbb:[ccc,ddd]}'
274 |     )
275 |   ).toEqual(false)
276 |   expect(Path.existIn({ a: [{}] }, 'a.0')).toEqual(true)
277 | })
278 | 
279 | test('existIn with start Path', () => {
280 |   expect(Path.existIn({ a: [{}] }, 'a.0', Path.parse('a'))).toEqual(false)
281 |   expect(Path.existIn({ a: [{}] }, 'b.a.0', Path.parse('b'))).toEqual(true)
282 | })
283 | 
284 | test('deleteIn', () => {
285 |   expect(
286 |     Path.deleteIn({ a: { b: { c: { ooo: 123, ccc: 234 } } } }, 'a.b.c.ccc')
287 |   ).toEqual({ a: { b: { c: { ooo: 123 } } } })
288 | 
289 |   expect(
290 |     Path.deleteIn({ a: { b: { c: { ooo: 123, ccc: 234 } } } }, null)
291 |   ).toEqual({ a: { b: { c: { ooo: 123, ccc: 234 } } } })
292 | 
293 |   expect(
294 |     Path.deleteIn({ a: { b: { c: { ooo: 123, ccc: 234 } } } }, [])
295 |   ).toEqual({ a: { b: { c: { ooo: 123, ccc: 234 } } } })
296 | 
297 |   expect(Path.deleteIn({ a: { b: { c: 'c' } } }, 'a.b.c.ccc')).toEqual({
298 |     a: { b: { c: 'c' } },
299 |   })
300 | 
301 |   expect(Path.deleteIn({ a: 1, b: 2 }, '{ a }')).toEqual({ b: 2 })
302 |   expect(Path.deleteIn([1, 2], '[0]')).toEqual([undefined, 2])
303 | })
304 | 
305 | test('ensureIn', () => {
306 |   expect(Path.parse('a.b').ensureIn({}, 'default')).toEqual('default')
307 |   expect(Path.parse('a.b').ensureIn({ a: { b: 'value' } }, 'default')).toEqual(
308 |     'value'
309 |   )
310 |   expect(Path.ensureIn({}, 'a.b.c', 'default')).toEqual('default')
311 | })
312 | 
313 | test('complex destructing', () => {
314 |   expect(
315 |     Path.setIn(
316 |       {},
317 |       '{aa:{bb:{cc:destructor1,dd:[destructor2,destructor3],ee}}}',
318 |       {
319 |         aa: {
320 |           bb: {
321 |             cc: 123,
322 |             dd: [333, 444],
323 |             ee: 'abcde',
324 |           },
325 |         },
326 |       }
327 |     )
328 |   ).toEqual({
329 |     destructor1: 123,
330 |     destructor2: 333,
331 |     destructor3: 444,
332 |     ee: 'abcde',
333 |   })
334 |   expect(
335 |     Path.getIn(
336 |       {
337 |         destructor1: 123,
338 |         destructor2: 333,
339 |         destructor3: 444,
340 |         ee: 'abcde',
341 |       },
342 |       '{aa:{bb:{cc:destructor1,dd:[destructor2,destructor3],ee}}}'
343 |     )
344 |   ).toEqual({
345 |     aa: {
346 |       bb: {
347 |         cc: 123,
348 |         dd: [333, 444],
349 |         ee: 'abcde',
350 |       },
351 |     },
352 |   })
353 | })
354 | 
355 | test('test getIn with invalid value', () => {
356 |   const value = {
357 |     array: [null, undefined, { nil: null, undef: undefined }],
358 |     nil: null,
359 |     undef: undefined,
360 |   }
361 |   expect(getIn(value, 'array.0')).toBeNull()
362 |   expect(getIn(value, 'array.1')).toBeUndefined()
363 |   expect(getIn(value, 'array.2.nil')).toBeNull()
364 |   expect(getIn(value, 'array.2.undef')).toBeUndefined()
365 |   expect(getIn(value, 'nil')).toBeNull()
366 |   expect(getIn(value, 'undef')).toBeUndefined()
367 | })
368 | 
369 | test('test setIn with invalid value', () => {
370 |   const value = {
371 |     a: 1,
372 |     b: 2,
373 |     array: [null, undefined, { nil: null, undef: undefined }],
374 |     nil: null,
375 |     undef: undefined,
376 |   }
377 |   setIn(value, 'a', null)
378 |   setIn(value, 'b', undefined)
379 |   // undefined 与 null 互转
380 |   setIn(value, 'array.0', undefined)
381 |   setIn(value, 'array.1', null)
382 |   setIn(value, 'array.2.nil', undefined)
383 |   setIn(value, 'array.2.undef', null)
384 |   setIn(value, 'nil', undefined)
385 |   setIn(value, 'undef', null)
386 | 
387 |   expect(getIn(value, 'a')).toBeNull()
388 |   expect(getIn(value, 'b')).toBeUndefined()
389 |   expect(getIn(value, 'array.0')).toBeUndefined()
390 |   expect(getIn(value, 'array.1')).toBeNull()
391 |   expect(getIn(value, 'array.2.nil')).toBeUndefined()
392 |   expect(getIn(value, 'array.2.undef')).toBeNull()
393 |   expect(getIn(value, 'nil')).toBeUndefined()
394 |   expect(getIn(value, 'undef')).toBeNull()
395 | })
396 | 
397 | test('path arguments', () => {
398 |   const path = new Path('a.b.c')
399 |   expect(new Path(path).segments).toEqual(['a', 'b', 'c'])
400 | 
401 |   const matchPath = Path.match('a.b.c')
402 |   expect(new Path(matchPath).segments).toEqual(['a', 'b', 'c'])
403 | 
404 |   expect(new Path(undefined).segments).toEqual([])
405 | })
406 | 
407 | test('path methods', () => {
408 |   const path = Path.parse('a.b.c')
409 | 
410 |   expect(path.concat(Path.parse('d.e')).segments).toEqual([
411 |     'a',
412 |     'b',
413 |     'c',
414 |     'd',
415 |     'e',
416 |   ])
417 | 
418 |   expect(Path.parse(['a', 'b', 'c']).toString()).toEqual('a.b.c')
419 |   expect(Path.parse(['a', 'b', 'c']).length).toEqual(3)
420 | 
421 |   const matchPath = Path.parse('*')
422 |   const regexPath = Path.parse(/.+/)
423 |   expect(() => matchPath.concat('a')).toThrowError()
424 |   expect(() => regexPath.concat('a')).toThrowError()
425 |   expect(() => matchPath.slice()).toThrowError()
426 |   expect(() => regexPath.slice()).toThrowError()
427 |   expect(() => matchPath.pop()).toThrowError()
428 |   expect(() => regexPath.pop()).toThrowError()
429 |   expect(() => matchPath.splice(0, 1)).toThrowError()
430 |   expect(() => regexPath.splice(0, 1)).toThrowError()
431 |   expect(() => matchPath.forEach(() => {})).toThrowError()
432 |   expect(() => regexPath.forEach(() => {})).toThrowError()
433 |   expect(() => matchPath.map(() => {})).toThrowError()
434 |   expect(() => regexPath.map(() => {})).toThrowError()
435 |   expect(() => matchPath.reduce((p) => p, '')).toThrowError()
436 |   expect(() => regexPath.reduce((p) => p, '')).toThrowError()
437 | 
438 |   expect(path.slice().segments).toEqual(['a', 'b', 'c'])
439 |   expect(path.push('d').segments).toEqual(['a', 'b', 'c', 'd'])
440 |   expect(path.pop().segments).toEqual(['a', 'b'])
441 |   expect(path.splice(0, 1).segments).toEqual(['b', 'c'])
442 | 
443 |   let key = ''
444 |   path.forEach((p) => (key += p + '_'))
445 |   expect(key).toEqual('a_b_c_')
446 |   expect(path.map((p) => p)).toEqual(['a', 'b', 'c'])
447 |   expect(path.reduce((str, p) => str + p, '')).toEqual('abc')
448 |   expect(path.parent().segments).toEqual(['a', 'b'])
449 | 
450 |   expect(() => Path.parse('*').includes('*')).toThrowError()
451 |   expect(() => Path.parse('*').includes('*')).toThrowError()
452 |   expect(() => Path.parse('a.b').includes('*')).toThrowError()
453 |   expect(Path.parse('*').includes('a.b')).toBeTruthy()
454 |   expect(Path.parse('a.b').includes('a.b')).toBeTruthy()
455 |   expect(Path.parse('a.b').includes('a.c')).toBeFalsy()
456 |   expect(Path.parse('a.b').includes('a.b.c')).toBeFalsy()
457 | 
458 |   expect(Path.parse('a.b.c').transform(/[a-z]/, (...result) => result)).toEqual(
459 |     ['a', 'b', 'c']
460 |   )
461 |   expect(Path.parse('a.b.c').transform(/[a-b]/, (...result) => result)).toEqual(
462 |     ['a', 'b']
463 |   )
464 |   expect(Path.parse('a.b.c').transform('', null)).toEqual('')
465 |   expect(() => Path.parse('*').transform('', () => {})).toThrowError()
466 |   expect(Path.transform('a.b.c', /[a-z]/, (...result) => result)).toEqual([
467 |     'a',
468 |     'b',
469 |     'c',
470 |   ])
471 | 
472 |   expect(Path.parse('a.b.c').match('*')).toBeTruthy()
473 |   expect(() => Path.parse('*').match('*')).toThrowError()
474 |   expect(Path.match('*')('a.b.c')).toBeTruthy()
475 |   expect(Path.match('a.b')('a.b.c')).toBeFalsy()
476 | 
477 |   const matcher = Path.match('a.b.c')
478 |   expect(Path.parse(matcher).segments).toEqual(['a', 'b', 'c'])
479 | })
480 | 
```

--------------------------------------------------------------------------------
/packages/json-schema/src/schema.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import {
  2 |   ISchema,
  3 |   SchemaEnum,
  4 |   SchemaProperties,
  5 |   SchemaReaction,
  6 |   SchemaTypes,
  7 |   SchemaKey,
  8 |   ISchemaTransformerOptions,
  9 |   Slot,
 10 | } from './types'
 11 | import { IFieldFactoryProps } from '@formily/core'
 12 | import { map, each, isFn, instOf, FormPath, isStr } from '@formily/shared'
 13 | import { compile, silent, shallowCompile, registerCompiler } from './compiler'
 14 | import { transformFieldProps } from './transformer'
 15 | import {
 16 |   reducePatches,
 17 |   registerPatches,
 18 |   registerPolyfills,
 19 |   enablePolyfills,
 20 | } from './patches'
 21 | import {
 22 |   registerVoidComponents,
 23 |   registerTypeDefaultComponents,
 24 | } from './polyfills'
 25 | import { SchemaNestedMap } from './shared'
 26 | 
 27 | export class Schema<
 28 |   Decorator = any,
 29 |   Component = any,
 30 |   DecoratorProps = any,
 31 |   ComponentProps = any,
 32 |   Pattern = any,
 33 |   Display = any,
 34 |   Validator = any,
 35 |   Message = any,
 36 |   ReactionField = any
 37 | > implements ISchema
 38 | {
 39 |   parent?: Schema
 40 |   root?: Schema
 41 |   name?: SchemaKey
 42 |   title?: Message
 43 |   description?: Message
 44 |   default?: any
 45 |   readOnly?: boolean
 46 |   writeOnly?: boolean
 47 |   type?: SchemaTypes
 48 |   enum?: SchemaEnum<Message>
 49 |   const?: any
 50 |   multipleOf?: number
 51 |   maximum?: number
 52 |   exclusiveMaximum?: number
 53 |   minimum?: number
 54 |   exclusiveMinimum?: number
 55 |   maxLength?: number
 56 |   minLength?: number
 57 |   pattern?: string | RegExp
 58 |   maxItems?: number
 59 |   minItems?: number
 60 |   uniqueItems?: boolean
 61 |   maxProperties?: number
 62 |   minProperties?: number
 63 |   required?: string[] | boolean | string
 64 |   format?: string
 65 |   /** nested json schema spec **/
 66 |   definitions?: Record<
 67 |     string,
 68 |     Schema<
 69 |       Decorator,
 70 |       Component,
 71 |       DecoratorProps,
 72 |       ComponentProps,
 73 |       Pattern,
 74 |       Display,
 75 |       Validator,
 76 |       Message
 77 |     >
 78 |   >
 79 |   properties?: Record<
 80 |     string,
 81 |     Schema<
 82 |       Decorator,
 83 |       Component,
 84 |       DecoratorProps,
 85 |       ComponentProps,
 86 |       Pattern,
 87 |       Display,
 88 |       Validator,
 89 |       Message
 90 |     >
 91 |   >
 92 |   items?:
 93 |     | Schema<
 94 |         Decorator,
 95 |         Component,
 96 |         DecoratorProps,
 97 |         ComponentProps,
 98 |         Pattern,
 99 |         Display,
100 |         Validator,
101 |         Message
102 |       >
103 |     | Schema<
104 |         Decorator,
105 |         Component,
106 |         DecoratorProps,
107 |         ComponentProps,
108 |         Pattern,
109 |         Display,
110 |         Validator,
111 |         Message
112 |       >[]
113 |   additionalItems?: Schema<
114 |     Decorator,
115 |     Component,
116 |     DecoratorProps,
117 |     ComponentProps,
118 |     Pattern,
119 |     Display,
120 |     Validator,
121 |     Message
122 |   >
123 |   patternProperties?: Record<
124 |     string,
125 |     Schema<
126 |       Decorator,
127 |       Component,
128 |       DecoratorProps,
129 |       ComponentProps,
130 |       Pattern,
131 |       Display,
132 |       Validator,
133 |       Message
134 |     >
135 |   >
136 |   additionalProperties?: Schema<
137 |     Decorator,
138 |     Component,
139 |     DecoratorProps,
140 |     ComponentProps,
141 |     Pattern,
142 |     Display,
143 |     Validator,
144 |     Message
145 |   >;
146 | 
147 |   //顺序描述
148 |   ['x-index']?: number;
149 |   //交互模式
150 |   ['x-pattern']?: Pattern;
151 |   //展示状态
152 |   ['x-display']?: Display;
153 |   //校验器
154 |   ['x-validator']?: Validator;
155 |   //装饰器
156 |   ['x-decorator']?: Decorator;
157 |   //装饰器属性
158 |   ['x-decorator-props']?: DecoratorProps;
159 |   //组件
160 |   ['x-component']?: Component;
161 |   //组件属性
162 |   ['x-component-props']?: ComponentProps;
163 | 
164 |   ['x-reactions']?: SchemaReaction<ReactionField>[];
165 | 
166 |   ['x-content']?: any;
167 | 
168 |   ['x-data']?: any;
169 | 
170 |   ['x-visible']?: boolean;
171 | 
172 |   ['x-hidden']?: boolean;
173 | 
174 |   ['x-disabled']?: boolean;
175 | 
176 |   ['x-editable']?: boolean;
177 | 
178 |   ['x-read-only']?: boolean;
179 | 
180 |   ['x-read-pretty']?: boolean;
181 | 
182 |   ['x-compile-omitted']?: string[];
183 | 
184 |   ['x-slot-node']?: Slot;
185 | 
186 |   [key: `x-${string | number}` | symbol]: any
187 | 
188 |   _isJSONSchemaObject = true
189 | 
190 |   version = '2.0'
191 | 
192 |   constructor(
193 |     json: ISchema<
194 |       Decorator,
195 |       Component,
196 |       DecoratorProps,
197 |       ComponentProps,
198 |       Pattern,
199 |       Display,
200 |       Validator,
201 |       Message
202 |     >,
203 |     parent?: Schema
204 |   ) {
205 |     if (parent) {
206 |       this.parent = parent
207 |       this.root = parent.root
208 |     } else {
209 |       this.root = this
210 |     }
211 |     return this.fromJSON(json)
212 |   }
213 | 
214 |   addProperty = (
215 |     key: SchemaKey,
216 |     schema: ISchema<
217 |       Decorator,
218 |       Component,
219 |       DecoratorProps,
220 |       ComponentProps,
221 |       Pattern,
222 |       Display,
223 |       Validator,
224 |       Message
225 |     >
226 |   ) => {
227 |     this.properties = this.properties || {}
228 |     this.properties[key] = new Schema(schema, this)
229 |     this.properties[key].name = key
230 |     return this.properties[key]
231 |   }
232 | 
233 |   removeProperty = (key: SchemaKey) => {
234 |     const schema = this.properties[key]
235 |     delete this.properties[key]
236 |     return schema
237 |   }
238 | 
239 |   setProperties = (
240 |     properties: SchemaProperties<
241 |       Decorator,
242 |       Component,
243 |       DecoratorProps,
244 |       ComponentProps,
245 |       Pattern,
246 |       Display,
247 |       Validator,
248 |       Message
249 |     >
250 |   ) => {
251 |     for (const key in properties) {
252 |       this.addProperty(key, properties[key])
253 |     }
254 |     return this
255 |   }
256 | 
257 |   addPatternProperty = (
258 |     key: SchemaKey,
259 |     schema: ISchema<
260 |       Decorator,
261 |       Component,
262 |       DecoratorProps,
263 |       ComponentProps,
264 |       Pattern,
265 |       Display,
266 |       Validator,
267 |       Message
268 |     >
269 |   ) => {
270 |     if (!schema) return
271 |     this.patternProperties = this.patternProperties || {}
272 |     this.patternProperties[key] = new Schema(schema, this)
273 |     this.patternProperties[key].name = key
274 |     return this.patternProperties[key]
275 |   }
276 | 
277 |   removePatternProperty = (key: SchemaKey) => {
278 |     const schema = this.patternProperties[key]
279 |     delete this.patternProperties[key]
280 |     return schema
281 |   }
282 | 
283 |   setPatternProperties = (
284 |     properties: SchemaProperties<
285 |       Decorator,
286 |       Component,
287 |       DecoratorProps,
288 |       ComponentProps,
289 |       Pattern,
290 |       Display,
291 |       Validator,
292 |       Message
293 |     >
294 |   ) => {
295 |     if (!properties) return this
296 |     for (const key in properties) {
297 |       this.addPatternProperty(key, properties[key])
298 |     }
299 |     return this
300 |   }
301 | 
302 |   setAdditionalProperties = (
303 |     properties: ISchema<
304 |       Decorator,
305 |       Component,
306 |       DecoratorProps,
307 |       ComponentProps,
308 |       Pattern,
309 |       Display,
310 |       Validator,
311 |       Message
312 |     >
313 |   ) => {
314 |     if (!properties) return
315 |     this.additionalProperties = new Schema(properties)
316 |     return this.additionalProperties
317 |   }
318 | 
319 |   setItems = (
320 |     schema:
321 |       | ISchema<
322 |           Decorator,
323 |           Component,
324 |           DecoratorProps,
325 |           ComponentProps,
326 |           Pattern,
327 |           Display,
328 |           Validator,
329 |           Message
330 |         >
331 |       | ISchema<
332 |           Decorator,
333 |           Component,
334 |           DecoratorProps,
335 |           ComponentProps,
336 |           Pattern,
337 |           Display,
338 |           Validator,
339 |           Message
340 |         >[]
341 |   ) => {
342 |     if (!schema) return
343 |     if (Array.isArray(schema)) {
344 |       this.items = schema.map((item) => new Schema(item, this))
345 |     } else {
346 |       this.items = new Schema(schema, this)
347 |     }
348 |     return this.items
349 |   }
350 | 
351 |   setAdditionalItems = (
352 |     items: ISchema<
353 |       Decorator,
354 |       Component,
355 |       DecoratorProps,
356 |       ComponentProps,
357 |       Pattern,
358 |       Display,
359 |       Validator,
360 |       Message
361 |     >
362 |   ) => {
363 |     if (!items) return
364 |     this.additionalItems = new Schema(items, this)
365 |     return this.additionalItems
366 |   }
367 | 
368 |   findDefinitions = (ref: string) => {
369 |     if (!ref || !this.root || !isStr(ref)) return
370 |     if (ref.indexOf('#/') !== 0) return
371 |     return FormPath.getIn(this.root, ref.substring(2).split('/'))
372 |   }
373 | 
374 |   mapProperties = <T>(
375 |     callback?: (
376 |       schema: Schema<
377 |         Decorator,
378 |         Component,
379 |         DecoratorProps,
380 |         ComponentProps,
381 |         Pattern,
382 |         Display,
383 |         Validator,
384 |         Message
385 |       >,
386 |       key: SchemaKey,
387 |       index: number
388 |     ) => T
389 |   ): T[] => {
390 |     return Schema.getOrderProperties(this).map(({ schema, key }, index) => {
391 |       return callback(schema, key, index)
392 |     })
393 |   }
394 | 
395 |   mapPatternProperties = <T>(
396 |     callback?: (
397 |       schema: Schema<
398 |         Decorator,
399 |         Component,
400 |         DecoratorProps,
401 |         ComponentProps,
402 |         Pattern,
403 |         Display,
404 |         Validator,
405 |         Message
406 |       >,
407 |       key: SchemaKey,
408 |       index: number
409 |     ) => T
410 |   ): T[] => {
411 |     return Schema.getOrderProperties(this, 'patternProperties').map(
412 |       ({ schema, key }, index) => {
413 |         return callback(schema, key, index)
414 |       }
415 |     )
416 |   }
417 | 
418 |   reduceProperties = <P, R>(
419 |     callback?: (
420 |       buffer: P,
421 |       schema: Schema<
422 |         Decorator,
423 |         Component,
424 |         DecoratorProps,
425 |         ComponentProps,
426 |         Pattern,
427 |         Display,
428 |         Validator,
429 |         Message
430 |       >,
431 |       key: SchemaKey,
432 |       index: number
433 |     ) => R,
434 |     predicate?: P
435 |   ): R => {
436 |     let results: any = predicate
437 |     Schema.getOrderProperties(this, 'properties').forEach(
438 |       ({ schema, key }, index) => {
439 |         results = callback(results, schema, key, index)
440 |       }
441 |     )
442 |     return results
443 |   }
444 | 
445 |   reducePatternProperties = <P, R>(
446 |     callback?: (
447 |       buffer: P,
448 |       schema: Schema<
449 |         Decorator,
450 |         Component,
451 |         DecoratorProps,
452 |         ComponentProps,
453 |         Pattern,
454 |         Display,
455 |         Validator,
456 |         Message
457 |       >,
458 |       key: SchemaKey,
459 |       index: number
460 |     ) => R,
461 |     predicate?: P
462 |   ): R => {
463 |     let results: any = predicate
464 |     Schema.getOrderProperties(this, 'patternProperties').forEach(
465 |       ({ schema, key }, index) => {
466 |         results = callback(results, schema, key, index)
467 |       }
468 |     )
469 |     return results
470 |   }
471 | 
472 |   compile = (scope?: any) => {
473 |     const schema = new Schema({}, this.parent)
474 |     each(this, (value, key) => {
475 |       if (isFn(value) && !key.includes('x-')) return
476 |       if (key === 'parent' || key === 'root') return
477 |       if (!SchemaNestedMap[key]) {
478 |         schema[key] = value ? compile(value, scope) : value
479 |       } else {
480 |         schema[key] = value ? shallowCompile(value, scope) : value
481 |       }
482 |     })
483 |     return schema
484 |   }
485 | 
486 |   fromJSON = (
487 |     json: ISchema<
488 |       Decorator,
489 |       Component,
490 |       DecoratorProps,
491 |       ComponentProps,
492 |       Pattern,
493 |       Display,
494 |       Validator,
495 |       Message
496 |     >
497 |   ) => {
498 |     if (!json) return this
499 |     if (Schema.isSchemaInstance(json)) return json
500 |     each(reducePatches(json), (value, key) => {
501 |       if (isFn(value) && !key.includes('x-')) return
502 |       if (key === 'properties') {
503 |         this.setProperties(value)
504 |       } else if (key === 'patternProperties') {
505 |         this.setPatternProperties(value)
506 |       } else if (key === 'additionalProperties') {
507 |         this.setAdditionalProperties(value)
508 |       } else if (key === 'items') {
509 |         this.setItems(value)
510 |       } else if (key === 'additionalItems') {
511 |         this.setAdditionalItems(value)
512 |       } else if (key === '$ref') {
513 |         this.fromJSON(this.findDefinitions(value))
514 |       } else {
515 |         this[key] = value
516 |       }
517 |     })
518 |     return this
519 |   }
520 | 
521 |   toJSON = (
522 |     recursion = true
523 |   ): ISchema<
524 |     Decorator,
525 |     Component,
526 |     DecoratorProps,
527 |     ComponentProps,
528 |     Pattern,
529 |     Display,
530 |     Validator,
531 |     Message
532 |   > => {
533 |     const results = {}
534 |     each(this, (value: any, key) => {
535 |       if (
536 |         (isFn(value) && !key.includes('x-')) ||
537 |         key === 'parent' ||
538 |         key === 'root'
539 |       )
540 |         return
541 |       if (key === 'properties' || key === 'patternProperties') {
542 |         if (!recursion) return
543 |         results[key] = map(value, (item) => item?.toJSON?.())
544 |       } else if (key === 'additionalProperties' || key === 'additionalItems') {
545 |         if (!recursion) return
546 |         results[key] = value?.toJSON?.()
547 |       } else if (key === 'items') {
548 |         if (!recursion) return
549 |         if (Array.isArray(value)) {
550 |           results[key] = value.map((item) => item?.toJSON?.())
551 |         } else {
552 |           results[key] = value?.toJSON?.()
553 |         }
554 |       } else {
555 |         results[key] = value
556 |       }
557 |     })
558 |     return results
559 |   }
560 | 
561 |   toFieldProps = (
562 |     options?: ISchemaTransformerOptions
563 |   ): IFieldFactoryProps<any, any> => {
564 |     return transformFieldProps(this, options)
565 |   }
566 | 
567 |   static getOrderProperties = (
568 |     schema: ISchema = {},
569 |     propertiesName: keyof ISchema = 'properties'
570 |   ) => {
571 |     const orderProperties = []
572 |     const unorderProperties = []
573 |     for (const key in schema[propertiesName]) {
574 |       const item = schema[propertiesName][key]
575 |       const index = item['x-index']
576 |       if (!isNaN(index)) {
577 |         orderProperties[index] = { schema: item, key }
578 |       } else {
579 |         unorderProperties.push({ schema: item, key })
580 |       }
581 |     }
582 |     return orderProperties.concat(unorderProperties).filter((item) => !!item)
583 |   }
584 | 
585 |   static compile = (expression: any, scope?: any) => {
586 |     return compile(expression, scope)
587 |   }
588 | 
589 |   static shallowCompile = (expression: any, scope?: any) => {
590 |     return shallowCompile(expression, scope)
591 |   }
592 | 
593 |   static isSchemaInstance = (value: any): value is Schema => {
594 |     return instOf(value, Schema)
595 |   }
596 | 
597 |   static registerCompiler = registerCompiler
598 | 
599 |   static registerPatches = registerPatches
600 | 
601 |   static registerVoidComponents = registerVoidComponents
602 | 
603 |   static registerTypeDefaultComponents = registerTypeDefaultComponents
604 | 
605 |   static registerPolyfills = registerPolyfills
606 | 
607 |   static enablePolyfills = enablePolyfills
608 | 
609 |   static silent = silent
610 | }
611 | 
```

--------------------------------------------------------------------------------
/packages/core/src/models/Field.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import {
  2 |   isValid,
  3 |   isEmpty,
  4 |   toArr,
  5 |   FormPathPattern,
  6 |   isArr,
  7 | } from '@formily/shared'
  8 | import {
  9 |   ValidatorTriggerType,
 10 |   parseValidatorDescriptions,
 11 | } from '@formily/validator'
 12 | import { define, observable, batch, toJS, action } from '@formily/reactive'
 13 | import {
 14 |   JSXComponent,
 15 |   LifeCycleTypes,
 16 |   IFieldFeedback,
 17 |   FeedbackMessage,
 18 |   IFieldCaches,
 19 |   IFieldRequests,
 20 |   FieldValidator,
 21 |   FieldDataSource,
 22 |   ISearchFeedback,
 23 |   IFieldProps,
 24 |   IFieldResetOptions,
 25 |   IFieldState,
 26 |   IModelSetter,
 27 |   IModelGetter,
 28 | } from '../types'
 29 | import {
 30 |   updateFeedback,
 31 |   queryFeedbacks,
 32 |   allowAssignDefaultValue,
 33 |   queryFeedbackMessages,
 34 |   getValuesFromEvent,
 35 |   createReactions,
 36 |   createStateSetter,
 37 |   createStateGetter,
 38 |   isHTMLInputEvent,
 39 |   setValidatorRule,
 40 |   batchValidate,
 41 |   batchSubmit,
 42 |   batchReset,
 43 |   setValidating,
 44 |   setSubmitting,
 45 |   setLoading,
 46 |   validateSelf,
 47 |   modifySelf,
 48 |   getValidFieldDefaultValue,
 49 |   initializeStart,
 50 |   initializeEnd,
 51 |   createChildrenFeedbackFilter,
 52 |   createReaction,
 53 | } from '../shared/internals'
 54 | import { Form } from './Form'
 55 | import { BaseField } from './BaseField'
 56 | import { IFormFeedback } from '../types'
 57 | export class Field<
 58 |   Decorator extends JSXComponent = any,
 59 |   Component extends JSXComponent = any,
 60 |   TextType = any,
 61 |   ValueType = any
 62 | > extends BaseField<Decorator, Component, TextType> {
 63 |   displayName = 'Field'
 64 | 
 65 |   props: IFieldProps<Decorator, Component, TextType, ValueType>
 66 | 
 67 |   loading: boolean
 68 |   validating: boolean
 69 |   submitting: boolean
 70 |   active: boolean
 71 |   visited: boolean
 72 |   selfModified: boolean
 73 |   modified: boolean
 74 |   inputValue: ValueType
 75 |   inputValues: any[]
 76 |   dataSource: FieldDataSource
 77 |   validator: FieldValidator
 78 |   feedbacks: IFieldFeedback[]
 79 |   caches: IFieldCaches = {}
 80 |   requests: IFieldRequests = {}
 81 |   constructor(
 82 |     address: FormPathPattern,
 83 |     props: IFieldProps<Decorator, Component, TextType, ValueType>,
 84 |     form: Form,
 85 |     designable: boolean
 86 |   ) {
 87 |     super()
 88 |     this.form = form
 89 |     this.props = props
 90 |     this.designable = designable
 91 |     initializeStart()
 92 |     this.locate(address)
 93 |     this.initialize()
 94 |     this.makeObservable()
 95 |     this.makeReactive()
 96 |     this.onInit()
 97 |     initializeEnd()
 98 |   }
 99 | 
100 |   protected initialize() {
101 |     this.initialized = false
102 |     this.loading = false
103 |     this.validating = false
104 |     this.submitting = false
105 |     this.selfModified = false
106 |     this.active = false
107 |     this.visited = false
108 |     this.mounted = false
109 |     this.unmounted = false
110 |     this.inputValues = []
111 |     this.inputValue = null
112 |     this.feedbacks = []
113 |     this.title = this.props.title
114 |     this.description = this.props.description
115 |     this.display = this.props.display
116 |     this.pattern = this.props.pattern
117 |     this.editable = this.props.editable
118 |     this.disabled = this.props.disabled
119 |     this.readOnly = this.props.readOnly
120 |     this.readPretty = this.props.readPretty
121 |     this.visible = this.props.visible
122 |     this.hidden = this.props.hidden
123 |     this.dataSource = this.props.dataSource
124 |     this.validator = this.props.validator
125 |     this.required = this.props.required
126 |     this.content = this.props.content
127 |     this.initialValue = this.props.initialValue
128 |     this.value = this.props.value
129 |     this.data = this.props.data
130 |     this.decorator = toArr(this.props.decorator)
131 |     this.component = toArr(this.props.component)
132 |   }
133 | 
134 |   protected makeObservable() {
135 |     if (this.designable) return
136 |     define(this, {
137 |       path: observable.ref,
138 |       title: observable.ref,
139 |       description: observable.ref,
140 |       dataSource: observable.ref,
141 |       selfDisplay: observable.ref,
142 |       selfPattern: observable.ref,
143 |       loading: observable.ref,
144 |       validating: observable.ref,
145 |       submitting: observable.ref,
146 |       selfModified: observable.ref,
147 |       modified: observable.ref,
148 |       active: observable.ref,
149 |       visited: observable.ref,
150 |       initialized: observable.ref,
151 |       mounted: observable.ref,
152 |       unmounted: observable.ref,
153 |       inputValue: observable.ref,
154 |       inputValues: observable.ref,
155 |       decoratorType: observable.ref,
156 |       componentType: observable.ref,
157 |       content: observable.ref,
158 |       feedbacks: observable.ref,
159 |       decoratorProps: observable,
160 |       componentProps: observable,
161 |       validator: observable.shallow,
162 |       data: observable.shallow,
163 |       component: observable.computed,
164 |       decorator: observable.computed,
165 |       errors: observable.computed,
166 |       warnings: observable.computed,
167 |       successes: observable.computed,
168 |       valid: observable.computed,
169 |       invalid: observable.computed,
170 |       selfErrors: observable.computed,
171 |       selfWarnings: observable.computed,
172 |       selfSuccesses: observable.computed,
173 |       selfValid: observable.computed,
174 |       selfInvalid: observable.computed,
175 |       validateStatus: observable.computed,
176 |       value: observable.computed,
177 |       initialValue: observable.computed,
178 |       display: observable.computed,
179 |       pattern: observable.computed,
180 |       required: observable.computed,
181 |       hidden: observable.computed,
182 |       visible: observable.computed,
183 |       disabled: observable.computed,
184 |       readOnly: observable.computed,
185 |       readPretty: observable.computed,
186 |       editable: observable.computed,
187 |       indexes: observable.computed,
188 |       setDisplay: action,
189 |       setTitle: action,
190 |       setDescription: action,
191 |       setDataSource: action,
192 |       setValue: action,
193 |       setPattern: action,
194 |       setInitialValue: action,
195 |       setLoading: action,
196 |       setValidating: action,
197 |       setFeedback: action,
198 |       setSelfErrors: action,
199 |       setSelfWarnings: action,
200 |       setSelfSuccesses: action,
201 |       setValidator: action,
202 |       setRequired: action,
203 |       setComponent: action,
204 |       setComponentProps: action,
205 |       setDecorator: action,
206 |       setDecoratorProps: action,
207 |       setData: action,
208 |       setContent: action,
209 |       validate: action,
210 |       reset: action,
211 |       onInit: batch,
212 |       onInput: batch,
213 |       onMount: batch,
214 |       onUnmount: batch,
215 |       onFocus: batch,
216 |       onBlur: batch,
217 |     })
218 |   }
219 | 
220 |   protected makeReactive() {
221 |     if (this.designable) return
222 |     this.disposers.push(
223 |       createReaction(
224 |         () => this.value,
225 |         (value) => {
226 |           this.notify(LifeCycleTypes.ON_FIELD_VALUE_CHANGE)
227 |           if (isValid(value)) {
228 |             if (this.selfModified && !this.caches.inputting) {
229 |               validateSelf(this)
230 |             }
231 |             if (!isEmpty(value) && this.display === 'none') {
232 |               this.caches.value = toJS(value)
233 |               this.form.deleteValuesIn(this.path)
234 |             }
235 |           }
236 |         }
237 |       ),
238 |       createReaction(
239 |         () => this.initialValue,
240 |         () => {
241 |           this.notify(LifeCycleTypes.ON_FIELD_INITIAL_VALUE_CHANGE)
242 |         }
243 |       ),
244 |       createReaction(
245 |         () => this.display,
246 |         (display) => {
247 |           const value = this.value
248 |           if (display !== 'none') {
249 |             if (value === undefined && this.caches.value !== undefined) {
250 |               this.setValue(this.caches.value)
251 |               this.caches.value = undefined
252 |             }
253 |           } else {
254 |             this.caches.value = toJS(value) ?? toJS(this.initialValue)
255 |             this.form.deleteValuesIn(this.path)
256 |           }
257 |           if (display === 'none' || display === 'hidden') {
258 |             this.setFeedback({
259 |               type: 'error',
260 |               messages: [],
261 |             })
262 |           }
263 |         }
264 |       ),
265 |       createReaction(
266 |         () => this.pattern,
267 |         (pattern) => {
268 |           if (pattern !== 'editable') {
269 |             this.setFeedback({
270 |               type: 'error',
271 |               messages: [],
272 |             })
273 |           }
274 |         }
275 |       )
276 |     )
277 |     createReactions(this)
278 |   }
279 | 
280 |   get selfErrors(): FeedbackMessage {
281 |     return queryFeedbackMessages(this, {
282 |       type: 'error',
283 |     })
284 |   }
285 | 
286 |   get errors(): IFormFeedback[] {
287 |     return this.form.errors.filter(createChildrenFeedbackFilter(this))
288 |   }
289 | 
290 |   get selfWarnings(): FeedbackMessage {
291 |     return queryFeedbackMessages(this, {
292 |       type: 'warning',
293 |     })
294 |   }
295 | 
296 |   get warnings(): IFormFeedback[] {
297 |     return this.form.warnings.filter(createChildrenFeedbackFilter(this))
298 |   }
299 | 
300 |   get selfSuccesses(): FeedbackMessage {
301 |     return queryFeedbackMessages(this, {
302 |       type: 'success',
303 |     })
304 |   }
305 | 
306 |   get successes(): IFormFeedback[] {
307 |     return this.form.successes.filter(createChildrenFeedbackFilter(this))
308 |   }
309 | 
310 |   get selfValid() {
311 |     return !this.selfErrors.length
312 |   }
313 | 
314 |   get valid() {
315 |     return !this.errors.length
316 |   }
317 | 
318 |   get selfInvalid() {
319 |     return !this.selfValid
320 |   }
321 | 
322 |   get invalid() {
323 |     return !this.valid
324 |   }
325 | 
326 |   get value(): ValueType {
327 |     return this.form.getValuesIn(this.path)
328 |   }
329 | 
330 |   get initialValue(): ValueType {
331 |     return this.form.getInitialValuesIn(this.path)
332 |   }
333 | 
334 |   get required() {
335 |     const validators = isArr(this.validator)
336 |       ? this.validator
337 |       : parseValidatorDescriptions(this.validator)
338 |     return validators.some((desc) => !!desc?.['required'])
339 |   }
340 | 
341 |   get validateStatus() {
342 |     if (this.validating) return 'validating'
343 |     if (this.selfInvalid) return 'error'
344 |     if (this.selfWarnings.length) return 'warning'
345 |     if (this.selfSuccesses.length) return 'success'
346 |   }
347 | 
348 |   set required(required: boolean) {
349 |     if (this.required === required) return
350 |     this.setValidatorRule('required', required)
351 |   }
352 | 
353 |   set value(value: ValueType) {
354 |     this.setValue(value)
355 |   }
356 | 
357 |   set initialValue(initialValue: ValueType) {
358 |     this.setInitialValue(initialValue)
359 |   }
360 | 
361 |   set selfErrors(messages: FeedbackMessage) {
362 |     this.setFeedback({
363 |       type: 'error',
364 |       code: 'EffectError',
365 |       messages,
366 |     })
367 |   }
368 | 
369 |   set selfWarnings(messages: FeedbackMessage) {
370 |     this.setFeedback({
371 |       type: 'warning',
372 |       code: 'EffectWarning',
373 |       messages,
374 |     })
375 |   }
376 | 
377 |   set selfSuccesses(messages: FeedbackMessage) {
378 |     this.setFeedback({
379 |       type: 'success',
380 |       code: 'EffectSuccess',
381 |       messages,
382 |     })
383 |   }
384 | 
385 |   setDataSource = (dataSource?: FieldDataSource) => {
386 |     this.dataSource = dataSource
387 |   }
388 | 
389 |   setFeedback = (feedback?: IFieldFeedback) => {
390 |     updateFeedback(this, feedback)
391 |   }
392 | 
393 |   setSelfErrors = (messages?: FeedbackMessage) => {
394 |     this.selfErrors = messages
395 |   }
396 | 
397 |   setSelfWarnings = (messages?: FeedbackMessage) => {
398 |     this.selfWarnings = messages
399 |   }
400 | 
401 |   setSelfSuccesses = (messages?: FeedbackMessage) => {
402 |     this.selfSuccesses = messages
403 |   }
404 | 
405 |   setValidator = (validator?: FieldValidator) => {
406 |     this.validator = validator
407 |   }
408 | 
409 |   setValidatorRule = (name: string, value: any) => {
410 |     setValidatorRule(this, name, value)
411 |   }
412 | 
413 |   setRequired = (required?: boolean) => {
414 |     this.required = required
415 |   }
416 | 
417 |   setValue = (value?: ValueType) => {
418 |     if (this.destroyed) return
419 |     if (!this.initialized) {
420 |       if (this.display === 'none') {
421 |         this.caches.value = value
422 |         return
423 |       }
424 |       value = getValidFieldDefaultValue(value, this.initialValue)
425 |       if (!allowAssignDefaultValue(this.value, value) && !this.designable) {
426 |         return
427 |       }
428 |     }
429 |     this.form.setValuesIn(this.path, value)
430 |   }
431 | 
432 |   setInitialValue = (initialValue?: ValueType) => {
433 |     if (this.destroyed) return
434 |     if (!this.initialized) {
435 |       if (
436 |         !allowAssignDefaultValue(this.initialValue, initialValue) &&
437 |         !this.designable
438 |       ) {
439 |         return
440 |       }
441 |     }
442 |     this.form.setInitialValuesIn(this.path, initialValue)
443 |   }
444 | 
445 |   setLoading = (loading?: boolean) => {
446 |     setLoading(this, loading)
447 |   }
448 | 
449 |   setValidating = (validating?: boolean) => {
450 |     setValidating(this, validating)
451 |   }
452 | 
453 |   setSubmitting = (submitting?: boolean) => {
454 |     setSubmitting(this, submitting)
455 |   }
456 | 
457 |   setState: IModelSetter<IFieldState> = createStateSetter(this)
458 | 
459 |   getState: IModelGetter<IFieldState> = createStateGetter(this)
460 | 
461 |   onInput = async (...args: any[]) => {
462 |     const isHTMLInputEventFromSelf = (args: any[]) =>
463 |       isHTMLInputEvent(args[0]) && 'currentTarget' in args[0]
464 |         ? args[0]?.target === args[0]?.currentTarget
465 |         : true
466 |     const getValues = (args: any[]) => {
467 |       if (args[0]?.target) {
468 |         if (!isHTMLInputEvent(args[0])) return args
469 |       }
470 |       return getValuesFromEvent(args)
471 |     }
472 | 
473 |     if (!isHTMLInputEventFromSelf(args)) return
474 | 
475 |     const values = getValues(args)
476 |     const value = values[0]
477 |     this.caches.inputting = true
478 |     this.inputValue = value
479 |     this.inputValues = values
480 |     this.value = value
481 |     this.modify()
482 |     this.notify(LifeCycleTypes.ON_FIELD_INPUT_VALUE_CHANGE)
483 |     this.notify(LifeCycleTypes.ON_FORM_INPUT_CHANGE, this.form)
484 |     await validateSelf(this, 'onInput')
485 |     this.caches.inputting = false
486 |   }
487 | 
488 |   onFocus = async (...args: any[]) => {
489 |     if (args[0]?.target) {
490 |       if (!isHTMLInputEvent(args[0], false)) return
491 |     }
492 |     this.active = true
493 |     this.visited = true
494 |     await validateSelf(this, 'onFocus')
495 |   }
496 | 
497 |   onBlur = async (...args: any[]) => {
498 |     if (args[0]?.target) {
499 |       if (!isHTMLInputEvent(args[0], false)) return
500 |     }
501 |     this.active = false
502 |     await validateSelf(this, 'onBlur')
503 |   }
504 | 
505 |   validate = (triggerType?: ValidatorTriggerType) => {
506 |     return batchValidate(this, `${this.address}.**`, triggerType)
507 |   }
508 | 
509 |   submit = <T>(onSubmit?: (values: any) => Promise<T> | void): Promise<T> => {
510 |     return batchSubmit(this, onSubmit)
511 |   }
512 | 
513 |   reset = (options?: IFieldResetOptions) => {
514 |     return batchReset(this, `${this.address}.**`, options)
515 |   }
516 | 
517 |   queryFeedbacks = (search?: ISearchFeedback): IFieldFeedback[] => {
518 |     return queryFeedbacks(this, search)
519 |   }
520 | 
521 |   modify = () => modifySelf(this)
522 | }
523 | 
```
Page 29/52FirstPrevNextLast