#
tokens: 43499/50000 3/1152 files (page 30/35)
lines: off (toggle) GitHub
raw markdown copy
This is page 30 of 35. Use http://codebase.md/alibaba/formily?lines=false&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/react/docs/api/shared/Schema.md:
--------------------------------------------------------------------------------

```markdown
# Schema

## Description

The core part of the @formily/react protocol driver. Schema is a general class in which users can use it by themselves. At the same time, both SchemaField and RecursionField rely on it. It has several core capabilities:

- Ability to parse json-schema
- The ability to convert json-schema to Field Model
- The ability to compile json-schema expressions

You can export the Schema Class from @formily/react, but if you don’t want to use @formily/react, you can rely on the @formily/json-schema package alone

## Constructor

```ts
class Schema {
  constructor(json: ISchema, parent?: ISchema)
}
```

Create a Schema Tree based on a piece of json schema data to ensure that each schema node contains the corresponding method

## Attributes

| Property             | Description                                                                     | Type                                                                               | Field Model Mapping                                                      |
| -------------------- | ------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| type                 | Type                                                                            | [SchemaTypes](#schematypes)                                                        | [GeneralField](https://core.formilyjs.org/api/models/field#generalfield) |
| title                | Title                                                                           | React.ReactNode                                                                    | `title`                                                                  |
| description          | Description                                                                     | React.ReactNode                                                                    | `description`                                                            |
| default              | Default value                                                                   | Any                                                                                | `initialValue`                                                           |
| readOnly             | Is it read-only                                                                 | Boolean                                                                            | `readOnly`                                                               |
| writeOnly            | Whether to write only                                                           | Boolean                                                                            | `editable`                                                               |
| enum                 | Enumeration                                                                     | [SchemaEnum](#schemaenum)                                                          | `dataSource`                                                             |
| const                | Check whether the field value is equal to the value of const                    | Any                                                                                | `validator`                                                              |
| multipleOf           | Check whether the field value is divisible by the value of multipleOf           | Number                                                                             | `validator`                                                              |
| maximum              | Check the maximum value (greater than)                                          | Number                                                                             | `validator`                                                              |
| exclusiveMaximum     | Check the maximum value (greater than or equal to                               | Number                                                                             | `validator`                                                              |
| minimum              | Validation minimum value (less than)                                            | Number                                                                             | `validator`                                                              |
| exclusiveMinimum     | Minimum value (less than or equal to)                                           | Number                                                                             | `validator`                                                              |
| maxLength            | Maximum length of verification                                                  | Number                                                                             | `validator`                                                              |
| minLength            | Check minimum length                                                            | Number                                                                             | `validator`                                                              |
| pattern              | Regular verification rules                                                      | RegExpString                                                                       | `validator`                                                              |
| maxItems             | Maximum number of items                                                         | Number                                                                             | `validator`                                                              |
| minItems             | Minimum number of items                                                         | Number                                                                             | `validator`                                                              |
| uniqueItems          | Whether to verify duplicates                                                    | Boolean                                                                            | `validator`                                                              |
| maxProperties        | Maximum number of properties                                                    | Number                                                                             | `validator`                                                              |
| minProperties        | Minimum number of properties                                                    | Number                                                                             | `validator`                                                              |
| required             | required                                                                        | Boolean                                                                            | `validator`                                                              |
| format               | Regular verification format                                                     | [ValidatorFormats](https://core.formilyjs.org/api/models/field#fieldvalidator)     | `validator`                                                              |
| properties           | Property description                                                            | [SchemaProperties](#schemaproperties)                                              | -                                                                        |
| items                | Array description                                                               | [SchemaItems](#schemaitems)                                                        | -                                                                        |
| additionalItems      | Additional array element description                                            | Schema                                                                             | -                                                                        |
| patternProperties    | Schema of a certain property of the dynamic matching object                     | [SchemaProperties](#schemaproperties)                                              | -                                                                        |
| additionalProperties | Schema of matching object additional properties                                 | Schema                                                                             | -                                                                        |
| x-index              | UI display order                                                                | Number                                                                             | -                                                                        |
| x-pattern            | UI interaction mode                                                             | [FieldPatternTypes](https://core.formilyjs.org/api/models/field#fieldpatterntypes) | `pattern`                                                                |
| x-display            | UI display                                                                      | [FieldDisplayTypes](https://core.formilyjs.org/api/models/field#fielddisplaytypes) | `display`                                                                |
| x-validator          | Field Validator                                                                 | [FieldValidator](https://core.formilyjs.org/api/models/field#fieldvalidator)       | `validator`                                                              |
| x-decorator          | Field UI wrapper component                                                      | `String \| React.FC`                                                               | `decorator`                                                              |
| x-decorator-props    | Field UI wrapper component properties                                           | Any                                                                                | `decorator`                                                              |
| x-component          | Field UI component                                                              | `String \| React.FC`                                                               | `component`                                                              |
| x-component-props    | Field UI component properties                                                   | Any                                                                                | `component`                                                              |
| x-reactions          | Field linkage agreement                                                         | [SchemaReactions](#schemareactions)                                                | `reactions`                                                              |
| x-content            | Field content, used to pass in the child nodes of a component                   | React.ReactNode                                                                    | `content`                                                                |
| x-visible            | Field display hidden                                                            | Boolean                                                                            | `visible`                                                                |
| x-hidden             | Field UI hidden (data retention)                                                | Boolean                                                                            | `hidden`                                                                 |
| x-disabled           | Field disabled                                                                  | Boolean                                                                            | `disabled`                                                               |
| x-editable           | Editable field                                                                  | Boolean                                                                            | `editable`                                                               |
| x-read-only          | Field read-only                                                                 | Boolean                                                                            | `readOnly`                                                               |
| x-read-pretty        | Field Reading State                                                             | Boolean                                                                            | `readPretty`                                                             |
| definitions          | Schema predefined                                                               | [SchemaProperties](#schemaproperties)                                              | -                                                                        |
| $ref                 | Read the Schema from the Schema predefined and merge it into the current Schema | String                                                                             | -                                                                        |
| x-data               | Extends Data                                                                    | Object                                                                             | `data`                                                                   |
| x-compile-omitted    | list of attributes to ignore compiled expressions                               | string[]                                                                           | `[]`                                                                     |
| x-slot-node          | Slot node mark                                                                  | [Slot](#slot)                                                                      | -                                                                        |

#### Detailed description

- The component ID of x-component matches the key of the component collection passed in [createSchemaField](/api/components/schema-field#signature)
- The component ID of x-decorator matches the key of the component collection passed in [createSchemaField](/api/components/schema-field#signature)
- Every attribute of Schema can use string expression `{{expression}}`, expression variables can be passed in from createSchemaField or from SchemaField component
- The predefined format of $ref specified Schema must be `#/definitions/address` this format, loading remote JSON Schema is not supported

## Method

### addProperty

#### Description

Add attribute description

#### Signature

```ts
interface addProperty {
  (key: string | number, schema: ISchema): Schema //Return the added Schema object
}
```

### removeProperty

#### Description

Remove attribute description

#### Signature

```ts
interface removeProperty {
  (key: string | number): Schema //Return the removed Schema object
}
```

### setProperties

#### Description

Overwrite update attribute description

#### Signature

```ts
interface setProperties {
  (properties: SchemaProperties): Schema //Return the current Schema object
}
```

SchemaProperties Reference [SchemaProperties](#schemaproperties)

### addPatternProperty

#### Description

Add regular attribute description

#### Signature

```ts
interface addPatternProperty {
  (regexp: string, schema: ISchema): Schema //Return the added Schema object
}
```

### removePatternProperty

#### Description

Remove regular attribute description

#### Signature

```ts
interface removePatternProperty {
  (regexp: string): Schema //Return the removed Schema object
}
```

### setPatternProperties

#### Description

Override update regular attribute description

#### Signature

```ts
interface setPatternProperties {
  (properties: SchemaProperties): Schema //Return the current Schema object
}
```

SchemaProperties Reference [SchemaProperties](#schemaproperties)

### setAdditionalProperties

#### Description

Overwrite update extended attribute description

#### Signature

```ts
interface setAdditionalProperties {
  (properties: ISchema): Schema //Returns the extended properties Schema object
}
```

### setItems

#### Description

Override to update the array item description

#### Signature

```ts
interface setItems {
  (items: SchemaItems): SchemaItems //Return the updated SchemaItems object
}
```

SchemaItems Reference [SchemaItems](#schemaitems)

### setAdditionalItems

#### Description

Override to update the array extension item description

#### Signature

```ts
interface setAdditionalItems {
  (items: ISchema): Schema //Return the updated Schema object
}
```

SchemaItems Reference [SchemaItems](#schemaitems)

### mapProperties

#### Description

Traverse and map the properties of the current Schema, and traverse based on the x-index order

#### Signature

```ts
interface mapProperties<T> {
  (mapper: (property: Schema, key: string | number) => T): T[]
}
```

### mapPatternProperties

#### Description

Traverse and map the patternProperties attribute of the current Schema, and traverse based on the x-index order

#### Signature

```ts
interface mapPatternProperties<T> {
  (mapper: (property: Schema, key: string | number) => T): T[]
}
```

### reduceProperties

#### Description

reduce the properties of the current Schema, and it will be traversed based on the x-index order

#### Signature

```ts
interface reduceProperties<T> {
  (
    reducer: (value: T, property: Schema, key: string | number) => T,
    initialValue?: T
  ): T
}
```

### reducePatternProperties

#### Description

reduce the patternProperties attribute of the current Schema, and it will be traversed based on the x-index order

#### Signature

```ts
interface reducePatternProperties<T> {
  (
    reducer: (value: T, property: Schema, key: string | number) => T,
    initialValue?: T
  ): T
}
```

### compile

#### Description

Deeply recurse the expression fragments in the current Schema object, compile the expression, and return the Schema. We can pass in the scope object, and then consume the scope variable in the expression

Expression fragment convention: a string ending with `{{`beginning with `}}` represents an expression fragment

#### Signature

```ts
interface compile {
  (scope: any): Schema
}
```

### fromJSON

#### Description

Convert ordinary json data into Schema objects

#### Signature

```ts
interface fromJSON {
  (json: ISchema): Schema
}
```

### toJSON

#### Description

Convert the current Schema object into ordinary json data

#### Signature

```ts
interface toJSON {
  (): ISchema
}
```

### toFieldProps

#### Description

Convert the current Schema object into a Formily field model attribute, refer to the mapping relationship [attribute](#attributes)

#### Signature

```ts
import { IFieldFactoryProps } from '@formily/core'

interface toFieldProps {
  (): IFieldFactoryProps
}
```

IFieldFactoryProps reference [IFieldFactoryProps](https://core.formilyjs.org/api/models/form#ifieldfactoryprops)

## Static method

### getOrderProperties

#### Description

Get the sorted properties from the Schema

#### Signature

```ts
interface getOrderProperties {
  (schema: ISchema = {}, propertiesName: keyof ISchema = 'properties'): ISchema
}
```

### compile

#### Description

In-depth traversal of expression fragments in any object, expression fragment convention: a string ending with `{{`beginning`}}` represents an expression fragment

#### Signature

```ts
interface compile {
  (target: any, scope: any): any
}
```

### shallowCompile

#### Description

Shallow traversal of expression fragments in any object, expression fragment convention: a string ending with `{{`beginning with `}}` represents an expression fragment

#### Signature

```ts
interface shallowCompile {
  (target: any, scope: any): any
}
```

### silent

#### Description

Whether to compile silently, if it is, there will be no reminder if the expression error is reported

#### Signature

```ts
interface silent {
  (value?: boolean): void
}
```

### isSchemaInstance

#### Description

Determine whether an object is an instance of Schema Class

#### Signature

```ts
interface isSchemaInstance {
  (target: any): target is Schema
}
```

### registerCompiler

#### Description

Register the expression compiler

#### Signature

```ts
interface registerCompiler {
  (compiler: (expression: string, scope: any) => any): void
}
```

### registerPatches

#### Description

Register Schema patch to facilitate compatibility of different versions of Schema protocol

#### Signature

```ts
type SchemaPatch = (schema: ISchema) => ISchema

interface registerPatches {
  (...args: SchemaPatch[]): void
}
```

### registerVoidComponents

#### Description

Mark the field component to indicate that the component is a virtual component and is compatible with formily1.x

#### Signature

```ts
interface registerVoidComponents {
  (components: string[]): void
}
```

#### Example

```ts
import { Schema } from '@formily/react'

Schema.registerVoidComponents(['card', 'tab', 'step'])
```

<Alert type="warning">
  Note that this api needs to be used with <code>enablePolyfills(['1.0'])</code>
</Alert>

### registerTypeDefaultComponents

#### Description

Identify the default component type for the Schema type

#### Signature

```ts
interface registerTypeDefaultComponents {
  (maps: Record<string, string>): void
}
```

#### Example

```ts
import { Schema } from '@formily/react'

Schema.registerTypeDefaultComponents({
  string: 'Input',
  number: 'NumberPicker',
  array: 'ArrayTable',
})
```

<Alert type="warning">
  Note that this api needs to be used with <code>enablePolyfills(['1.0'])</code>
</Alert>

### registerPolyfills

#### Description

Registration agreement compatible gasket

#### Signature

```ts
type SchemaPatch = (schema: ISchema) => ISchema

interface registerPolyfills {
  (version: string, patch: SchemaPatch): void
}
```

#### Example

```ts
import { Schema } from '@formily/react'

Schema.registerPolyfills('1.0', (schema) => {
  schema['x-decorator'] = 'FormItem'
  return schema
})
```

### enablePolyfills

#### Description

Turn on the protocol gasket, the 1.0 version protocol compatible gasket is built in by default, and the main compatibility features are:

- x-decorator does not declare, it is automatically used as FormItem
- x-linkages converted to x-reactions
- x-props is automatically converted to x-decorator-props
- x-rules converted to x-validator
- convert editable to x-editable
- Convert visible to x-visible
- x-component is automatically converted to VoidField for card/block/grid-row/grid-col/grid/layout/step/tab/text-box,

#### Signature

```ts
interface enablePolyfills {
  (versions: string[]): void
}
```

#### Example

```ts
import { Schema } from '@formily/react'

Schema.enablePolyfills(['1.0'])
```

## Types of

### ISchema

#### Description

ISchema is a normal JSON data, and at the same time it is JSON data following the Schema [Attribute](#attributes) specification

### SchemaTypes

#### Description

Schema description type

#### Signature

```ts
type SchemaTypes =
  | 'string'
  | 'object'
  | 'array'
  | 'number'
  | 'boolean'
  | 'void'
  | 'date'
  | 'datetime'
  | (string & {})
```

### SchemaProperties

#### Description

Schema attribute description

#### Signature

```ts
type SchemaProperties = Record<string, ISchema>
```

### SchemaItems

#### Description

Schema array item description

#### Signature

```ts
type SchemaItems = ISchema | ISchema[]
```

### SchemaEnum

#### Description

Schema enum

#### Signature

```ts
type SchemaEnum<Message> = Array<
  | string
  | number
  | { label: Message; value: any; [key: string]: any }
  | { key: any; title: Message; [key: string]: any }
>
```

### SchemaReactions

#### Description

Schema linkage protocol, if the reaction object contains target, it represents active linkage mode, otherwise it represents passive linkage mode  
If you want to achieve more complex linkage, you can pass in the reaction responder function through the scope for processing  
FormPathPattern path syntax documentation is [here](https://core.formilyjs.org/api/entry/form-path#formpathpattern)

#### Signature

```ts
import { IGeneralFieldState } from '@formily/core'

type SchemaReactionEffect =
  | 'onFieldInit'
  | 'onFieldMount'
  | 'onFieldUnmount'
  | 'onFieldValueChange'
  | 'onFieldInputValueChange'
  | 'onFieldInitialValueChange'
  | 'onFieldValidateStart'
  | 'onFieldValidateEnd'
  | 'onFieldValidateFailed'
  | 'onFieldValidateSuccess'

type SchemaReaction<Field = any> =
  | {
      dependencies?: //The list of dependent field paths can only describe dependencies in dot paths, and supports relative paths
      | Array<
            | string //If it is an array contains string format, then it is also an array format when reading
            | {
                //If it is an array contains object format, then it is an object format when reading, but the name field is equivalent to an alias
                name?: string
                type?: string
                source?: string
                property?: string
              }
          >
        | Record<string, string> //If it is an object format, It is also an object format when reading, but the key for object is equivalent to an alias
      when?: string | boolean //Linkage condition
      target?: string //The field path to be operated, supports FormPathPattern path syntax, note: relative path is not supported! !
      effects?: SchemaReactionEffect[] //Independent life cycle hook in active mode
      fulfill?: {
        //To meet the conditions
        state?: IGeneralFieldState //Update state
        schema?: ISchema //Update Schema
        run?: string //Execute statement
      }
      otherwise?: {
        //Does not meet the conditions
        state?: IGeneralFieldState //Update state
        schema?: ISchema //Update Schema
        run?: string //Execute statement
      }
    }
  | ((field: Field) => void) //Can be complex linkage

type SchemaReactions<Field = any> =
  | SchemaReaction<Field>
  | SchemaReaction<Field>[]
```

#### Example

**Active linkage**

Writing method one, standard initiative linkage

```json
{
  "type": "object",
  "properties": {
    "source": {
      "type": "string",
      "x-component": "Input",
      "x-reactions": {
        "target": "target",
        "when": "{{$self.value === '123'}}",
        "fulfill": {
          "state": {
            "visible": false
          }
        },
        "otherwise": {
          "state": {
            "visible": true
          }
        }
      }
    },
    "target": {
      "type": "string",
      "x-component": "Input"
    }
  }
}
```

Writing method two, local expression distribution linkage

```json
{
  "type": "object",
  "properties": {
    "source": {
      "type": "string",
      "x-component": "Input",
      "x-reactions": {
        "target": "target",
        "fulfill": {
          "state": {
            "visible": "{{$self.value === '123'}}" //Any level of attributes supports expressions
          }
        }
      }
    },
    "target": {
      "type": "string",
      "x-component": "Input"
    }
  }
}
```

Writing method three, based on Schema protocol linkage

```json
{
  "type": "object",
  "properties": {
    "source": {
      "type": "string",
      "x-component": "Input",
      "x-reactions": {
        "target": "target",
        "fulfill": {
          "schema": {
            "x-visible": "{{$self.value === '123'}}" //Any level of attributes supports expressions
          }
        }
      }
    },
    "target": {
      "type": "string",
      "x-component": "Input"
    }
  }
}
```

Writing method four, based on run statement linkage

```json
{
  "type": "object",
  "properties": {
    "source": {
      "type": "string",
      "x-component": "Input",
      "x-reactions": {
        "fulfill": {
          "run": "$form.setFieldState('target',state=>{state.visible = $self.value === '123'})"
        }
      }
    },
    "target": {
      "type": "string",
      "x-component": "Input"
    }
  }
}
```

Writing method five, based on the linkage of life cycle hooks

```json
{
  "type": "object",
  "properties": {
    "source": {
      "type": "string",
      "x-component": "Input",
      "x-reactions": {
        "target": "target",
        "effects": ["onFieldInputValueChange"],
        "fulfill": {
          "state": {
            "visible": "{{$self.value === '123'}}" //Any level of attributes supports expressions
          }
        }
      }
    },
    "target": {
      "type": "string",
      "x-component": "Input"
    }
  }
}
```

**Passive linkage**

Writing method one, standard passive linkage

```json
{
  "type": "object",
  "properties": {
    "source": {
      "type": "string",
      "x-component": "Input"
    },
    "target": {
      "type": "string",
      "x-component": "Input",
      "x-reactions": {
        "dependencies": ["source"], //Dependency path is written by default to take value. If you rely on other attributes of the field, you can use source#modified, and use # to split to get detailed attributes
        // "dependencies":{ aliasName:"source" }, //alias form
        "fulfill": {
          "schema": {
            "x-visible": "{{$deps[0] === '123'}}" //Any level of attributes supports expressions
          }
        }
      }
    }
  }
}
```

Writing method two, linkage of adjacent elements

```json
{
  "type": "array",
  "x-component": "ArrayTable",
  "items": {
    "type": "object",
    "properties": {
      "source": {
        "type": "string",
        "x-component": "Input"
      },
      "target": {
        "type": "string",
        "x-component": "Input",
        "x-reactions": {
          "dependencies": [".source"],
          "fulfill": {
            "schema": {
              "x-visible": "{{$deps[0] === '123'}}"
            }
          }
        }
      }
    }
  }
}
```

**Complex linkage**

```json
{
  "type": "object",
  "properties": {
    "source": {
      "type": "string",
      "x-component": "Input"
    },
    "target": {
      "type": "string",
      "x-component": "Input",
      "x-reactions": "{{myReaction}}" //For externally passed functions, more complex linkages can be realized within the function
    }
  }
}
```

**Component attribute linkage**

Writing one, operating status

```json
{
  "type": "object",
  "properties": {
    "source": {
      "type": "string",
      "x-component": "Input",
      "x-reactions": {
        "target": "target",
        "fulfill": {
          "state": {
            "component[1].style.color": "{{$self.value === '123'?'red':'blue'}}" //Any level attribute supports expressions, and the key is a support path Expression, can achieve precise manipulation of attributes
          }
        }
      }
    },
    "target": {
      "type": "string",
      "x-component": "Input"
    }
  }
}
```

Writing method two, operating the Schema protocol

```json
{
  "type": "object",
  "properties": {
    "source": {
      "type": "string",
      "x-component": "Input",
      "x-reactions": {
        "target": "target",
        "fulfill": {
          "schema": {
            "x-component-props.style.color": "{{$self.value === '123'?'red':'blue'}}" //Any level of property supports expressions, and the key is supported Path expression, can achieve precise operation properties
          }
        }
      }
    },
    "target": {
      "type": "string",
      "x-component": "Input"
    }
  }
}
```

### Slot

#### Description

Mark this node as a Slot node, which will be skipped in the normal rendering process.  
Use `target` to specify the target property for rendering this node, which must be a sibling property at the same level.  
You can use `isRenderProp` to specify that this node is passed in the form of the renderProp function.  
When `isRenderProp` is `true`, the renderProp function’s argument list can be accessed within the Slot through `$slotArgs`.

#### Signature

```ts
type Slot = {
  //Slot target: Specify the target property for rendering this node, which must be a sibling property at the same level.
  target: string // 'some-sibling-node.x-component-props.xxx' or 'some-sibling-node.x-decorator-props.xxx'
  //whether it is a renderProp Slot
  isRenderProp?: boolean
}
```

#### Example

**ReactNode Prop**  
Reference [SchemaField](https://react.formilyjs.org/api/components/schema-field#json-schema-reactnode-prop-use-case-x-slot-node)

```json
{
  "type": "object",
  "properties": {
    "search_icon": {
      "x-slot-node": {
        "target": "button.x-component-props.icon" //Specify to render the search_icon node as a slot into the icon prop of the Button component.
      },
      "x-component": "SearchOutlined",
      "x-component-props": {
        "data-testid": "icon"
      }
    },
    "button": {
      "type": "string",
      "x-component": "Button",
      "x-component-props": {
        "data-testid": "button"
      }
    }
  }
}
```

**RenderProp**  
Reference [SchemaField](https://react.formilyjs.org/api/components/schema-field#json-schema-render-prop-use-case-x-slot-node--isrenderprop)

```json
{
  "type": "object",
  "properties": {
    "dollar_icon": {
      "x-slot-node": {
        "target": "rate.x-component-props.character", //Specify to render the dollar_icon node as a slot into the character prop of the Rate component.
        "isRenderProp": true //The character prop accepts a renderProp function. Specify the Slot as a renderProp to take control of the rendering of the rating icons.
      },
      "x-component": "DollarOutlined",
      "x-component-props": {
        "data-testid": "icon",
        "rotate": "{{$slotArgs[0].value * 45}}", //When isRenderProp is true, the renderProp function’s argument list can be accessed within the Slot through $slotArgs.
        "style": {
          "fontSize": "50px"
        }
      }
    },
    "rate": {
      "x-component": "Rate"
    }
  }
}
```

## Built-in expression scope

Built-in expression scope is mainly used to realize various linkage relationships in expressions

### $self

Represents the current field instance, can be used in ordinary attribute expressions, and can also be used in x-reactions

### $values

Represents the top-level form data, which can be used in ordinary attribute expressions, and can also be used in x-reactions

### $form

Represents the current Form instance, which can be used in ordinary attribute expressions, and can also be used in x-reactions

### $observable

It is used to create reactive objects in the same way as observable

### $memo

Used to create persistent reference data in the same way as autorun.memo

### $effect

The timing of the next microtask in response to autorun's first execution and the dispose in response to autorun are used in the same way as autorun.effect

### $dependencies

It can only be consumed by expressions in x-reactions, corresponding to the dependencies defined by x-reactions, and the sequence of the array is the same

### $deps

It can only be consumed by expressions in x-reactions, corresponding to the dependencies defined by x-reactions, and the sequence of the array is the same

### $target

Can only be consumed in expressions in x-reactions, representing the target field of active mode

### $slotArgs

Can only be consumed in slot node. When slot used as render prop, $slotArgs can access render function arguments array

```

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

```markdown
# FormItem

> The brand-new FormItem component, compared to Antd's FormItem, it supports more functions. At the same time, it is positioned as a pure style component and does not manage the state of the form, so it will be lighter and more convenient for customization

## Markup Schema example

```tsx
import React from 'react'
import { Input, Select, FormItem, FormButtonGroup, Submit } from '@formily/antd'
import { createForm } from '@formily/core'
import { FormProvider, createSchemaField } from '@formily/react'

const SchemaField = createSchemaField({
  components: {
    Input,
    Select,
    FormItem,
  },
})

const form = createForm()

export default () => (
  <FormProvider form={form}>
    <SchemaField>
      <SchemaField.String
        name="input"
        title="input box"
        x-decorator="FormItem"
        x-component="Input"
        required
      />
    </SchemaField>
    <FormButtonGroup>
      <Submit onSubmit={console.log}>Submit</Submit>
    </FormButtonGroup>
  </FormProvider>
)
```

## JSON Schema case

```tsx
import React from 'react'
import { Input, FormItem, FormButtonGroup, Submit } from '@formily/antd'
import { createForm } from '@formily/core'
import { FormProvider, createSchemaField } from '@formily/react'

const SchemaField = createSchemaField({
  components: {
    Input,
    FormItem,
  },
})

const form = createForm()

const schema = {
  type: 'object',
  properties: {
    input: {
      type: 'string',
      title: 'input box',
      'x-decorator': 'FormItem',
      'x-component': 'Input',
      'x-component-props': {
        style: {
          width: 240,
        },
      },
    },
  },
}

export default () => (
  <FormProvider form={form}>
    <SchemaField schema={schema} />
    <FormButtonGroup>
      <Submit onSubmit={console.log}>Submit</Submit>
    </FormButtonGroup>
  </FormProvider>
)
```

## Pure JSX case

```tsx
import React from 'react'
import { Input, FormItem, FormButtonGroup, Submit } from '@formily/antd'
import { createForm } from '@formily/core'
import { FormProvider, Field } from '@formily/react'

const form = createForm()

export default () => (
  <FormProvider form={form}>
    <Field
      name="input"
      title="input box"
      required
      decorator={[FormItem]}
      component={[
        Input,
        {
          style: {
            width: 240,
          },
        },
      ]}
    />
    <FormButtonGroup>
      <Submit onSubmit={console.log}>Submit</Submit>
    </FormButtonGroup>
  </FormProvider>
)
```

## Commonly used attribute cases

```tsx
import React from 'react'
import {
  Input,
  Radio,
  TreeSelect,
  Cascader,
  Select,
  DatePicker,
  FormItem,
  NumberPicker,
  Switch,
} from '@formily/antd'
import { createForm } from '@formily/core'
import { FormProvider, createSchemaField } from '@formily/react'

const Title = (props) => <h3>{props.text}</h3>

const SchemaField = createSchemaField({
  components: {
    Input,
    Select,
    Cascader,
    TreeSelect,
    DatePicker,
    NumberPicker,
    Switch,
    Radio,
    FormItem,
    Title,
  },
})

const form = createForm()

export default () => {
  return (
    <FormProvider form={form}>
      <SchemaField>
        <SchemaField.Void
          x-component="Title"
          x-component-props={{ text: 'Display when label is empty' }}
        />
        <SchemaField.String
          x-decorator="FormItem"
          x-component="Input"
          x-decorator-props={{
            labelWidth: 300,
          }}
        />
        <SchemaField.String
          title=""
          x-decorator="FormItem"
          x-component="Input"
          x-decorator-props={{
            labelWidth: 300,
          }}
        />
        <SchemaField.Void
          x-component="Title"
          x-component-props={{ text: 'colon' }}
        />
        <SchemaField.String
          title="default"
          x-decorator="FormItem"
          x-component="Input"
        />
        <SchemaField.String
          title="no colon (colon=false)"
          x-decorator="FormItem"
          x-component="Input"
          x-decorator-props={{
            colon: false,
          }}
        />

        <SchemaField.Void
          x-component="Title"
          x-component-props={{ text: 'Fixed width settings' }}
        />
        <SchemaField.String
          title="Fixed label width (labelWidth)"
          x-decorator="FormItem"
          x-component="Input"
          x-decorator-props={{
            labelWidth: 300,
          }}
        />
        <SchemaField.String
          title="Fixed label width (labelWidth) overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow overflow"
          description="description description"
          x-decorator="FormItem"
          x-component="Input"
          x-decorator-props={{
            labelWidth: 300,
            tooltip: 'Prompt Tip',
            tooltipLayout: 'text',
          }}
        />
        <SchemaField.String
          title="Fixed label width (labelWidth) newline newline newline newline newline newline newline newline newline newline newline newline newline newline newline newline newline newline newline newline newline newline newline newline newline"
          description="description description"
          x-decorator="FormItem"
          x-component="Input"
          x-decorator-props={{
            labelWidth: 300,
            labelWrap: true,
            tooltip: 'Prompt Tip',
          }}
        />
        <SchemaField.String
          title="fixed content width (wrapperWidth)"
          x-decorator="FormItem"
          x-component="Input"
          x-decorator-props={{
            labelWidth: 300,
            wrapperWidth: 300,
          }}
        />

        <SchemaField.Void
          x-component="Title"
          x-component-props={{ text: 'Alignment settings' }}
        />
        <SchemaField.String
          title="labelLeft Alignment(labelAlign=left)"
          x-decorator="FormItem"
          x-component="Input"
          x-decorator-props={{
            labelWidth: 300,
            labelAlign: 'left',
          }}
        />
        <SchemaField.String
          title="label right alignment (labelAlign=right default)"
          x-decorator="FormItem"
          x-component="Input"
          x-decorator-props={{
            labelWidth: 300,
            labelAlign: 'right',
          }}
        />

        <SchemaField.String
          title="Content left aligned (wrapperAlign=left default)"
          x-decorator="FormItem"
          x-component="Input"
          x-decorator-props={{
            labelWidth: 300,
            wrapperWidth: 240,
            wrapperAlign: 'left',
          }}
        />
        <SchemaField.String
          title="Content align right (wrapperAlign=right)"
          x-decorator="FormItem"
          x-component="Input"
          x-decorator-props={{
            labelWidth: 300,
            wrapperWidth: 240,
            wrapperAlign: 'right',
          }}
        />

        <SchemaField.String
          title="tooltip"
          x-decorator="FormItem"
          x-component="Input"
          x-decorator-props={{
            tooltip: 'tooltip',
          }}
        />

        <SchemaField.Void
          x-component="Title"
          x-component-props={{ text: 'Is it full?' }}
        />

        <SchemaField.String
          title="The default is not full (fullness=false)"
          x-decorator="FormItem"
          x-component="Select"
        />
        <SchemaField.String
          title="Fullness(fullness=true)"
          x-decorator="FormItem"
          x-component="Select"
          x-decorator-props={{
            fullness: true,
          }}
        />

        <SchemaField.Void
          x-component="Title"
          x-component-props={{ text: 'auxiliary information' }}
        />

        <SchemaField.String
          title="Required asterisk"
          x-decorator="FormItem"
          x-component="Input"
          x-decorator-props={{
            asterisk: true,
            labelCol: 6,
            wrapperCol: 10,
          }}
        />

        <SchemaField.String
          title="prefix"
          x-decorator="FormItem"
          x-component="Input"
          x-decorator-props={{
            addonBefore: 'addonBefore',
            labelCol: 6,
            wrapperCol: 10,
          }}
        />
        <SchemaField.String
          title="suffix"
          x-decorator="FormItem"
          x-component="Input"
          x-decorator-props={{
            addonAfter: 'addonAfter',
            labelCol: 6,
            wrapperCol: 10,
          }}
        />

        <SchemaField.String
          title="Help information feedbackText"
          x-decorator="FormItem"
          x-component="Input"
          x-decorator-props={{
            feedbackText: 'feedbackText',
            labelCol: 6,
            wrapperCol: 10,
          }}
        />

        <SchemaField.String
          title="extra information extra"
          x-decorator="FormItem"
          x-component="Input"
          x-decorator-props={{
            feedbackText: 'feedbackText',
            extra: 'extra',
            labelCol: 6,
            wrapperCol: 10,
          }}
        />
      </SchemaField>
    </FormProvider>
  )
}
```

## Required style

```tsx
import React, { useState } from 'react'
import { Input, FormItem, FormLayout } from '@formily/antd'
import { Radio } from 'antd'
import { createForm } from '@formily/core'
import { FormProvider, createSchemaField } from '@formily/react'

const SchemaField = createSchemaField({
  components: {
    Input,
    FormItem,
  },
})

const form = createForm()

export default () => {
  const [requiredMark, setRequiredMark] = useState(true)
  return (
    <div>
      <p>
        Required Mark:
        <Radio.Group
          value={requiredMark}
          onChange={(e) => setRequiredMark(e.target.value)}
        >
          <Radio.Button value="optional">optional</Radio.Button>
          <Radio.Button value={true}>true</Radio.Button>
          <Radio.Button value={false}>false</Radio.Button>
        </Radio.Group>
      </p>
      <FormProvider form={form}>
        <FormLayout requiredMark={requiredMark}>
          <SchemaField>
            <SchemaField.String
              title="I am Required"
              required
              x-decorator="FormItem"
              x-component="Input"
            />
            <SchemaField.String
              title="I am Optional"
              x-decorator="FormItem"
              x-component="Input"
            />
            <SchemaField.String
              default="When the field is not editable, always hide the required/optional flag"
              x-editable={false}
              x-decorator="FormItem"
              x-component="Input"
            />
            <SchemaField.String
              title="I am Required"
              required
              default="Not editable"
              x-editable={false}
              x-decorator="FormItem"
              x-component="Input"
            />
            <SchemaField.String
              title="I am Optional"
              default="Not editable"
              x-editable={false}
              x-decorator="FormItem"
              x-component="Input"
            />
          </SchemaField>
        </FormLayout>
      </FormProvider>
    </div>
  )
}
```

## Borderless case

Set to remove the component border

```tsx
import React from 'react'
import {
  Input,
  Radio,
  TreeSelect,
  Cascader,
  Select,
  DatePicker,
  FormItem,
  NumberPicker,
  Switch,
} from '@formily/antd'
import { createForm } from '@formily/core'
import { FormProvider, createSchemaField } from '@formily/react'

const Title = (props) => <h3>{props.text}</h3>

const SchemaField = createSchemaField({
  components: {
    Input,
    Select,
    Cascader,
    TreeSelect,
    DatePicker,
    NumberPicker,
    Switch,
    Radio,
    FormItem,
    Title,
  },
})

const form = createForm()

export default () => {
  return (
    <FormProvider form={form}>
      <SchemaField>
        <SchemaField.String
          name="input"
          title="Input"
          x-decorator="FormItem"
          x-component="Input"
          required
          x-decorator-props={{
            bordered: false,
          }}
        />
        <SchemaField.String
          name="Select"
          title="Select"
          x-decorator="FormItem"
          x-component="Select"
          required
          x-decorator-props={{
            bordered: false,
          }}
        />
        <SchemaField.String
          name="Select"
          title="Select"
          x-decorator="FormItem"
          x-component="Select"
          required
          x-decorator-props={{
            bordered: false,
          }}
        />
        <SchemaField.String
          name="Cascader"
          title="Cascader"
          x-decorator="FormItem"
          x-component="Cascader"
          required
          x-decorator-props={{
            bordered: false,
          }}
        />
        <SchemaField.String
          name="DatePicker"
          title="DatePicker"
          x-decorator="FormItem"
          x-component="DatePicker"
          required
          x-decorator-props={{
            bordered: false,
          }}
        />
        <SchemaField.String
          name="NumberPicker"
          title="NumberPicker"
          x-decorator="FormItem"
          x-component="NumberPicker"
          required
          x-decorator-props={{
            bordered: false,
          }}
        />
        <SchemaField.String
          name="TreeSelect"
          title="TreeSelect"
          x-decorator="FormItem"
          x-component="TreeSelect"
          required
          x-decorator-props={{
            bordered: false,
          }}
        />
        <SchemaField.Boolean
          name="Switch"
          title="Switch"
          x-decorator="FormItem"
          x-component="Switch"
          required
          x-decorator-props={{
            bordered: false,
          }}
        />
      </SchemaField>
    </FormProvider>
  )
}
```

## Embedded mode case

Set the form component to inline mode

```tsx
import React from 'react'
import {
  Input,
  Radio,
  TreeSelect,
  Cascader,
  Select,
  DatePicker,
  FormItem,
  NumberPicker,
  Switch,
} from '@formily/antd'
import { createForm } from '@formily/core'
import { FormProvider, createSchemaField } from '@formily/react'

const Title = (props) => <h3>{props.text}</h3>

const SchemaField = createSchemaField({
  components: {
    Input,
    Select,
    Cascader,
    TreeSelect,
    DatePicker,
    NumberPicker,
    Switch,
    Radio,
    FormItem,
    Title,
  },
})

const form = createForm()

export default () => {
  return (
    <FormProvider form={form}>
      <SchemaField>
        <SchemaField.String
          name="input"
          title="Input"
          x-decorator="FormItem"
          x-component="Input"
          required
          x-decorator-props={{
            inset: true,
          }}
        />
        <SchemaField.String
          name="Select"
          title="Select"
          x-decorator="FormItem"
          x-component="Select"
          required
          x-decorator-props={{
            inset: true,
          }}
        />
        <SchemaField.String
          name="Select"
          title="Select"
          x-decorator="FormItem"
          x-component="Select"
          required
          x-decorator-props={{
            inset: true,
          }}
        />
        <SchemaField.String
          name="Cascader"
          title="Cascader"
          x-decorator="FormItem"
          x-component="Cascader"
          required
          x-decorator-props={{
            inset: true,
          }}
        />
        <SchemaField.String
          name="DatePicker"
          title="DatePicker"
          x-decorator="FormItem"
          x-component="DatePicker"
          required
          x-decorator-props={{
            inset: true,
          }}
        />
        <SchemaField.String
          name="NumberPicker"
          title="NumberPicker"
          x-decorator="FormItem"
          x-component="NumberPicker"
          required
          x-decorator-props={{
            inset: true,
          }}
        />
        <SchemaField.String
          name="TreeSelect"
          title="TreeSelect"
          x-decorator="FormItem"
          x-component="TreeSelect"
          required
          x-decorator-props={{
            inset: true,
          }}
        />
        <SchemaField.Boolean
          name="Switch"
          title="Switch"
          x-decorator="FormItem"
          x-component="Switch"
          required
          x-decorator-props={{
            inset: false,
          }}
        />
      </SchemaField>
    </FormProvider>
  )
}
```

## Feedback Customization Case

The button for specifying feedback can be passed in through `feedbackIcon`

```tsx
import React from 'react'
import {
  Input,
  Radio,
  TreeSelect,
  Cascader,
  Select,
  DatePicker,
  TimePicker,
  FormItem,
  FormLayout,
  NumberPicker,
  Switch,
} from '@formily/antd'
import { createForm } from '@formily/core'
import { FormProvider, createSchemaField } from '@formily/react'
import { CheckCircleFilled, LoadingOutlined } from '@ant-design/icons'
const Title = (props) => <h3>{props.text}</h3>

const SchemaField = createSchemaField({
  components: {
    Input,
    Select,
    Cascader,
    TreeSelect,
    DatePicker,
    TimePicker,
    NumberPicker,
    Switch,
    Radio,
    FormItem,
    Title,
    FormLayout,
  },
})

const form = createForm()

export default () => {
  return (
    <FormProvider form={form}>
      <SchemaField>
        <SchemaField.String
          title="error status (feedbackStatus=error)"
          x-decorator="FormItem"
          x-component="Input"
          description="description"
          x-decorator-props={{
            feedbackStatus: 'error',
          }}
        />

        <SchemaField.String
          title="Warning Status(feedbackStatus=warning)"
          x-decorator="FormItem"
          x-component="Input"
          description="description"
          x-decorator-props={{
            feedbackStatus: 'warning',
          }}
        />

        <SchemaField.String
          title="Success Status (feedbackStatus=success)"
          x-decorator="FormItem"
          x-component="Input"
          description="description"
          x-decorator-props={{
            feedbackStatus: 'success',
            feedbackIcon: <CheckCircleFilled style={{ color: '#52c41a' }} />,
          }}
        />

        <SchemaField.String
          title="Loading Status(feedbackStatus=pending)"
          x-decorator="FormItem"
          x-component="Input"
          description="description"
          x-decorator-props={{
            feedbackStatus: 'pending',
            feedbackIcon: <LoadingOutlined style={{ color: '#1890ff' }} />,
          }}
        />

        <SchemaField.String
          title="Status border style disabled(feedbackStatus=error)"
          x-decorator="FormItem"
          x-component="Input"
          description="description"
          x-decorator-props={{
            enableOutlineFeedback: false,
            feedbackStatus: 'error',
          }}
        />

        <SchemaField.Void
          x-component="Title"
          x-component-props={{ text: 'Layout of feedback information' }}
        />

        <SchemaField.String
          title="Compact mode required"
          x-decorator="FormItem"
          x-component="Input"
          required
          x-decorator-props={{
            feedbackLayout: 'terse',
          }}
        />

        <SchemaField.String
          title="Compact mode has feedback(feedbackLayout=terse)"
          x-decorator="FormItem"
          x-component="Input"
          x-decorator-props={{
            feedbackStatus: 'error',
            feedbackText: 'error message',
            feedbackLayout: 'terse',
          }}
        />

        <SchemaField.String
          title="Compact mode without feedback(feedbackLayout=terse)"
          x-decorator="FormItem"
          x-component="Input"
          x-decorator-props={{
            feedbackLayout: 'terse',
          }}
        />

        <SchemaField.String
          title="loose mode (feedbackLayout=loose)"
          x-decorator="FormItem"
          x-component="Input"
          x-decorator-props={{
            feedbackStatus: 'error',
            feedbackText: 'error message',
            feedbackLayout: 'loose',
          }}
        />

        <SchemaField.String
          title="Popup Mode (feedbackLayout=popover)"
          x-decorator="FormItem"
          x-component="Input"
          x-decorator-props={{
            feedbackStatus: 'warning',
            feedbackText: 'warning message',
            feedbackLayout: 'popover',
          }}
        />

        <SchemaField.String
          title="Popup Mode (feedbackLayout=popover)"
          x-decorator="FormItem"
          x-component="Input"
          x-decorator-props={{
            feedbackStatus: 'error',
            feedbackText: 'error message',
            feedbackLayout: 'popover',
          }}
        />
        <SchemaField.String
          title="Popup Mode (feedbackLayout=popover)"
          x-decorator="FormItem"
          x-component="Input"
          x-decorator-props={{
            feedbackStatus: 'success',
            feedbackText: 'success message',
            feedbackLayout: 'popover',
          }}
        />

        <SchemaField.Void
          x-component="Title"
          x-component-props={{ text: 'Component adaptation' }}
        />
        <SchemaField.Void
          x-component="FormLayout"
          x-component-props={{ layout: 'vertical' }}
        >
          <SchemaField.String
            title="Select"
            x-decorator="FormItem"
            x-component="Select"
            x-decorator-props={{
              feedbackStatus: 'success',
              feedbackIcon: <CheckCircleFilled style={{ color: '#52c41a' }} />,
            }}
          />

          <SchemaField.String
            title="DatePicker"
            x-decorator="FormItem"
            x-component="DatePicker"
            x-decorator-props={{
              feedbackStatus: 'success',
              feedbackIcon: <CheckCircleFilled style={{ color: '#52c41a' }} />,
            }}
          />
          <SchemaField.String
            title="DatePicker.RangePicker"
            x-decorator="FormItem"
            x-component="DatePicker.RangePicker"
            x-decorator-props={{
              feedbackStatus: 'success',
              feedbackIcon: <CheckCircleFilled style={{ color: '#52c41a' }} />,
            }}
          />
          <SchemaField.String
            title="DatePicker.YearPicker"
            x-decorator="FormItem"
            x-component="DatePicker.YearPicker"
            x-decorator-props={{
              feedbackStatus: 'success',
              feedbackIcon: <CheckCircleFilled style={{ color: '#52c41a' }} />,
            }}
          />
          <SchemaField.String
            title="DatePicker.MonthPicker"
            x-decorator="FormItem"
            x-component="DatePicker.MonthPicker"
            x-decorator-props={{
              feedbackStatus: 'success',
              feedbackIcon: <CheckCircleFilled style={{ color: '#52c41a' }} />,
            }}
          />
          <SchemaField.String
            title="DatePicker.TimePicker"
            x-decorator="FormItem"
            x-component="TimePicker"
            x-decorator-props={{
              feedbackStatus: 'success',
              feedbackIcon: <CheckCircleFilled style={{ color: '#52c41a' }} />,
            }}
          />
          <SchemaField.String
            title="NumberPicker"
            x-decorator="FormItem"
            x-component="NumberPicker"
            x-decorator-props={{
              feedbackStatus: 'success',
              feedbackIcon: <CheckCircleFilled style={{ color: '#52c41a' }} />,
            }}
          />

          <SchemaField.String
            title="TreeSelect"
            x-decorator="FormItem"
            x-component="TreeSelect"
            x-decorator-props={{
              feedbackStatus: 'success',
              feedbackIcon: <CheckCircleFilled style={{ color: '#52c41a' }} />,
            }}
          />

          <SchemaField.String
            title="Cascader"
            x-decorator="FormItem"
            x-component="Cascader"
            x-decorator-props={{
              feedbackStatus: 'success',
              feedbackIcon: <CheckCircleFilled style={{ color: '#52c41a' }} />,
            }}
          />
        </SchemaField.Void>
      </SchemaField>
    </FormProvider>
  )
}
```

## Size control case

```tsx
import React from 'react'
import {
  Input,
  Radio,
  TreeSelect,
  Cascader,
  Select,
  DatePicker,
  FormItem,
  NumberPicker,
  Switch,
} from '@formily/antd'
import { createForm, onFieldChange } from '@formily/core'
import { FormProvider, createSchemaField } from '@formily/react'

const Div = (props) => <div {...props} />

const SchemaField = createSchemaField({
  components: {
    Input,
    Select,
    Cascader,
    TreeSelect,
    DatePicker,
    NumberPicker,
    Switch,
    Radio,
    FormItem,
    Div,
  },
})

const form = createForm({
  values: {
    size: 'default',
  },
  effects: () => {
    onFieldChange('size', ['value'], (field, form) => {
      form.setFieldState('sizeWrap.*', (state) => {
        if (state.decorator[1]) {
          state.decorator[1].size = field.value
        }
      })
    })
  },
})

export default () => {
  return (
    <FormProvider form={form}>
      <SchemaField>
        <SchemaField.String
          name="size"
          title="Radio.Group"
          x-decorator="FormItem"
          x-component="Radio.Group"
          enum={[
            { value: 'small', label: 'Small' },
            { value: 'default', label: 'Default' },
            { value: 'large', label: 'Large' },
          ]}
        />
        <SchemaField.Void name="sizeWrap" x-component="Div">
          <SchemaField.String
            name="input"
            title="Input"
            x-decorator="FormItem"
            x-component="Input"
            required
          />
          <SchemaField.String
            name="select1"
            title="Multiple Select"
            x-decorator="FormItem"
            x-component="Select"
            enum={[
              {
                label: 'Option 1',
                value: 1,
              },
              {
                label: 'Option 2',
                value: 2,
              },
            ]}
            x-component-props={{
              mode: 'multiple',
              placeholder: 'Please choose',
            }}
            required
          />
          <SchemaField.String
            name="select2"
            title="Select"
            x-decorator="FormItem"
            x-component="Select"
            enum={[
              {
                label: 'Option 1',
                value: 1,
              },
              {
                label: 'Option 2',
                value: 2,
              },
            ]}
            x-component-props={{
              placeholder: 'Please choose',
            }}
            required
          />
          <SchemaField.String
            name="Cascader"
            title="Cascader"
            x-decorator="FormItem"
            x-component="Cascader"
            required
          />
          <SchemaField.String
            name="DatePicker"
            title="DatePicker"
            x-decorator="FormItem"
            x-component="DatePicker"
            required
          />
          <SchemaField.String
            name="NumberPicker"
            title="NumberPicker"
            x-decorator="FormItem"
            x-component="NumberPicker"
            required
          />
          <SchemaField.String
            name="TreeSelect"
            title="TreeSelect"
            x-decorator="FormItem"
            x-component="TreeSelect"
            required
          />
          <SchemaField.Boolean
            name="Switch"
            title="Switch"
            x-decorator="FormItem"
            x-component="Switch"
            required
          />
        </SchemaField.Void>
      </SchemaField>
    </FormProvider>
  )
}
```

## API

### FormItem

| Property name         | Type                                                   | Description                                                                                                                                   | Default value       |
| --------------------- | ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------- | ------------------- |
| label                 | ReactNode                                              | label                                                                                                                                         | -                   |
| style                 | CSSProperties                                          | Style                                                                                                                                         | -                   |
| labelStyle            | CSSProperties                                          | Label style                                                                                                                                   | -                   |
| wrapperStyle          | CSSProperties                                          | Component container style                                                                                                                     | -                   |
| className             | string                                                 | Component style class name                                                                                                                    | -                   |
| colon                 | boolean                                                | colon                                                                                                                                         | true                |
| tooltip               | ReactNode                                              | Question mark prompt                                                                                                                          | -                   |
| tooltipLayout         | `"icon" \| "text"`                                     | Ask the prompt layout                                                                                                                         | `"icon"`            |
| tooltipIcon           | ReactNode                                              | Ask the prompt icon                                                                                                                           | `?`                 |
| labelAlign            | `"left"` \| `"right"`                                  | Label text alignment                                                                                                                          | `"right"`           |
| labelWrap             | boolean                                                | Label change, otherwise an ellipsis appears, hover has tooltip                                                                                | false               |
| labelWidth            | `number \| string`                                     | Label fixed width                                                                                                                             | -                   |
| wrapperWidth          | `number \| string`                                     | Content fixed width                                                                                                                           | -                   |
| labelCol              | number                                                 | The number of columns occupied by the label grid, and the number of content columns add up to 24                                              | -                   |
| wrapperCol            | number                                                 | The number of columns occupied by the content grid, and the number of label columns add up to 24                                              | -                   |
| wrapperAlign          | `"left"` \| `"right"`                                  | Content text alignment                                                                                                                        | `"left"`            |
| wrapperWrap           | boolean                                                | Change the content, otherwise an ellipsis appears, and hover has tooltip                                                                      | false               |
| fullness              | boolean                                                | fullness                                                                                                                                      | false               |
| addonBefore           | ReactNode                                              | Prefix content                                                                                                                                | -                   |
| addonAfter            | ReactNode                                              | Suffix content                                                                                                                                | -                   |
| size                  | `"small"` \| `"default"` \| `"large"`                  | size                                                                                                                                          | -                   |
| inset                 | boolean                                                | Is it an inline layout                                                                                                                        | false               |
| extra                 | ReactNode                                              | Extended description script                                                                                                                   | -                   |
| feedbackText          | ReactNode                                              | Feedback Case                                                                                                                                 | -                   |
| feedbackLayout        | `"loose"` \| `"terse"` \| `"popover" \| "none"`        | Feedback layout                                                                                                                               | -                   |
| feedbackStatus        | `"error"` \| `"warning"` \| `"success"` \| `"pending"` | Feedback layout                                                                                                                               | -                   |
| feedbackIcon          | ReactNode                                              | Feedback icon                                                                                                                                 | -                   |
| enableOutlineFeedback | boolean                                                | Enable the border color style of the abnormal state, it is recommended to turn off this item when there is a sub-form in the custom component | true                |
| getPopupContainer     | function(triggerNode)                                  | when `feedbackLayout` is popover, The DOM container of the tip, the default behavior is to create a div element in body                      | () => document.body |
| asterisk              | boolean                                                | Asterisk reminder                                                                                                                             | -                   |
| gridSpan              | number                                                 | Grid layout occupies width                                                                                                                    | -                   |
| bordered              | boolean                                                | Is there a border                                                                                                                             | -                   |

### FormItem.BaseItem

Pure style components, the properties are the same as FormItem, and Formily Core does not do state bridging. It is mainly used for scenarios that need to rely on the style layout capabilities of FormItem but do not want to access the Field state.

```

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

```typescript
import { createForm } from '../'
import {
  onFieldValidateStart,
  onFieldValueChange,
  onFormInitialValuesChange,
  onFormValuesChange,
} from '../effects'
import { attach, sleep } from './shared'
import { LifeCycleTypes } from '../types'
import { observable, batch } from '@formily/reactive'

test('create form', () => {
  const form = attach(createForm())
  expect(form).not.toBeUndefined()
})

test('createField/createArrayField/createObjectField/createVoidField', () => {
  const form = attach(createForm())
  const normal = attach(
    form.createField({
      name: 'normal',
      basePath: 'parent',
    })
  )
  const normal2 = attach(
    form.createField({
      name: 'normal',
      basePath: 'parent',
    })
  )
  const array_ = attach(
    form.createArrayField({ name: 'array', basePath: 'parent' })
  )
  const array2_ = attach(
    form.createArrayField({ name: 'array', basePath: 'parent' })
  )
  const object_ = attach(
    form.createObjectField({ name: 'object', basePath: 'parent' })
  )
  const object2_ = attach(
    form.createObjectField({ name: 'object', basePath: 'parent' })
  )
  const void_ = attach(
    form.createVoidField({ name: 'void', basePath: 'parent' })
  )
  const void2_ = attach(
    form.createVoidField({ name: 'void', basePath: 'parent' })
  )
  const children_ = attach(
    form.createField({ name: 'children', basePath: 'parent.void' })
  )
  expect(normal).not.toBeUndefined()
  expect(array_).not.toBeUndefined()
  expect(object_).not.toBeUndefined()
  expect(void_).not.toBeUndefined()
  expect(normal.address.toString()).toEqual('parent.normal')
  expect(normal.path.toString()).toEqual('parent.normal')
  expect(array_.address.toString()).toEqual('parent.array')
  expect(array_.path.toString()).toEqual('parent.array')
  expect(object_.address.toString()).toEqual('parent.object')
  expect(object_.path.toString()).toEqual('parent.object')
  expect(void_.address.toString()).toEqual('parent.void')
  expect(void_.path.toString()).toEqual('parent.void')
  expect(children_.address.toString()).toEqual('parent.void.children')
  expect(children_.path.toString()).toEqual('parent.children')
  expect(form.createField({ name: '' })).toBeUndefined()
  expect(form.createArrayField({ name: '' })).toBeUndefined()
  expect(form.createObjectField({ name: '' })).toBeUndefined()
  expect(form.createVoidField({ name: '' })).toBeUndefined()
  expect(array_ === array2_).toBeTruthy()
  expect(object_ === object2_).toBeTruthy()
  expect(void_ === void2_).toBeTruthy()
  expect(normal === normal2).toBeTruthy()
})

test('setValues/setInitialValues', () => {
  const form = attach(createForm())
  form.setValues({
    aa: 123,
    cc: {
      kk: 321,
    },
  })
  const field = attach(
    form.createField({
      name: 'cc.mm',
      initialValue: 'ooo',
    })
  )
  const field2 = attach(
    form.createField({
      name: 'cc.pp',
      initialValue: 'www',
    })
  )
  expect(form.values.aa).toEqual(123)
  expect(form.values.cc.kk).toEqual(321)
  expect(form.values.cc.mm).toEqual('ooo')
  expect(form.initialValues.cc.mm).toEqual('ooo')
  expect(form.values.cc.pp).toEqual('www')
  expect(form.initialValues.cc.pp).toEqual('www')
  expect(field.value).toEqual('ooo')
  expect(field2.value).toEqual('www')
  form.setInitialValues({
    bb: '123',
    cc: {
      dd: 'xxx',
      pp: 'www2',
    },
  })
  expect(form.values.aa).toEqual(123)
  expect(form.values.bb).toEqual('123')
  expect(form.values.cc.kk).toEqual(321)
  expect(form.values.cc.dd).toEqual('xxx')
  expect(form.initialValues.bb).toEqual('123')
  expect(form.initialValues.cc.kk).toBeUndefined()
  expect(form.initialValues.cc.dd).toEqual('xxx')
  expect(form.values.cc.mm).toEqual('ooo')
  expect(form.initialValues.cc.mm).toEqual('ooo')
  expect(field.value).toEqual('ooo')
  expect(form.values.cc.pp).toEqual('www2')
  expect(form.initialValues.cc.pp).toEqual('www2')
  expect(field2.value).toEqual('www2')
  form.setInitialValues({}, 'overwrite')
  expect(form.initialValues?.cc?.pp).toBeUndefined()
  form.setValues({}, 'overwrite')
  expect(form.values.aa).toBeUndefined()
  form.setInitialValues({ aa: { bb: [{ cc: 123 }] } }, 'deepMerge')
  expect(form.values).toEqual({ aa: { bb: [{ cc: 123 }] } })
  form.setValues({ bb: { bb: [{ cc: 123 }] } }, 'deepMerge')
  expect(form.values).toEqual({
    aa: { bb: [{ cc: 123 }] },
    bb: { bb: [{ cc: 123 }] },
  })
  form.setInitialValues({ aa: [123] }, 'shallowMerge')
  expect(form.values).toEqual({
    aa: [123],
    bb: { bb: [{ cc: 123 }] },
  })
  form.setValues({ bb: [123] }, 'shallowMerge')
  expect(form.values).toEqual({
    aa: [123],
    bb: [123],
  })
})

test('no field initialValues merge', () => {
  const form = attach(
    createForm<any>({
      values: {
        aa: '123',
      },
      initialValues: {
        aa: '333',
        bb: '321',
      },
    })
  )

  expect(form.values).toEqual({
    aa: '123',
    bb: '321',
  })
})

test('setLoading', async () => {
  const form = attach(createForm())
  expect(form.loading).toBeFalsy()
  form.setLoading(true)
  await sleep(100)
  expect(form.loading).toBeTruthy()
})

test('setValues with null', () => {
  const form = attach(createForm())
  form.setInitialValues({
    'object-1': {
      'array-1': null,
    },
    'object-2': {
      'array-2': null,
    },
  })
  form.setValues({
    'object-1': {
      'array-1': null,
    },
    'object-2': {
      'array-2': null,
    },
  })
  expect(form.values).toEqual({
    'object-1': {
      'array-1': null,
    },
    'object-2': {
      'array-2': null,
    },
  })
})

test('observable values/initialValues', () => {
  const values: any = observable({
    aa: 123,
    bb: 321,
  })
  const initialValues: any = observable({
    cc: 321,
    dd: 444,
  })
  const form = attach(
    createForm({
      values,
      initialValues,
    })
  )
  batch(() => {
    values.kk = 321
  })
  expect(form.values.kk).toEqual(321)
})

test('deleteValuesIn/deleteInitialValuesIn', () => {
  const form = attach(
    createForm<{
      aa?: number
      bb?: number
    }>({
      values: {
        aa: 123,
      },
      initialValues: {
        bb: 123,
      },
    })
  )
  expect(form.values.aa).toEqual(123)
  expect(form.values.bb).toEqual(123)
  form.deleteValuesIn('aa')
  form.deleteInitialValuesIn('bb')
  expect(form.existValuesIn('aa')).toBeFalsy()
  expect(form.existInitialValuesIn('bb')).toBeFalsy()
})

test('setSubmitting/setValidating', async () => {
  const form = attach(createForm())
  form.setSubmitting(true)
  expect(form.submitting).toBeFalsy()
  await sleep()
  expect(form.submitting).toBeTruthy()
  form.setSubmitting(false)
  expect(form.submitting).toBeFalsy()
  form.setValidating(true)
  expect(form.validating).toBeFalsy()
  await sleep()
  expect(form.validating).toBeTruthy()
  form.setValidating(false)
  expect(form.validating).toBeFalsy()
})

test('setEffects/addEffects/removeEffects', () => {
  const form = attach(createForm())
  const valueChange = jest.fn()
  const valueChange2 = jest.fn()
  form.addEffects('e1', () => {
    onFieldValueChange('aa', valueChange)
  })
  const field = attach(
    form.createField({
      name: 'aa',
    })
  )
  field.setValue('123')
  expect(valueChange).toBeCalledTimes(1)
  form.removeEffects('e1')
  field.setValue('321')
  expect(valueChange).toBeCalledTimes(1)
  form.addEffects('e2', () => {
    onFieldValueChange('aa', valueChange)
  })
  field.setValue('444')
  expect(valueChange).toBeCalledTimes(2)
  form.setEffects(() => {
    onFieldValueChange('aa', valueChange2)
  })
  field.setValue('555')
  expect(valueChange).toBeCalledTimes(3)
  expect(valueChange2).toBeCalledTimes(1)
})

test('query', () => {
  const form = attach(createForm())
  attach(
    form.createObjectField({
      name: 'object',
    })
  )
  attach(
    form.createVoidField({
      name: 'void',
      basePath: 'object',
    })
  )
  attach(
    form.createField({
      name: 'normal',
      basePath: 'object.void',
    })
  )
  attach(
    form.createArrayField({
      name: 'array',
    })
  )
  expect(form.query('object').take()).not.toBeUndefined()
  expect(form.query('object.void').take()).not.toBeUndefined()
  expect(form.query('object.void.normal').take()).not.toBeUndefined()
  expect(form.query('object.normal').take()).not.toBeUndefined()
  expect(form.query('object.*').map((field) => field.path.toString())).toEqual([
    'object.void',
    'object.normal',
  ])
  expect(form.query('*').map((field) => field.path.toString())).toEqual([
    'object',
    'object.void',
    'object.normal',
    'array',
  ])
  expect(form.query('array').take()).not.toBeUndefined()
  expect(form.query('*').take()).not.toBeUndefined()
  expect(form.query('*(oo)').take()).toBeUndefined()
  expect(form.query('*(oo)').map()).toEqual([])
  expect(form.query('object.void').get('value')).toBeUndefined()
  expect(form.query('object.void').get('initialValue')).toBeUndefined()
  expect(form.query('object.void').get('inputValue')).toBeUndefined()
  expect(form.query('array').get('value')).toEqual([])
  expect(form.query('array').get('initialValue')).toBeUndefined()
  expect(form.query('array').get('inputValue')).toBeNull()
  form.setFieldState('array', (state) => {
    state.value = [111]
    state.initialValue = [111]
    state.inputValue = [111]
  })
  expect(form.query('array').get('value')).toEqual([111])
  expect(form.query('array').get('initialValue')).toEqual([111])
  expect(form.query('array').get('inputValue')).toEqual([111])
  expect(form.query('array').getIn('inputValue')).toEqual([111])
  expect(form.query('opo').get('value')).toBeUndefined()
  expect(form.query('opo').getIn('value')).toBeUndefined()
  expect(form.query('opo').get('initialValue')).toBeUndefined()
  expect(form.query('opo').get('inputValue')).toBeUndefined()
})

test('notify/subscribe/unsubscribe', () => {
  const form = attach(createForm())
  const subscribe = jest.fn()
  const id = form.subscribe(subscribe)
  expect(subscribe).toBeCalledTimes(0)
  form.setInitialValues({ aa: 123 })
  expect(subscribe).toBeCalledTimes(2)
  expect(form.values).toEqual({ aa: 123 })
  form.notify(LifeCycleTypes.ON_FORM_SUBMIT)
  expect(subscribe).toBeCalledTimes(3)
  form.unsubscribe(id)
  form.notify(LifeCycleTypes.ON_FORM_SUBMIT)
  expect(subscribe).toBeCalledTimes(3)
})

test('setState/getState/setFormState/getFormState/setFieldState/getFieldState', () => {
  const form = attach(createForm())
  const state = form.getState()
  form.setState((state) => {
    state.pattern = 'disabled'
    state.values = { aa: 123 }
  })
  expect(form.pattern).toEqual('disabled')
  expect(form.disabled).toBeTruthy()
  expect(form.values.aa).toEqual(123)
  form.setState(state)
  expect(form.pattern).toEqual('editable')
  expect(form.disabled).toBeFalsy()
  expect(form.values.aa).toBeUndefined()
  form.setFormState((state) => {
    state.pattern = 'readOnly'
    state.values = { bb: 321 }
  })
  expect(form.pattern).toEqual('readOnly')
  expect(form.disabled).toBeFalsy()
  expect(form.readOnly).toBeTruthy()
  expect(form.values.aa).toBeUndefined()
  expect(form.values.bb).toEqual(321)
  form.setFormState(state)
  expect(form.pattern).toEqual('editable')
  expect(form.disabled).toBeFalsy()
  expect(form.readOnly).toBeFalsy()
  expect(form.values.aa).toBeUndefined()
  expect(form.values.bb).toBeUndefined()
  attach(
    form.createField({
      name: 'aa',
    })
  )
  const fieldState = form.getFieldState('aa')
  form.setFieldState('aa', (state) => {
    state.title = 'AA'
    state.description = 'This is AA'
    state.value = '123'
  })
  expect(form.getFieldState('aa', (state) => state.title)).toEqual('AA')
  expect(form.getFieldState('aa', (state) => state.description)).toEqual(
    'This is AA'
  )
  expect(form.getFieldState('aa', (state) => state.value)).toEqual('123')
  form.setFieldState('aa', fieldState)
  expect(form.getFieldState('aa', (state) => state.title)).toBeUndefined()
  expect(form.getFieldState('aa', (state) => state.description)).toBeUndefined()
  expect(form.getFieldState('aa', (state) => state.value)).toBeUndefined()
  form.setState((state) => {
    state.display = 'none'
  })
  expect(form.getFieldState('aa', (state) => state.visible)).toBeFalsy()
  const update = (value: any) => (state: any) => {
    state.value = value
  }
  const update2 = (state: any) => {
    state.value = 123
  }
  form.setFieldState('kk', update(123))
  form.setFieldState('kk', update(321))
  form.setFieldState('oo', update2)
  form.setFieldState('oo', update2)
  const oo = attach(
    form.createField({
      name: 'oo',
    })
  )
  const kk = attach(
    form.createField({
      name: 'kk',
    })
  )
  expect(oo.value).toBeUndefined()
  expect(kk.value).toBeUndefined()
})

test('validate/valid/invalid/errors/warnings/successes/clearErrors/clearWarnings/clearSuccesses/queryFeedbacks', async () => {
  const form = attach(createForm())
  const aa = attach(
    form.createField({
      name: 'aa',
      required: true,
      validator(value) {
        if (value == '123') {
          return {
            type: 'success',
            message: 'success',
          }
        } else if (value == '321') {
          return {
            type: 'warning',
            message: 'warning',
          }
        } else if (value == '111') {
          return 'error'
        }
      },
    })
  )
  const bb = attach(
    form.createField({
      name: 'bb',
      required: true,
    })
  )
  attach(
    form.createVoidField({
      name: 'cc',
    })
  )
  try {
    await form.validate()
  } catch {}
  expect(form.invalid).toBeTruthy()
  expect(form.valid).toBeFalsy()
  expect(form.errors).toEqual([
    {
      type: 'error',
      address: 'aa',
      path: 'aa',
      code: 'ValidateError',
      triggerType: 'onInput',
      messages: ['The field value is required'],
    },
    {
      type: 'error',
      address: 'bb',
      path: 'bb',
      code: 'ValidateError',
      triggerType: 'onInput',
      messages: ['The field value is required'],
    },
  ])
  await aa.onInput('123')
  expect(form.errors).toEqual([
    {
      type: 'error',
      address: 'bb',
      path: 'bb',
      code: 'ValidateError',
      triggerType: 'onInput',
      messages: ['The field value is required'],
    },
  ])
  expect(form.successes).toEqual([
    {
      type: 'success',
      address: 'aa',
      path: 'aa',
      code: 'ValidateSuccess',
      triggerType: 'onInput',
      messages: ['success'],
    },
  ])
  await aa.onInput('321')
  expect(form.errors).toEqual([
    {
      type: 'error',
      address: 'bb',
      path: 'bb',
      code: 'ValidateError',
      triggerType: 'onInput',
      messages: ['The field value is required'],
    },
  ])
  expect(form.warnings).toEqual([
    {
      type: 'warning',
      address: 'aa',
      path: 'aa',
      code: 'ValidateWarning',
      triggerType: 'onInput',
      messages: ['warning'],
    },
  ])
  await aa.onInput('111')
  expect(form.errors).toEqual([
    {
      type: 'error',
      address: 'aa',
      path: 'aa',
      code: 'ValidateError',
      triggerType: 'onInput',
      messages: ['error'],
    },
    {
      type: 'error',
      address: 'bb',
      path: 'bb',
      code: 'ValidateError',
      triggerType: 'onInput',
      messages: ['The field value is required'],
    },
  ])
  await aa.onInput('yes')
  await bb.onInput('yes')
  await form.validate()
  expect(form.invalid).toBeFalsy()
  expect(form.valid).toBeTruthy()
  expect(form.errors).toEqual([])
  expect(form.successes).toEqual([])
  expect(form.warnings).toEqual([])
  await aa.onInput('')
  await bb.onInput('')
  try {
    await form.validate()
  } catch {}
  expect(form.errors).toEqual([
    {
      type: 'error',
      address: 'aa',
      path: 'aa',
      code: 'ValidateError',
      triggerType: 'onInput',
      messages: ['The field value is required'],
    },
    {
      type: 'error',
      address: 'bb',
      path: 'bb',
      code: 'ValidateError',
      triggerType: 'onInput',
      messages: ['The field value is required'],
    },
  ])
  form.clearErrors('aa')
  expect(form.errors).toEqual([
    {
      type: 'error',
      address: 'bb',
      path: 'bb',
      code: 'ValidateError',
      triggerType: 'onInput',
      messages: ['The field value is required'],
    },
  ])
  form.clearErrors('*')
  expect(form.errors).toEqual([])
  await aa.onInput('123')
  expect(form.errors).toEqual([])
  expect(form.successes).toEqual([
    {
      type: 'success',
      address: 'aa',
      path: 'aa',
      code: 'ValidateSuccess',
      triggerType: 'onInput',
      messages: ['success'],
    },
  ])
  form.clearSuccesses('aa')
  expect(form.successes).toEqual([])
  await aa.onInput('321')
  expect(form.errors).toEqual([])
  expect(form.successes).toEqual([])
  expect(form.warnings).toEqual([
    {
      type: 'warning',
      address: 'aa',
      path: 'aa',
      code: 'ValidateWarning',
      triggerType: 'onInput',
      messages: ['warning'],
    },
  ])
  form.clearWarnings('*')
  expect(form.errors).toEqual([])
  expect(form.successes).toEqual([])
  expect(form.warnings).toEqual([])
  await aa.onInput('123')
  await bb.onInput('')
  expect(
    form.queryFeedbacks({
      type: 'error',
    }).length
  ).toEqual(1)
  expect(
    form.queryFeedbacks({
      type: 'success',
    }).length
  ).toEqual(1)
  expect(
    form.queryFeedbacks({
      code: 'ValidateError',
    }).length
  ).toEqual(1)
  expect(
    form.queryFeedbacks({
      code: 'ValidateSuccess',
    }).length
  ).toEqual(1)
  expect(
    form.queryFeedbacks({
      code: 'EffectError',
    }).length
  ).toEqual(0)
  expect(
    form.queryFeedbacks({
      code: 'EffectSuccess',
    }).length
  ).toEqual(0)
  expect(
    form.queryFeedbacks({
      path: 'aa',
    }).length
  ).toEqual(1)
  expect(
    form.queryFeedbacks({
      path: 'bb',
    }).length
  ).toEqual(1)
  expect(
    form.queryFeedbacks({
      address: 'aa',
    }).length
  ).toEqual(1)
  expect(
    form.queryFeedbacks({
      address: 'bb',
    }).length
  ).toEqual(1)
  aa.setValue('')
  bb.setValue('')
  form.clearErrors()
  form.clearSuccesses()
  form.clearWarnings()
  try {
    await form.validate('aa')
  } catch {}
  expect(
    form.queryFeedbacks({
      type: 'error',
    }).length
  ).toEqual(1)
  try {
    await form.validate('*')
  } catch {}
  expect(
    form.queryFeedbacks({
      type: 'error',
    }).length
  ).toEqual(2)
})

test('setPattern/pattern/editable/readOnly/disabled/readPretty', () => {
  const form = attach(
    createForm({
      pattern: 'disabled',
    })
  )
  const field = attach(
    form.createField({
      name: 'aa',
    })
  )
  expect(form.pattern).toEqual('disabled')
  expect(form.disabled).toBeTruthy()
  expect(field.pattern).toEqual('disabled')
  expect(field.disabled).toBeTruthy()
  form.setPattern('readOnly')
  expect(form.pattern).toEqual('readOnly')
  expect(form.readOnly).toBeTruthy()
  expect(field.pattern).toEqual('readOnly')
  expect(field.readOnly).toBeTruthy()
  form.setPattern('readPretty')
  expect(form.pattern).toEqual('readPretty')
  expect(form.readPretty).toBeTruthy()
  expect(field.pattern).toEqual('readPretty')
  expect(field.readPretty).toBeTruthy()
  const form2 = attach(
    createForm({
      editable: false,
    })
  )
  expect(form2.pattern).toEqual('readPretty')
  expect(form2.readPretty).toBeTruthy()
  const form3 = attach(
    createForm({
      disabled: true,
    })
  )
  expect(form3.pattern).toEqual('disabled')
  expect(form3.disabled).toBeTruthy()
  const form4 = attach(
    createForm({
      readOnly: true,
    })
  )
  expect(form4.pattern).toEqual('readOnly')
  expect(form4.readOnly).toBeTruthy()
  const form5 = attach(
    createForm({
      readPretty: true,
    })
  )
  expect(form5.pattern).toEqual('readPretty')
  expect(form5.readPretty).toBeTruthy()
})

test('setDisplay/display/visible/hidden', () => {
  const form = attach(
    createForm({
      display: 'hidden',
    })
  )
  const field = attach(
    form.createField({
      name: 'aa',
    })
  )
  expect(form.display).toEqual('hidden')
  expect(form.hidden).toBeTruthy()
  expect(field.display).toEqual('hidden')
  expect(field.hidden).toBeTruthy()
  form.setDisplay('visible')
  expect(form.display).toEqual('visible')
  expect(form.visible).toBeTruthy()
  expect(field.display).toEqual('visible')
  expect(field.visible).toBeTruthy()
  form.setDisplay('none')
  expect(form.display).toEqual('none')
  expect(form.visible).toBeFalsy()
  expect(field.display).toEqual('none')
  expect(field.visible).toBeFalsy()
  const form2 = attach(
    createForm({
      hidden: true,
    })
  )
  expect(form2.display).toEqual('hidden')
  expect(form2.hidden).toBeTruthy()
  expect(form2.visible).toBeFalsy()
  const form3 = attach(
    createForm({
      visible: false,
    })
  )
  expect(form3.display).toEqual('none')
  expect(form3.visible).toBeFalsy()
})

test('submit', async () => {
  const form = attach(createForm())
  const onSubmit = jest.fn()
  const field = attach(
    form.createField({
      name: 'aa',
      required: true,
    })
  )
  let errors1: Error
  try {
    await form.submit(onSubmit)
  } catch (e) {
    errors1 = e
  }
  expect(errors1).not.toBeUndefined()
  expect(onSubmit).toBeCalledTimes(0)
  field.onInput('123')
  await form.submit(onSubmit)
  expect(onSubmit).toBeCalledTimes(1)
  let errors2: Error
  try {
    await form.submit(() => {
      throw new Error('xxx')
    })
  } catch (e) {
    errors2 = e
  }
  expect(errors2).not.toBeUndefined()
  expect(form.valid).toBeTruthy()
})

test('reset', async () => {
  const form = attach(
    createForm<{
      aa?: number
      bb?: number
    }>({
      values: {
        bb: 123,
      },
      initialValues: {
        aa: 123,
      },
    })
  )
  const field = attach(
    form.createField({
      name: 'aa',
      required: true,
    })
  )
  const field2 = attach(
    form.createField({
      name: 'bb',
      required: true,
    })
  )
  attach(
    form.createVoidField({
      name: 'cc',
    })
  )
  expect(field.value).toEqual(123)
  expect(field2.value).toEqual(123)
  expect(form.values.aa).toEqual(123)
  expect(form.values.bb).toEqual(123)
  field.onInput('xxxxx')
  expect(form.values.aa).toEqual('xxxxx')
  try {
    await form.reset()
  } catch {}
  expect(form.valid).toBeTruthy()
  expect(form.values.aa).toEqual(123)
  expect(field.value).toEqual(123)
  expect(form.values.bb).toBeUndefined()
  expect(field2.value).toBeUndefined()
  field.onInput('aaa')
  field2.onInput('bbb')
  expect(form.valid).toBeTruthy()
  expect(form.values.aa).toEqual('aaa')
  expect(field.value).toEqual('aaa')
  expect(form.values.bb).toEqual('bbb')
  expect(field2.value).toEqual('bbb')
  try {
    await form.reset('*', {
      validate: true,
    })
  } catch {}
  expect(form.valid).toBeFalsy()
  expect(form.values.aa).toEqual(123)
  expect(field.value).toEqual(123)
  expect(form.values.bb).toBeUndefined()
  expect(field2.value).toBeUndefined()
  field.onInput('aaa')
  field2.onInput('bbb')
  try {
    await form.reset('*', {
      forceClear: true,
    })
  } catch {}
  expect(form.valid).toBeTruthy()
  expect(form.values.aa).toBeUndefined()
  expect(field.value).toBeUndefined()
  expect(form.values.bb).toBeUndefined()
  expect(field2.value).toBeUndefined()
  field.onInput('aaa')
  field2.onInput('bbb')
  try {
    await form.reset('aa', {
      forceClear: true,
    })
  } catch {}
  expect(form.valid).toBeTruthy()
  expect(form.values.aa).toBeUndefined()
  expect(field.value).toBeUndefined()
  expect(form.values.bb).toEqual('bbb')
  expect(field2.value).toEqual('bbb')
})

test('devtools', () => {
  // @ts-ignore
  window['__FORMILY_DEV_TOOLS_HOOK__'] = {
    inject() {},
    unmount() {},
  }
  const form = attach(createForm())
  form.onUnmount()
})

test('reset array field', async () => {
  const form = attach(
    createForm({
      values: {
        array: [{ value: 123 }],
      },
    })
  )
  attach(
    form.createArrayField({
      name: 'array',
      required: true,
    })
  )
  expect(form.values).toEqual({
    array: [{ value: 123 }],
  })
  await form.reset('*', {
    forceClear: true,
  })
  expect(form.values).toEqual({
    array: [],
  })
})

test('reset object field', async () => {
  const form = attach(
    createForm({
      values: {
        object: { value: 123 },
      },
    })
  )
  attach(
    form.createObjectField({
      name: 'object',
      required: true,
    })
  )
  expect(form.values).toEqual({
    object: { value: 123 },
  })
  await form.reset('*', {
    forceClear: true,
  })
  expect(form.values).toEqual({
    object: {},
  })
})

test('initialValues merge values before create field', () => {
  const form = attach(createForm())
  const array = attach(
    form.createArrayField({
      name: 'array',
    })
  )
  form.values.array = [{ aa: '321' }]
  const arr_0_aa = attach(
    form.createField({
      name: 'aa',
      basePath: 'array.0',
      initialValue: '123',
    })
  )
  expect(array.value).toEqual([{ aa: '321' }])
  expect(arr_0_aa.value).toEqual('321')
})

test('no patch with empty initialValues', () => {
  const form = attach(
    createForm({
      values: {
        array: [1, 2, 3],
      },
    })
  )
  attach(
    form.createObjectField({
      name: 'array.0.1',
    })
  )

  expect(form.values).toEqual({
    array: [1, 2, 3],
  })
})

test('initialValues merge values after create field', () => {
  const form = attach(createForm())
  const aa = attach(
    form.createArrayField({
      name: 'aa',
      initialValue: '111',
    })
  )
  const array = attach(
    form.createArrayField({
      name: 'array',
    })
  )
  const arr_0_aa = attach(
    form.createField({
      name: 'aa',
      basePath: 'array.0',
      initialValue: '123',
    })
  )
  form.values.aa = '222'
  form.values.array = [{ aa: '321' }]
  expect(array.value).toEqual([{ aa: '321' }])
  expect(arr_0_aa.value).toEqual('321')
  expect(aa.value).toEqual('222')
})

test('remove property of form values with undefined value', () => {
  const form = attach(createForm())
  const field = attach(
    form.createField({
      name: 'aaa',
      initialValue: 123,
    })
  )
  expect(form.values).toMatchObject({ aaa: 123 })
  field.display = 'none'
  expect(form.values.hasOwnProperty('aaa')).toBeFalsy()
  field.display = 'visible'
  expect(form.values.hasOwnProperty('aaa')).toBeTruthy()
  field.setValue(undefined)
  expect(form.values.hasOwnProperty('aaa')).toBeTruthy()
})

test('empty array initialValues', () => {
  const form = attach(
    createForm({
      initialValues: {
        aa: [0],
        bb: [''],
        cc: [],
        dd: [null],
        ee: [undefined],
      },
    })
  )
  form.createArrayField({
    name: 'aa',
  })
  form.createArrayField({
    name: 'bb',
  })
  form.createArrayField({
    name: 'cc',
  })
  form.createArrayField({
    name: 'dd',
  })
  form.createArrayField({
    name: 'ee',
  })
  expect(form.values.aa).toEqual([0])
  expect(form.values.bb).toEqual([''])
  expect(form.values.cc).toEqual([])
  expect(form.values.dd).toEqual([null])
  expect(form.values.ee).toEqual([undefined])
})

test('form lifecycle can be triggered after call form.setXXX', () => {
  let initialValuesTriggerNum = 0
  let valuesTriggerNum = 0

  const form = attach(
    createForm<{
      aa?: number
      bb?: number
    }>({
      initialValues: {
        aa: 1,
      },
      values: {
        bb: 1,
      },
    })
  )

  form.setEffects(() => {
    onFormInitialValuesChange(() => {
      initialValuesTriggerNum++
    })

    onFormValuesChange(() => {
      valuesTriggerNum++
    })
  })

  expect(initialValuesTriggerNum).toEqual(0)
  expect(valuesTriggerNum).toEqual(0)

  form.initialValues.aa = 2
  form.values.bb = 2

  expect(initialValuesTriggerNum).toEqual(1)
  // initialValues 会通过 applyValuesPatch 改变 values,导致 onFormValuesChange 多触发一次
  expect(valuesTriggerNum).toEqual(2)

  form.setInitialValues({ aa: 3 })
  form.setValues({ bb: 3 })

  expect(initialValuesTriggerNum).toEqual(2)
  expect(valuesTriggerNum).toEqual(4)

  // 测试 form.setXXX 之后还能正常触发:https://github.com/alibaba/formily/issues/1675
  form.initialValues.aa = 4
  form.values.bb = 4

  expect(initialValuesTriggerNum).toEqual(3)
  expect(valuesTriggerNum).toEqual(6)
})

test('form values change with array field(default value)', async () => {
  const handler = jest.fn()
  const form = attach(
    createForm({
      effects() {
        onFormValuesChange(handler)
      },
    })
  )
  const array = attach(
    form.createArrayField({
      name: 'array',
      initialValue: [
        {
          hello: 'world',
        },
      ],
    })
  )
  await array.push({})
  expect(handler).toBeCalledTimes(2)
})

test('setValues deep merge', () => {
  const form = attach(
    createForm({
      initialValues: {
        aa: {
          bb: 123,
          cc: 321,
          dd: [11, 22, 33],
        },
      },
    })
  )
  expect(form.values).toEqual({
    aa: {
      bb: 123,
      cc: 321,
      dd: [11, 22, 33],
    },
  })
  form.setValues({
    aa: {
      bb: '',
      cc: '',
      dd: [44, 55, 66],
    },
  })
  expect(form.values).toEqual({
    aa: {
      bb: '',
      cc: '',
      dd: [44, 55, 66],
    },
  })
})

test('exception validate', async () => {
  const form = attach(createForm())
  attach(
    form.createField({
      name: 'aa',
      validator() {
        throw new Error('runtime error')
      },
    })
  )
  try {
    await form.validate()
  } catch {}
  expect(form.invalid).toBeTruthy()
  expect(form.validating).toBeFalsy()
})

test('designable form', () => {
  const form = attach(
    createForm({
      designable: true,
    })
  )
  attach(
    form.createField({
      name: 'bb',
      initialValue: 123,
    })
  )
  attach(
    form.createField({
      name: 'bb',
      initialValue: 321,
    })
  )
  attach(
    form.createField({
      name: 'aa',
      value: 123,
    })
  )
  attach(
    form.createField({
      name: 'aa',
      value: 321,
    })
  )
  expect(form.values.aa).toEqual(321)
  expect(form.initialValues.bb).toEqual(321)
})

test('validate will skip display none', async () => {
  const validateA = jest.fn()
  const validateB = jest.fn()
  const form = attach(
    createForm({
      effects() {
        onFieldValidateStart('aa', validateA)
        onFieldValidateStart('bb', validateB)
      },
    })
  )
  const validator = jest.fn()
  const aa = attach(
    form.createField({
      name: 'aa',
      validator() {
        validator()
        return 'error'
      },
    })
  )
  const bb = attach(
    form.createField({
      name: 'bb',
      validator() {
        validator()
        return 'error'
      },
    })
  )
  try {
    await form.validate()
  } catch (e) {
    expect(e).toEqual([
      {
        triggerType: 'onInput',
        type: 'error',
        code: 'ValidateError',
        messages: ['error'],
        address: 'aa',
        path: 'aa',
      },
      {
        triggerType: 'onInput',
        type: 'error',
        code: 'ValidateError',
        messages: ['error'],
        address: 'bb',
        path: 'bb',
      },
    ])
  }
  expect(validateA).toBeCalledTimes(1)
  expect(validateB).toBeCalledTimes(1)
  expect(aa.invalid).toBeTruthy()
  expect(bb.invalid).toBeTruthy()
  expect(validator).toBeCalledTimes(2)
  aa.display = 'none'
  try {
    await form.validate()
  } catch (e) {
    expect(e).toEqual([
      {
        triggerType: 'onInput',
        type: 'error',
        code: 'ValidateError',
        messages: ['error'],
        address: 'bb',
        path: 'bb',
      },
    ])
  }
  expect(validateA).toBeCalledTimes(1)
  expect(validateB).toBeCalledTimes(2)
  expect(aa.invalid).toBeFalsy()
  expect(bb.invalid).toBeTruthy()
  expect(validator).toBeCalledTimes(3)
  bb.display = 'none'
  await form.validate()
  expect(validateA).toBeCalledTimes(1)
  expect(validateB).toBeCalledTimes(2)
  expect(aa.invalid).toBeFalsy()
  expect(bb.invalid).toBeFalsy()
  expect(validator).toBeCalledTimes(3)
})

test('validate will skip unmounted', async () => {
  const validateA = jest.fn()
  const validateB = jest.fn()
  const form = attach(
    createForm({
      effects() {
        onFieldValidateStart('aa', validateA)
        onFieldValidateStart('bb', validateB)
      },
    })
  )
  const validator = jest.fn()
  const aa = attach(
    form.createField({
      name: 'aa',
      validator() {
        validator()
        return 'error'
      },
    })
  )
  const bb = attach(
    form.createField({
      name: 'bb',
      validator() {
        validator()
        return 'error'
      },
    })
  )
  try {
    await form.validate()
  } catch (e) {
    expect(e).toEqual([
      {
        triggerType: 'onInput',
        type: 'error',
        code: 'ValidateError',
        messages: ['error'],
        address: 'aa',
        path: 'aa',
      },
      {
        triggerType: 'onInput',
        type: 'error',
        code: 'ValidateError',
        messages: ['error'],
        address: 'bb',
        path: 'bb',
      },
    ])
  }
  expect(validateA).toBeCalledTimes(1)
  expect(validateB).toBeCalledTimes(1)
  expect(aa.invalid).toBeTruthy()
  expect(bb.invalid).toBeTruthy()
  expect(validator).toBeCalledTimes(2)
  aa.onUnmount()
  try {
    await form.validate()
  } catch (e) {
    expect(e).toEqual([
      {
        triggerType: 'onInput',
        type: 'error',
        code: 'ValidateError',
        messages: ['error'],
        address: 'aa',
        path: 'aa',
      },
      {
        triggerType: 'onInput',
        type: 'error',
        code: 'ValidateError',
        messages: ['error'],
        address: 'bb',
        path: 'bb',
      },
    ])
  }
  expect(validateA).toBeCalledTimes(2)
  expect(validateB).toBeCalledTimes(2)
  expect(aa.invalid).toBeTruthy()
  expect(bb.invalid).toBeTruthy()
  expect(validator).toBeCalledTimes(4)
  form.clearFormGraph('*(aa,bb)')
  await form.validate()
  expect(validateA).toBeCalledTimes(2)
  expect(validateB).toBeCalledTimes(2)
  expect(aa.invalid).toBeFalsy()
  expect(bb.invalid).toBeFalsy()
  expect(validator).toBeCalledTimes(4)
})

test('validate will skip uneditable', async () => {
  const validateA = jest.fn()
  const validateB = jest.fn()
  const form = attach(
    createForm({
      effects() {
        onFieldValidateStart('aa', validateA)
        onFieldValidateStart('bb', validateB)
      },
    })
  )
  const validator = jest.fn()
  const aa = attach(
    form.createField({
      name: 'aa',
      validator() {
        validator()
        return 'error'
      },
    })
  )
  const bb = attach(
    form.createField({
      name: 'bb',
      validator() {
        validator()
        return 'error'
      },
    })
  )
  try {
    await form.validate()
  } catch (e) {
    expect(e).toEqual([
      {
        triggerType: 'onInput',
        type: 'error',
        code: 'ValidateError',
        messages: ['error'],
        address: 'aa',
        path: 'aa',
      },
      {
        triggerType: 'onInput',
        type: 'error',
        code: 'ValidateError',
        messages: ['error'],
        address: 'bb',
        path: 'bb',
      },
    ])
  }
  expect(validateA).toBeCalledTimes(1)
  expect(validateB).toBeCalledTimes(1)
  expect(aa.invalid).toBeTruthy()
  expect(bb.invalid).toBeTruthy()
  expect(validator).toBeCalledTimes(2)
  aa.editable = false
  try {
    await form.validate()
  } catch (e) {
    expect(e).toEqual([
      {
        triggerType: 'onInput',
        type: 'error',
        code: 'ValidateError',
        messages: ['error'],
        address: 'bb',
        path: 'bb',
      },
    ])
  }
  expect(validateA).toBeCalledTimes(1)
  expect(validateB).toBeCalledTimes(2)
  expect(aa.invalid).toBeFalsy()
  expect(bb.invalid).toBeTruthy()
  expect(validator).toBeCalledTimes(3)
  bb.editable = false
  await form.validate()
  expect(validateA).toBeCalledTimes(1)
  expect(validateB).toBeCalledTimes(2)
  expect(aa.invalid).toBeFalsy()
  expect(bb.invalid).toBeFalsy()
  expect(validator).toBeCalledTimes(3)
})

test('validator order with format', async () => {
  const form = attach(createForm())

  attach(
    form.createField({
      name: 'aa',
      required: true,
      validator: {
        format: 'url',
        message: 'custom',
      },
    })
  )

  attach(
    form.createField({
      name: 'bb',
      required: true,
      validator: (value) => {
        if (!value) return ''
        return value !== '111' ? 'custom' : ''
      },
    })
  )
  const results = await form.submit<any[]>(() => {}).catch((e) => e)
  expect(results.map(({ messages }) => messages)).toEqual([
    ['The field value is required'],
    ['The field value is required'],
  ])
})

test('form unmount can not effect field values', () => {
  const form = attach(
    createForm({
      values: {
        aa: '123',
      },
    })
  )
  attach(
    form.createField({
      name: 'aa',
    })
  )
  expect(form.values.aa).toEqual('123')
  form.onUnmount()
  expect(form.values.aa).toEqual('123')
})

test('form clearFormGraph need clear field values', () => {
  const form = attach(
    createForm({
      values: {
        aa: '123',
      },
    })
  )
  attach(
    form.createField({
      name: 'aa',
    })
  )
  expect(form.values.aa).toEqual('123')
  form.clearFormGraph('*')
  expect(form.values.aa).toBeUndefined()
})

test('form clearFormGraph not clear field values', () => {
  const form = attach(
    createForm({
      values: {
        aa: '123',
      },
    })
  )
  attach(
    form.createField({
      name: 'aa',
    })
  )
  expect(form.values.aa).toEqual('123')
  form.clearFormGraph('*', false)
  expect(form.values.aa).toEqual('123')
})

test('form values auto clean with visible false', () => {
  const form = attach(
    createForm({
      initialValues: {
        aa: '123',
        bb: '321',
        cc: 'cc',
      },
    })
  )
  attach(
    form.createField({
      name: 'aa',
    })
  )
  attach(
    form.createField({
      name: 'bb',
      reactions: (field) => {
        field.visible = form.values.aa === '1233'
      },
    })
  )
  attach(
    form.createField({
      name: 'cc',
    })
  )

  expect(form.values).toEqual({
    aa: '123',
    cc: 'cc',
  })
})

test('form values auto clean with visible false in async setInitialValues', () => {
  const form = attach(createForm())
  attach(
    form.createField({
      name: 'aa',
    })
  )
  attach(
    form.createField({
      name: 'bb',
      reactions: (field) => {
        field.visible = form.values.aa === '1233'
      },
    })
  )
  attach(
    form.createField({
      name: 'cc',
    })
  )

  form.setInitialValues({
    aa: '123',
    bb: '321',
    cc: 'cc',
  })

  expect(form.values).toEqual({
    aa: '123',
    cc: 'cc',
  })
})

test('form values ref should not changed with setValues', () => {
  const form = attach(
    createForm({
      values: {
        aa: '123',
      },
    })
  )
  const values = form.values
  form.setValues({
    bb: '321',
  })
  expect(form.values === values).toBeTruthy()
})

test('form initial values ref should not changed with setInitialValues', () => {
  const form = attach(
    createForm({
      initialValues: {
        aa: '123',
      },
    })
  )
  const values = form.initialValues
  form.setInitialValues({
    bb: '321',
  })
  expect(form.initialValues === values).toBeTruthy()
})

test('form query undefined query should not throw error', () => {
  const form = attach(createForm())

  ;(form.fields as any)['a'] = undefined
  expect(() => form.query('*').take()).not.toThrowError()
  expect(Object.keys(form.fields)).toEqual([])
})

```
Page 30/35FirstPrevNextLast