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

# Directory Structure

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

# Files

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

```typescript
   1 | import { autorun, batch, observable } from '@formily/reactive'
   2 | import { createForm, onFieldReact, isField } from '../'
   3 | import { DataField } from '../types'
   4 | import { attach, sleep } from './shared'
   5 | 
   6 | test('create field', () => {
   7 |   const form = attach(createForm())
   8 |   const field = attach(
   9 |     form.createField({
  10 |       name: 'normal',
  11 |     })
  12 |   )
  13 |   expect(field).not.toBeUndefined()
  14 | })
  15 | 
  16 | test('create field props', () => {
  17 |   const form = attach(createForm())
  18 |   const field1 = attach(
  19 |     form.createField({
  20 |       name: 'field1',
  21 |       title: 'Field 1',
  22 |       description: 'This is Field 1',
  23 |       required: true,
  24 |     })
  25 |   )
  26 |   expect(field1.title).toEqual('Field 1')
  27 |   expect(field1.description).toEqual('This is Field 1')
  28 |   expect(field1.required).toBeTruthy()
  29 |   expect(field1.validator).not.toBeUndefined()
  30 |   const field2 = attach(
  31 |     form.createField({
  32 |       name: 'field2',
  33 |       disabled: true,
  34 |       hidden: true,
  35 |     })
  36 |   )
  37 |   expect(field2.pattern).toEqual('disabled')
  38 |   expect(field2.disabled).toBeTruthy()
  39 |   expect(field2.display).toEqual('hidden')
  40 |   expect(field2.hidden).toBeTruthy()
  41 |   const field3 = attach(
  42 |     form.createField({
  43 |       name: 'field3',
  44 |       readOnly: true,
  45 |       visible: false,
  46 |     })
  47 |   )
  48 |   expect(field3.pattern).toEqual('readOnly')
  49 |   expect(field3.readOnly).toBeTruthy()
  50 |   expect(field3.display).toEqual('none')
  51 |   expect(field3.visible).toBeFalsy()
  52 |   const field4 = attach(
  53 |     form.createField({
  54 |       name: 'field4',
  55 |       value: 123,
  56 |     })
  57 |   )
  58 |   expect(field4.value).toEqual(123)
  59 |   expect(field4.initialValue).toBeUndefined()
  60 |   const field5 = attach(
  61 |     form.createField({
  62 |       name: 'field5',
  63 |       initialValue: 123,
  64 |     })
  65 |   )
  66 |   expect(field5.value).toEqual(123)
  67 |   expect(field5.initialValue).toEqual(123)
  68 | })
  69 | 
  70 | test('field display and value', () => {
  71 |   const form = attach(createForm())
  72 |   const objectField = attach(
  73 |     form.createObjectField({
  74 |       name: 'object',
  75 |     })
  76 |   )
  77 |   const arrayField = attach(
  78 |     form.createArrayField({
  79 |       name: 'array',
  80 |     })
  81 |   )
  82 |   const valueField = attach(
  83 |     form.createField({
  84 |       name: 'value',
  85 |     })
  86 |   )
  87 |   expect(objectField.value).toEqual({})
  88 |   expect(arrayField.value).toEqual([])
  89 |   expect(valueField.value).toBeUndefined()
  90 | 
  91 |   objectField.hidden = true
  92 |   arrayField.hidden = true
  93 |   valueField.hidden = true
  94 |   expect(objectField.value).toEqual({})
  95 |   expect(arrayField.value).toEqual([])
  96 |   expect(valueField.value).toBeUndefined()
  97 | 
  98 |   objectField.hidden = false
  99 |   arrayField.hidden = false
 100 |   valueField.hidden = false
 101 |   expect(objectField.value).toEqual({})
 102 |   expect(arrayField.value).toEqual([])
 103 |   expect(valueField.value).toBeUndefined()
 104 | 
 105 |   objectField.visible = false
 106 |   arrayField.visible = false
 107 |   valueField.visible = false
 108 |   expect(objectField.value).toBeUndefined()
 109 |   expect(arrayField.value).toBeUndefined()
 110 |   expect(valueField.value).toBeUndefined()
 111 | 
 112 |   objectField.visible = true
 113 |   arrayField.visible = true
 114 |   valueField.visible = true
 115 |   expect(objectField.value).toEqual({})
 116 |   expect(arrayField.value).toEqual([])
 117 |   expect(valueField.value).toBeUndefined()
 118 | 
 119 |   objectField.value = { value: '123' }
 120 |   arrayField.value = ['123']
 121 |   valueField.value = '123'
 122 |   expect(objectField.value).toEqual({ value: '123' })
 123 |   expect(arrayField.value).toEqual(['123'])
 124 |   expect(valueField.value).toEqual('123')
 125 | 
 126 |   objectField.hidden = true
 127 |   arrayField.hidden = true
 128 |   valueField.hidden = true
 129 |   expect(objectField.value).toEqual({ value: '123' })
 130 |   expect(arrayField.value).toEqual(['123'])
 131 |   expect(valueField.value).toEqual('123')
 132 | 
 133 |   objectField.hidden = false
 134 |   arrayField.hidden = false
 135 |   valueField.hidden = false
 136 |   expect(objectField.value).toEqual({ value: '123' })
 137 |   expect(arrayField.value).toEqual(['123'])
 138 |   expect(valueField.value).toEqual('123')
 139 | 
 140 |   objectField.visible = false
 141 |   arrayField.visible = false
 142 |   valueField.visible = false
 143 |   expect(objectField.value).toBeUndefined()
 144 |   expect(arrayField.value).toBeUndefined()
 145 |   expect(valueField.value).toBeUndefined()
 146 | 
 147 |   objectField.visible = true
 148 |   arrayField.visible = true
 149 |   valueField.visible = true
 150 |   expect(objectField.value).toEqual({ value: '123' })
 151 |   expect(arrayField.value).toEqual(['123'])
 152 |   expect(valueField.value).toEqual('123')
 153 | })
 154 | 
 155 | test('nested display/pattern', () => {
 156 |   const form = attach(createForm())
 157 |   const object_ = attach(
 158 |     form.createObjectField({
 159 |       name: 'object',
 160 |     })
 161 |   )
 162 |   const void_ = attach(
 163 |     form.createVoidField({
 164 |       name: 'void',
 165 |       basePath: 'object',
 166 |     })
 167 |   )
 168 |   const aaa = attach(
 169 |     form.createField({
 170 |       name: 'aaa',
 171 |       basePath: 'object.void',
 172 |     })
 173 |   )
 174 |   const bbb = attach(
 175 |     form.createField({
 176 |       name: 'bbb',
 177 |       basePath: 'object',
 178 |     })
 179 |   )
 180 |   const ddd = attach(
 181 |     form.createField({
 182 |       name: 'ddd',
 183 |     })
 184 |   )
 185 |   expect(ddd.visible).toBeTruthy()
 186 |   expect(ddd.editable).toBeTruthy()
 187 |   object_.setPattern('readPretty')
 188 |   expect(void_.pattern).toEqual('readPretty')
 189 |   expect(aaa.pattern).toEqual('readPretty')
 190 |   expect(bbb.pattern).toEqual('readPretty')
 191 |   object_.setPattern('readOnly')
 192 |   expect(void_.pattern).toEqual('readOnly')
 193 |   expect(aaa.pattern).toEqual('readOnly')
 194 |   expect(bbb.pattern).toEqual('readOnly')
 195 |   object_.setPattern('disabled')
 196 |   expect(void_.pattern).toEqual('disabled')
 197 |   expect(aaa.pattern).toEqual('disabled')
 198 |   expect(bbb.pattern).toEqual('disabled')
 199 |   object_.setPattern()
 200 |   expect(void_.pattern).toEqual('editable')
 201 |   expect(aaa.pattern).toEqual('editable')
 202 |   expect(bbb.pattern).toEqual('editable')
 203 | 
 204 |   object_.setDisplay('hidden')
 205 |   expect(void_.display).toEqual('hidden')
 206 |   expect(aaa.display).toEqual('hidden')
 207 |   expect(bbb.display).toEqual('hidden')
 208 |   object_.setDisplay('none')
 209 |   expect(void_.display).toEqual('none')
 210 |   expect(aaa.display).toEqual('none')
 211 |   expect(bbb.display).toEqual('none')
 212 |   object_.setDisplay()
 213 |   expect(void_.display).toEqual('visible')
 214 |   expect(aaa.display).toEqual('visible')
 215 |   expect(bbb.display).toEqual('visible')
 216 | 
 217 |   aaa.setValue('123')
 218 |   expect(aaa.value).toEqual('123')
 219 |   aaa.setDisplay('none')
 220 |   expect(aaa.value).toBeUndefined()
 221 |   aaa.setDisplay('visible')
 222 |   expect(aaa.value).toEqual('123')
 223 |   aaa.setValue('123')
 224 |   object_.setDisplay('none')
 225 |   expect(aaa.value).toBeUndefined()
 226 |   object_.setDisplay('visible')
 227 |   expect(aaa.value).toEqual('123')
 228 | })
 229 | 
 230 | test('setValue/setInitialValue', () => {
 231 |   const form = attach(createForm())
 232 |   const aaa = attach(
 233 |     form.createField({
 234 |       name: 'aaa',
 235 |     })
 236 |   )
 237 |   const bbb = attach(
 238 |     form.createField({
 239 |       name: 'bbb',
 240 |     })
 241 |   )
 242 |   aaa.setValue('123')
 243 |   expect(aaa.value).toEqual('123')
 244 |   expect(form.values.aaa).toEqual('123')
 245 |   bbb.setValue('123')
 246 |   expect(bbb.value).toEqual('123')
 247 |   expect(form.values.bbb).toEqual('123')
 248 |   const ccc = attach(
 249 |     form.createField({
 250 |       name: 'ccc',
 251 |     })
 252 |   )
 253 |   const ddd = attach(
 254 |     form.createField({
 255 |       name: 'ddd',
 256 |     })
 257 |   )
 258 |   ccc.setInitialValue('123')
 259 |   expect(ccc.value).toEqual('123')
 260 |   expect(ccc.initialValue).toEqual('123')
 261 |   expect(form.values.ccc).toEqual('123')
 262 |   ddd.setInitialValue('123')
 263 |   expect(ddd.value).toEqual('123')
 264 |   expect(ddd.initialValue).toEqual('123')
 265 |   expect(form.values.ddd).toEqual('123')
 266 |   ccc.setInitialValue('222')
 267 |   expect(ccc.value).toEqual('222')
 268 |   expect(ccc.initialValue).toEqual('222')
 269 |   expect(form.values.ccc).toEqual('222')
 270 |   ddd.setInitialValue('222')
 271 |   expect(ddd.value).toEqual('222')
 272 |   expect(ddd.initialValue).toEqual('222')
 273 |   expect(form.values.ddd).toEqual('222')
 274 | })
 275 | 
 276 | test('setLoading/setValidating', async () => {
 277 |   const form = attach(createForm())
 278 |   const field = attach(
 279 |     form.createField({
 280 |       name: 'aa',
 281 |     })
 282 |   )
 283 |   field.setLoading(true)
 284 |   expect(field.loading).toBeFalsy()
 285 |   await sleep()
 286 |   expect(field.loading).toBeTruthy()
 287 |   field.setLoading(false)
 288 |   field.setLoading(false)
 289 |   expect(field.loading).toBeFalsy()
 290 |   field.setValidating(true)
 291 |   expect(field.validating).toBeFalsy()
 292 |   await sleep()
 293 |   expect(field.validating).toBeTruthy()
 294 |   field.setValidating(false)
 295 |   expect(field.validating).toBeFalsy()
 296 | })
 297 | 
 298 | test('setComponent/setComponentProps', () => {
 299 |   const component = () => null
 300 |   const form = attach(createForm())
 301 |   const field = attach(
 302 |     form.createField({
 303 |       name: 'aa',
 304 |     })
 305 |   )
 306 | 
 307 |   field.setComponent(undefined, { props: 123 })
 308 |   field.setComponent(component)
 309 |   expect(field.component[0]).toEqual(component)
 310 |   expect(field.component[1]).toEqual({ props: 123 })
 311 |   field.setComponentProps({
 312 |     hello: 'world',
 313 |   })
 314 |   expect(field.component[1]).toEqual({ props: 123, hello: 'world' })
 315 | })
 316 | 
 317 | test('setDecorator/setDecoratorProps', () => {
 318 |   const component = () => null
 319 |   const form = attach(createForm())
 320 |   const field = attach(
 321 |     form.createField({
 322 |       name: 'aa',
 323 |     })
 324 |   )
 325 |   field.setDecorator(undefined, { props: 123 })
 326 |   field.setDecorator(component)
 327 |   expect(field.decorator[0]).toEqual(component)
 328 |   expect(field.decorator[1]).toEqual({ props: 123 })
 329 |   field.setDecoratorProps({
 330 |     hello: 'world',
 331 |   })
 332 |   expect(field.decorator[1]).toEqual({ props: 123, hello: 'world' })
 333 | })
 334 | 
 335 | test('reaction initialValue', () => {
 336 |   const form = attach(
 337 |     createForm({
 338 |       values: {
 339 |         aa: 123,
 340 |       },
 341 |     })
 342 |   )
 343 |   const aa = attach(
 344 |     form.createField({
 345 |       name: 'aa',
 346 |       reactions(field) {
 347 |         field.initialValue = 321
 348 |       },
 349 |     })
 350 |   )
 351 |   const bb = attach(
 352 |     form.createField({
 353 |       name: 'bb',
 354 |       value: 123,
 355 |       reactions(field) {
 356 |         field.initialValue = 321
 357 |       },
 358 |     })
 359 |   )
 360 |   expect(aa.value).toEqual(123)
 361 |   expect(bb.value).toEqual(123)
 362 | })
 363 | 
 364 | test('selfValidate/errors/warnings/successes/valid/invalid/validateStatus/queryFeedbacks', async () => {
 365 |   const form = attach(createForm())
 366 |   const field = attach(
 367 |     form.createField({
 368 |       name: 'aa',
 369 |       required: true,
 370 |       validateFirst: true,
 371 |       validator: [
 372 |         (value) => {
 373 |           if (value == '123') {
 374 |             return {
 375 |               type: 'success',
 376 |               message: 'success',
 377 |             }
 378 |           } else if (value == '321') {
 379 |             return {
 380 |               type: 'warning',
 381 |               message: 'warning',
 382 |             }
 383 |           } else if (value == '111') {
 384 |             return 'error'
 385 |           }
 386 |         },
 387 |         {
 388 |           triggerType: 'onBlur',
 389 |           format: 'url',
 390 |         },
 391 |         {
 392 |           triggerType: 'onFocus',
 393 |           format: 'date',
 394 |         },
 395 |       ],
 396 |     })
 397 |   )
 398 |   const field2 = attach(
 399 |     form.createField({
 400 |       name: 'bb',
 401 |       required: true,
 402 |       value: '111',
 403 |       validator: [
 404 |         (value) => {
 405 |           if (value == '123') {
 406 |             return {
 407 |               type: 'success',
 408 |               message: 'success',
 409 |             }
 410 |           } else if (value == '321') {
 411 |             return {
 412 |               type: 'warning',
 413 |               message: 'warning',
 414 |             }
 415 |           } else if (value == '111') {
 416 |             return 'error'
 417 |           }
 418 |         },
 419 |         {
 420 |           triggerType: 'onBlur',
 421 |           format: 'url',
 422 |         },
 423 |         {
 424 |           triggerType: 'onFocus',
 425 |           format: 'date',
 426 |         },
 427 |       ],
 428 |     })
 429 |   )
 430 |   const field3 = attach(
 431 |     form.createField({
 432 |       name: 'xxx',
 433 |     })
 434 |   )
 435 |   const field4 = attach(
 436 |     form.createField({
 437 |       name: 'ppp',
 438 |       required: true,
 439 |     })
 440 |   )
 441 |   try {
 442 |     await field.validate()
 443 |   } catch {}
 444 |   try {
 445 |     await field2.validate()
 446 |   } catch {}
 447 |   expect(field.invalid).toBeTruthy()
 448 |   expect(field.selfErrors.length).toEqual(1)
 449 |   expect(field2.invalid).toBeTruthy()
 450 |   expect(field2.selfErrors.length).toEqual(3)
 451 |   await field.onInput('123')
 452 |   expect(field.selfSuccesses).toEqual(['success'])
 453 |   await field.onInput('321')
 454 |   expect(field.selfWarnings).toEqual(['warning'])
 455 |   await field.onInput('111')
 456 |   expect(field.selfErrors).toEqual(['error'])
 457 |   await field.onBlur()
 458 |   expect(field.selfErrors).toEqual([
 459 |     'error',
 460 |     'The field value is a invalid url',
 461 |   ])
 462 |   await field.onFocus()
 463 |   expect(field.selfErrors).toEqual([
 464 |     'error',
 465 |     'The field value is a invalid url',
 466 |     'The field value is not a valid date format',
 467 |   ])
 468 |   field.setFeedback()
 469 |   expect(field.selfErrors).toEqual([
 470 |     'error',
 471 |     'The field value is a invalid url',
 472 |     'The field value is not a valid date format',
 473 |   ])
 474 |   expect(field3.feedbacks).toEqual([])
 475 |   field3.setFeedback()
 476 |   field3.setFeedback({ messages: null })
 477 |   field3.setFeedback({ messages: ['error'], code: 'EffectError' })
 478 |   field3.setFeedback({ messages: ['error2'], code: 'EffectError' })
 479 |   expect(field3.feedbacks).toEqual([
 480 |     { code: 'EffectError', messages: ['error2'] },
 481 |   ])
 482 |   expect(
 483 |     field3.queryFeedbacks({
 484 |       address: 'xxx',
 485 |     })
 486 |   ).toEqual([{ code: 'EffectError', messages: ['error2'] }])
 487 |   expect(
 488 |     field3.queryFeedbacks({
 489 |       address: 'yyy',
 490 |     })
 491 |   ).toEqual([])
 492 |   expect(
 493 |     field3.queryFeedbacks({
 494 |       path: 'yyy',
 495 |     })
 496 |   ).toEqual([])
 497 |   field3.setFeedback({ messages: null, code: 'EffectError' })
 498 |   field3.setFeedback({ messages: [], code: 'EffectError' })
 499 |   field4.setDisplay('none')
 500 |   await field4.validate()
 501 |   expect(field4.selfErrors).toEqual([])
 502 | })
 503 | 
 504 | test('setValidateRule', () => {
 505 |   const form = attach(createForm())
 506 |   const field1 = attach(
 507 |     form.createField({
 508 |       name: 'aa',
 509 |       validator: [{ required: true }],
 510 |     })
 511 |   )
 512 |   const field2 = attach(
 513 |     form.createField({
 514 |       name: 'bb',
 515 |       validator: 'phone',
 516 |     })
 517 |   )
 518 |   const field3 = attach(
 519 |     form.createField({
 520 |       name: 'cc',
 521 |       validator: 'phone',
 522 |     })
 523 |   )
 524 |   const field4 = attach(
 525 |     form.createField({
 526 |       name: 'dd',
 527 |       validator: { format: 'phone' },
 528 |     })
 529 |   )
 530 |   const field5 = attach(
 531 |     form.createField({
 532 |       name: 'ee',
 533 |       validator: [{ format: 'phone' }],
 534 |     })
 535 |   )
 536 |   const field6 = attach(
 537 |     form.createField({
 538 |       name: 'ff',
 539 |     })
 540 |   )
 541 |   field1.setValidatorRule('format', 'phone')
 542 |   field2.setValidatorRule('max', 3)
 543 |   field3.setValidatorRule('format', 'url')
 544 |   field4.setValidatorRule('min', 3)
 545 |   field5.setValidatorRule('min', 3)
 546 |   field6.setValidatorRule('min', 3)
 547 |   expect(field1.validator).toEqual([{ required: true }, { format: 'phone' }])
 548 |   expect(field2.validator).toEqual([{ format: 'phone' }, { max: 3 }])
 549 |   expect(field3.validator).toEqual([{ format: 'url' }])
 550 |   expect(field4.validator).toEqual([{ format: 'phone' }, { min: 3 }])
 551 |   expect(field5.validator).toEqual([{ format: 'phone' }, { min: 3 }])
 552 |   expect(field6.validator).toEqual([{ min: 3 }])
 553 | })
 554 | 
 555 | test('query', () => {
 556 |   const form = attach(createForm())
 557 |   const object_ = attach(
 558 |     form.createObjectField({
 559 |       name: 'object',
 560 |     })
 561 |   )
 562 |   const void_ = attach(
 563 |     form.createVoidField({
 564 |       name: 'void',
 565 |       basePath: 'object',
 566 |     })
 567 |   )
 568 |   const aaa = attach(
 569 |     form.createField({
 570 |       name: 'aaa',
 571 |       basePath: 'object.void',
 572 |     })
 573 |   )
 574 |   const bbb = attach(
 575 |     form.createField({
 576 |       name: 'bbb',
 577 |       basePath: 'object',
 578 |     })
 579 |   )
 580 |   expect(object_.query('object.void').take()).not.toBeUndefined()
 581 |   expect(object_.query('object.void.aaa').take()).not.toBeUndefined()
 582 |   expect(void_.query('.')).not.toBeUndefined()
 583 |   expect(void_.query('.bbb').take()).not.toBeUndefined()
 584 |   expect(aaa.query('.ccc').take()).toBeUndefined()
 585 |   expect(aaa.query('..').take()).not.toBeUndefined()
 586 |   expect(aaa.query('..bbb').take()).not.toBeUndefined()
 587 |   expect(bbb.query('.void').take()).not.toBeUndefined()
 588 |   expect(bbb.query('.void.aaa').take()).not.toBeUndefined()
 589 |   expect(bbb.query('.void.ccc').take()).toBeUndefined()
 590 | })
 591 | 
 592 | test('empty initialValue', () => {
 593 |   const form = attach(createForm())
 594 |   const aa = attach(
 595 |     form.createField({
 596 |       name: 'aa',
 597 |       initialValue: '',
 598 |     })
 599 |   )
 600 |   const bb = attach(
 601 |     form.createField({
 602 |       name: 'bb',
 603 |     })
 604 |   )
 605 |   expect(aa.value).toEqual('')
 606 |   expect(form.values.aa).toEqual('')
 607 |   expect(bb.value).toEqual(undefined)
 608 |   expect(form.values.bb).toEqual(undefined)
 609 | })
 610 | 
 611 | test('objectFieldWithInitialValue', async () => {
 612 |   const form = attach(
 613 |     createForm({
 614 |       initialValues: {
 615 |         obj: {
 616 |           a: 'a',
 617 |         },
 618 |       },
 619 |     })
 620 |   )
 621 |   attach(
 622 |     form.createObjectField({
 623 |       name: 'obj',
 624 |     })
 625 |   )
 626 |   const fieldObjA = attach(
 627 |     form.createField({
 628 |       name: 'obj.a',
 629 |     })
 630 |   )
 631 | 
 632 |   expect(fieldObjA.initialValue).toEqual('a')
 633 |   fieldObjA.value = 'aa'
 634 |   expect(fieldObjA.value).toEqual('aa')
 635 |   expect(fieldObjA.initialValue).toEqual('a')
 636 | })
 637 | 
 638 | test('initialValueWithArray', () => {
 639 |   const form = attach(createForm())
 640 |   const field = attach(
 641 |     form.createArrayField({
 642 |       name: 'aaa',
 643 |       initialValue: [1, 2],
 644 |     })
 645 |   )
 646 |   expect(field.initialValue).toEqual([1, 2])
 647 |   expect(field.value).toEqual([1, 2])
 648 |   expect(form.initialValues.aaa).toEqual([1, 2])
 649 |   expect(form.values.aaa).toEqual([1, 2])
 650 | })
 651 | 
 652 | test('resetObjectFieldWithInitialValue', async () => {
 653 |   const form = attach(createForm())
 654 |   attach(
 655 |     form.createObjectField({
 656 |       name: 'obj',
 657 |     })
 658 |   )
 659 |   const fieldObjA = attach(
 660 |     form.createField({
 661 |       name: 'obj.a',
 662 |       initialValue: 'a',
 663 |     })
 664 |   )
 665 | 
 666 |   fieldObjA.value = 'aa'
 667 |   expect(fieldObjA.value).toEqual('aa')
 668 |   await form.reset()
 669 |   expect(fieldObjA.value).toEqual('a')
 670 | 
 671 |   fieldObjA.value = 'aa'
 672 |   expect(fieldObjA.value).toEqual('aa')
 673 |   await form.reset()
 674 |   expect(fieldObjA.initialValue).toEqual('a')
 675 |   expect(fieldObjA.value).toEqual('a')
 676 | })
 677 | 
 678 | test('reset', async () => {
 679 |   const form = attach(
 680 |     createForm<any>({
 681 |       values: {
 682 |         bb: 123,
 683 |       },
 684 |       initialValues: {
 685 |         aa: 123,
 686 |         cc: null,
 687 |       },
 688 |     })
 689 |   )
 690 |   const aa = attach(
 691 |     form.createField({
 692 |       name: 'aa',
 693 |       required: true,
 694 |     })
 695 |   )
 696 |   const bb = attach(
 697 |     form.createField({
 698 |       name: 'bb',
 699 |       required: true,
 700 |     })
 701 |   )
 702 |   const cc = attach(
 703 |     form.createField({
 704 |       name: 'cc',
 705 |       required: true,
 706 |     })
 707 |   )
 708 |   const dd = attach(
 709 |     form.createField({
 710 |       name: 'dd',
 711 |       required: true,
 712 |     })
 713 |   )
 714 |   expect(aa.value).toEqual(123)
 715 |   expect(bb.value).toEqual(123)
 716 |   expect(cc.value).toEqual(null)
 717 |   expect(form.values.aa).toEqual(123)
 718 |   expect(form.values.bb).toEqual(123)
 719 |   expect(form.values.cc).toEqual(null)
 720 |   aa.onInput('xxxxx')
 721 |   expect(form.values.aa).toEqual('xxxxx')
 722 |   dd.onInput(null)
 723 |   expect(form.values.dd).toEqual(null)
 724 |   aa.reset()
 725 |   expect(aa.value).toEqual(123)
 726 |   expect(form.values.aa).toEqual(123)
 727 |   bb.onInput('xxxxx')
 728 |   expect(form.values.bb).toEqual('xxxxx')
 729 |   bb.reset()
 730 |   expect(bb.value).toBeUndefined()
 731 |   expect(form.values.bb).toBeUndefined()
 732 | 
 733 |   cc.onInput('xxxxx')
 734 |   expect(form.values.cc).toEqual('xxxxx')
 735 |   cc.reset()
 736 |   expect(cc.value).toBeNull()
 737 |   expect(form.values.cc).toBeNull()
 738 |   dd.reset()
 739 |   expect(dd.value).toBeUndefined()
 740 |   expect(form.values.dd).toBeUndefined()
 741 | 
 742 |   aa.reset({
 743 |     forceClear: true,
 744 |   })
 745 |   expect(aa.value).toBeUndefined()
 746 |   expect(form.values.aa).toBeUndefined()
 747 |   cc.reset({
 748 |     forceClear: true,
 749 |   })
 750 |   expect(cc.value).toBeUndefined()
 751 |   expect(form.values.cc).toBeUndefined()
 752 | 
 753 |   expect(aa.valid).toBeTruthy()
 754 |   await aa.reset({
 755 |     forceClear: true,
 756 |     validate: true,
 757 |   })
 758 |   expect(aa.valid).toBeFalsy()
 759 | 
 760 |   expect(cc.valid).toBeTruthy()
 761 |   await cc.reset({
 762 |     forceClear: true,
 763 |     validate: true,
 764 |   })
 765 |   expect(cc.valid).toBeFalsy()
 766 | })
 767 | 
 768 | test('match', () => {
 769 |   const form = attach(
 770 |     createForm<any>({
 771 |       values: {
 772 |         bb: 123,
 773 |       },
 774 |       initialValues: {
 775 |         aa: 123,
 776 |       },
 777 |     })
 778 |   )
 779 |   const aa = attach(
 780 |     form.createField({
 781 |       name: 'aa',
 782 |       required: true,
 783 |     })
 784 |   )
 785 |   expect(aa.match('aa')).toBeTruthy()
 786 |   expect(aa.match('*')).toBeTruthy()
 787 |   expect(aa.match('a~')).toBeTruthy()
 788 |   expect(aa.match('*(aa,bb)')).toBeTruthy()
 789 | })
 790 | 
 791 | test('setState/getState', () => {
 792 |   const form = attach(createForm())
 793 |   const aa = attach(
 794 |     form.createField({
 795 |       name: 'aa',
 796 |       required: true,
 797 |     })
 798 |   )
 799 |   const state = aa.getState()
 800 |   aa.setState((state) => {
 801 |     state.value = '123'
 802 |     state.title = 'AAA'
 803 |   })
 804 |   expect(aa.value).toEqual('123')
 805 |   expect(aa.title).toEqual('AAA')
 806 |   state['setState'] = () => {}
 807 |   aa.setState(state)
 808 |   expect(aa.value).toBeUndefined()
 809 |   expect(aa.title).toBeUndefined()
 810 |   aa.setState((state) => {
 811 |     state.hidden = false
 812 |   })
 813 |   expect(aa.display).toEqual('visible')
 814 |   aa.setState((state) => {
 815 |     state.visible = true
 816 |   })
 817 |   expect(aa.display).toEqual('visible')
 818 |   aa.setState((state) => {
 819 |     state.readOnly = false
 820 |   })
 821 |   expect(aa.pattern).toEqual('editable')
 822 |   aa.setState((state) => {
 823 |     state.disabled = false
 824 |   })
 825 |   expect(aa.pattern).toEqual('editable')
 826 |   aa.setState((state) => {
 827 |     state.editable = true
 828 |   })
 829 |   expect(aa.pattern).toEqual('editable')
 830 |   aa.setState((state) => {
 831 |     state.editable = false
 832 |   })
 833 |   expect(aa.pattern).toEqual('readPretty')
 834 |   aa.setState((state) => {
 835 |     state.readPretty = true
 836 |   })
 837 |   expect(aa.pattern).toEqual('readPretty')
 838 |   aa.setState((state) => {
 839 |     state.readPretty = false
 840 |   })
 841 |   expect(aa.pattern).toEqual('editable')
 842 |   form.setFieldState('bb', (state) => {
 843 |     state.value = 'bbb'
 844 |   })
 845 |   form.setFieldState('bb', (state) => {
 846 |     state.visible = false
 847 |   })
 848 |   const bb = attach(
 849 |     form.createField({
 850 |       name: 'bb',
 851 |     })
 852 |   )
 853 |   expect(bb.value).toEqual(undefined)
 854 |   expect(bb.visible).toBeFalsy()
 855 |   form.setFieldState('*', (state) => {
 856 |     state.value = '123'
 857 |   })
 858 |   const cc = attach(
 859 |     form.createField({
 860 |       name: 'cc',
 861 |     })
 862 |   )
 863 |   expect(aa.value).toEqual('123')
 864 |   expect(bb.value).toBeUndefined()
 865 |   expect(cc.value).toEqual('123')
 866 |   form.setFieldState(form.query('cc'), (state) => {
 867 |     state.value = 'ccc'
 868 |   })
 869 |   expect(cc.value).toEqual('ccc')
 870 |   form.setFieldState(cc, (state) => {
 871 |     state.value = '123'
 872 |   })
 873 |   expect(cc.value).toEqual('123')
 874 |   expect(form.getFieldState(aa)).not.toBeUndefined()
 875 |   expect(form.getFieldState(form.query('aa'))).not.toBeUndefined()
 876 | })
 877 | 
 878 | test('setDataSource', () => {
 879 |   const form = attach(createForm())
 880 |   const aa = attach(
 881 |     form.createField({
 882 |       name: 'aa',
 883 |       required: true,
 884 |     })
 885 |   )
 886 |   aa.setDataSource([
 887 |     { label: 's1', value: 's1' },
 888 |     { label: 's2', value: 's2' },
 889 |   ])
 890 |   expect(aa.dataSource).toEqual([
 891 |     { label: 's1', value: 's1' },
 892 |     { label: 's2', value: 's2' },
 893 |   ])
 894 | })
 895 | 
 896 | test('setTitle/setDescription', () => {
 897 |   const form = attach(createForm())
 898 |   const aa = attach(
 899 |     form.createField({
 900 |       name: 'aa',
 901 |       required: true,
 902 |     })
 903 |   )
 904 |   aa.setTitle('AAA')
 905 |   aa.setDescription('This is AAA')
 906 |   expect(aa.title).toEqual('AAA')
 907 |   expect(aa.description).toEqual('This is AAA')
 908 | })
 909 | 
 910 | test('required/setRequired', () => {
 911 |   const form = attach(createForm())
 912 |   const aa = attach(
 913 |     form.createField({
 914 |       name: 'aa',
 915 |     })
 916 |   )
 917 |   aa.setRequired(true)
 918 |   expect(aa.required).toBeTruthy()
 919 |   aa.setRequired(false)
 920 |   expect(aa.required).toBeFalsy()
 921 |   const bb = attach(
 922 |     form.createField({
 923 |       name: 'bb',
 924 |       validator: {
 925 |         max: 3,
 926 |         required: true,
 927 |       },
 928 |     })
 929 |   )
 930 |   expect(bb.required).toBeTruthy()
 931 |   bb.setRequired(false)
 932 |   expect(bb.required).toBeFalsy()
 933 |   const cc = attach(
 934 |     form.createField({
 935 |       name: 'cc',
 936 |       validator: [
 937 |         'date',
 938 |         {
 939 |           max: 3,
 940 |         },
 941 |         {
 942 |           required: true,
 943 |         },
 944 |       ],
 945 |     })
 946 |   )
 947 |   expect(cc.required).toBeTruthy()
 948 |   cc.setRequired(false)
 949 |   expect(cc.required).toBeFalsy()
 950 |   const dd = attach(
 951 |     form.createField({
 952 |       name: 'dd',
 953 |       validator: {
 954 |         max: 3,
 955 |       },
 956 |     })
 957 |   )
 958 |   expect(dd.required).toBeFalsy()
 959 |   dd.setRequired(true)
 960 |   expect(dd.required).toBeTruthy()
 961 | })
 962 | 
 963 | test('setData/setContent', () => {
 964 |   const form = attach(createForm())
 965 |   const aa = attach(
 966 |     form.createField({
 967 |       name: 'aa',
 968 |       required: true,
 969 |     })
 970 |   )
 971 |   aa.setData('This is data')
 972 |   aa.setContent('This is Content')
 973 |   expect(aa.data).toEqual('This is data')
 974 |   expect(aa.content).toEqual('This is Content')
 975 | })
 976 | 
 977 | test('setData/setContent in void field', () => {
 978 |   const form = attach(createForm())
 979 |   const voidFeild = attach(
 980 |     form.createVoidField({
 981 |       name: 'voidFeild',
 982 |     })
 983 |   )
 984 |   voidFeild.setData('This is data')
 985 |   voidFeild.setContent('This is Content')
 986 |   expect(voidFeild.data).toEqual('This is data')
 987 |   expect(voidFeild.content).toEqual('This is Content')
 988 | })
 989 | 
 990 | test('setErrors/setWarnings/setSuccesses/setValidator', async () => {
 991 |   const form = attach(createForm())
 992 |   const aa = attach(
 993 |     form.createField({
 994 |       name: 'aa',
 995 |     })
 996 |   )
 997 |   const bb = attach(
 998 |     form.createField({
 999 |       name: 'bb',
1000 |     })
1001 |   )
1002 |   const cc = attach(
1003 |     form.createField({
1004 |       name: 'cc',
1005 |     })
1006 |   )
1007 |   const dd = attach(
1008 |     form.createField({
1009 |       name: 'dd',
1010 |       validator() {
1011 |         return new Promise(() => {})
1012 |       },
1013 |     })
1014 |   )
1015 |   aa.setSelfErrors(['error'])
1016 |   aa.setSelfWarnings(['warning'])
1017 |   aa.setSelfSuccesses(['success'])
1018 |   bb.setSelfSuccesses(['success'])
1019 |   cc.setSelfWarnings(['warning'])
1020 |   expect(aa.selfErrors).toEqual(['error'])
1021 |   expect(aa.valid).toBeFalsy()
1022 |   expect(aa.selfWarnings).toEqual(['warning'])
1023 |   expect(aa.selfSuccesses).toEqual(['success'])
1024 |   expect(bb.validateStatus).toEqual('success')
1025 |   expect(cc.validateStatus).toEqual('warning')
1026 |   aa.setValidator('date')
1027 |   await aa.onInput('123')
1028 |   expect(aa.selfErrors.length).toEqual(2)
1029 |   dd.onInput('123')
1030 |   await sleep()
1031 |   expect(dd.validateStatus).toEqual('validating')
1032 | })
1033 | 
1034 | test('reactions', async () => {
1035 |   const form = attach(createForm())
1036 |   const aa = attach(
1037 |     form.createField({
1038 |       name: 'aa',
1039 |     })
1040 |   )
1041 |   const bb = attach(
1042 |     form.createField({
1043 |       name: 'bb',
1044 |       reactions: [
1045 |         (field) => {
1046 |           const aa = field.query('aa')
1047 |           if (aa.get('value') === '123') {
1048 |             field.visible = false
1049 |           } else {
1050 |             field.visible = true
1051 |           }
1052 |           if (aa.get('inputValue') === '333') {
1053 |             field.editable = false
1054 |           } else if (aa.get('inputValue') === '444') {
1055 |             field.editable = true
1056 |           }
1057 |           if (aa.get('initialValue') === '555') {
1058 |             field.readOnly = true
1059 |           } else if (aa.get('initialValue') === '666') {
1060 |             field.readOnly = false
1061 |           }
1062 |         },
1063 |         null,
1064 |       ],
1065 |     })
1066 |   )
1067 |   expect(bb.visible).toBeTruthy()
1068 |   aa.setValue('123')
1069 |   expect(bb.visible).toBeFalsy()
1070 |   await aa.onInput('333')
1071 |   expect(bb.editable).toBeFalsy()
1072 |   await aa.onInput('444')
1073 |   expect(bb.editable).toBeTruthy()
1074 |   aa.setInitialValue('555')
1075 |   expect(bb.readOnly).toBeTruthy()
1076 |   aa.setInitialValue('666')
1077 |   expect(bb.readOnly).toBeFalsy()
1078 |   form.onUnmount()
1079 | })
1080 | 
1081 | test('fault tolerance', () => {
1082 |   const form = attach(createForm())
1083 |   const field = attach(
1084 |     form.createField({
1085 |       name: 'aa',
1086 |       value: 123,
1087 |     })
1088 |   )
1089 |   field.setDisplay('none')
1090 |   expect(field.value).toBeUndefined()
1091 |   field.setDisplay('visible')
1092 |   expect(field.value).toEqual(123)
1093 |   field.setDisplay('none')
1094 |   expect(field.value).toBeUndefined()
1095 |   field.setValue(321)
1096 |   expect(field.value).toBeUndefined()
1097 |   field.setDisplay('visible')
1098 |   expect(field.value).toEqual(321)
1099 |   form.setDisplay(null)
1100 |   form.setPattern(null)
1101 |   const field2 = attach(
1102 |     form.createField({
1103 |       name: 'xxx',
1104 |     })
1105 |   )
1106 |   expect(field2.display).toEqual('visible')
1107 |   expect(field2.pattern).toEqual('editable')
1108 | })
1109 | 
1110 | test('initialValue', () => {
1111 |   const form = attach(createForm())
1112 |   const field = attach(
1113 |     form.createField({
1114 |       name: 'aaa',
1115 |       initialValue: 123,
1116 |     })
1117 |   )
1118 |   expect(form.values.aaa).toEqual(123)
1119 |   expect(form.initialValues.aaa).toEqual(123)
1120 |   expect(field.value).toEqual(123)
1121 |   expect(field.initialValue).toEqual(123)
1122 | })
1123 | 
1124 | test('array path calculation with none index', async () => {
1125 |   const form = attach(createForm())
1126 |   const array = attach(
1127 |     form.createArrayField({
1128 |       name: 'array',
1129 |     })
1130 |   )
1131 |   await array.push({})
1132 |   const input = attach(
1133 |     form.createField({
1134 |       name: '0.input',
1135 |       basePath: 'array',
1136 |     })
1137 |   )
1138 |   expect(input.path.toString()).toEqual('array.0.input')
1139 | })
1140 | 
1141 | test('array path calculation with none index and void nested', async () => {
1142 |   const form = attach(createForm())
1143 |   const array = attach(
1144 |     form.createArrayField({
1145 |       name: 'array',
1146 |     })
1147 |   )
1148 |   await array.push({})
1149 |   attach(
1150 |     form.createVoidField({
1151 |       name: '0.column',
1152 |       basePath: 'array',
1153 |     })
1154 |   )
1155 |   const input = attach(
1156 |     form.createField({
1157 |       name: 'input',
1158 |       basePath: 'array.0.column',
1159 |     })
1160 |   )
1161 |   expect(input.path.toString()).toEqual('array.0.input')
1162 | })
1163 | 
1164 | test('array path calculation with object index', async () => {
1165 |   const form = attach(createForm())
1166 |   const array = attach(
1167 |     form.createArrayField({
1168 |       name: 'array',
1169 |     })
1170 |   )
1171 |   await array.push({})
1172 |   attach(
1173 |     form.createObjectField({
1174 |       name: '0',
1175 |       basePath: 'array',
1176 |     })
1177 |   )
1178 |   const input = attach(
1179 |     form.createField({
1180 |       name: 'input',
1181 |       basePath: 'array.0',
1182 |     })
1183 |   )
1184 |   expect(input.path.toString()).toEqual('array.0.input')
1185 | })
1186 | 
1187 | test('array path calculation with void index', async () => {
1188 |   const form = attach(createForm())
1189 |   const array = attach(
1190 |     form.createArrayField({
1191 |       name: 'array',
1192 |     })
1193 |   )
1194 |   await array.push('')
1195 |   attach(
1196 |     form.createVoidField({
1197 |       name: '0',
1198 |       basePath: 'array',
1199 |     })
1200 |   )
1201 |   const input = attach(
1202 |     form.createField({
1203 |       name: 'input',
1204 |       basePath: 'array.0',
1205 |     })
1206 |   )
1207 |   expect(input.path.toString()).toEqual('array.0')
1208 | })
1209 | 
1210 | test('array path calculation with void index and void wrapper', async () => {
1211 |   const form = attach(createForm())
1212 |   attach(
1213 |     form.createVoidField({
1214 |       name: 'layout',
1215 |     })
1216 |   )
1217 |   const array_in_layout = attach(
1218 |     form.createArrayField({
1219 |       name: 'array_in_layout',
1220 |       basePath: 'layout',
1221 |     })
1222 |   )
1223 |   await array_in_layout.push('')
1224 |   attach(
1225 |     form.createVoidField({
1226 |       name: '0',
1227 |       basePath: 'layout.array_in_layout',
1228 |     })
1229 |   )
1230 |   const input = attach(
1231 |     form.createField({
1232 |       name: 'input',
1233 |       basePath: 'layout.array_in_layout.0',
1234 |     })
1235 |   )
1236 |   expect(input.path.toString()).toEqual('array_in_layout.0')
1237 | })
1238 | 
1239 | test('reaction in reaction', () => {
1240 |   const form = attach(createForm())
1241 |   const void_ = attach(
1242 |     form.createVoidField({
1243 |       name: 'void',
1244 |     })
1245 |   )
1246 |   attach(
1247 |     form.createField({
1248 |       name: 'field1',
1249 |       basePath: 'void',
1250 |       initialValue: 123,
1251 |     })
1252 |   )
1253 |   const field2 = attach(
1254 |     form.createField({
1255 |       name: 'field2',
1256 |       basePath: 'void',
1257 |       initialValue: 456,
1258 |       reactions: (field) => {
1259 |         const f1 = field.query('field1')
1260 |         if (f1.get('value') === 123) {
1261 |           field.display = 'visible'
1262 |         } else {
1263 |           field.display = 'none'
1264 |         }
1265 |       },
1266 |     })
1267 |   )
1268 |   void_.setDisplay('none')
1269 |   expect(field2.value).toEqual(undefined)
1270 |   expect(field2.display).toEqual('none')
1271 | })
1272 | 
1273 | test('nested fields hidden and selfValidate', async () => {
1274 |   const form = attach(createForm())
1275 |   const parent = attach(
1276 |     form.createVoidField({
1277 |       name: 'parent',
1278 |     })
1279 |   )
1280 |   attach(
1281 |     form.createField({
1282 |       name: 'aa',
1283 |       basePath: 'parent',
1284 |       required: true,
1285 |     })
1286 |   )
1287 |   attach(
1288 |     form.createField({
1289 |       name: 'bb',
1290 |       basePath: 'parent',
1291 |       required: true,
1292 |     })
1293 |   )
1294 |   try {
1295 |     await form.validate()
1296 |   } catch {}
1297 |   expect(form.invalid).toBeTruthy()
1298 |   parent.display = 'hidden'
1299 |   await form.validate()
1300 |   expect(form.invalid).toBeFalsy()
1301 | })
1302 | 
1303 | test('deep nested fields hidden and selfValidate', async () => {
1304 |   const form = attach(createForm())
1305 |   const parent1 = attach(
1306 |     form.createVoidField({
1307 |       name: 'parent1',
1308 |     })
1309 |   )
1310 |   const parent2 = attach(
1311 |     form.createVoidField({
1312 |       name: 'parent2',
1313 |       basePath: 'parent1',
1314 |     })
1315 |   )
1316 |   const aa = attach(
1317 |     form.createField({
1318 |       name: 'aa',
1319 |       basePath: 'parent1.parent2',
1320 |       required: true,
1321 |     })
1322 |   )
1323 |   const bb = attach(
1324 |     form.createField({
1325 |       name: 'bb',
1326 |       basePath: 'parent1.parent2',
1327 |       required: true,
1328 |     })
1329 |   )
1330 |   try {
1331 |     await form.validate()
1332 |   } catch {}
1333 |   expect(form.invalid).toBeTruthy()
1334 |   parent2.display = 'visible'
1335 |   parent1.display = 'hidden'
1336 |   expect(parent2.display).toEqual('hidden')
1337 |   expect(aa.display).toEqual('hidden')
1338 |   expect(bb.display).toEqual('hidden')
1339 |   await form.validate()
1340 |   expect(form.invalid).toBeFalsy()
1341 | })
1342 | 
1343 | test('deep nested fields hidden and selfValidate with middle hidden', async () => {
1344 |   const form = attach(createForm())
1345 |   const parent1 = attach(
1346 |     form.createVoidField({
1347 |       name: 'parent1',
1348 |     })
1349 |   )
1350 |   const parent2 = attach(
1351 |     form.createVoidField({
1352 |       name: 'parent2',
1353 |       basePath: 'parent1',
1354 |     })
1355 |   )
1356 |   const aa = attach(
1357 |     form.createField({
1358 |       name: 'aa',
1359 |       basePath: 'parent1.parent2',
1360 |       required: true,
1361 |     })
1362 |   )
1363 |   const bb = attach(
1364 |     form.createField({
1365 |       name: 'bb',
1366 |       basePath: 'parent1.parent2',
1367 |       required: true,
1368 |     })
1369 |   )
1370 |   try {
1371 |     await form.validate()
1372 |   } catch {}
1373 |   expect(form.invalid).toBeTruthy()
1374 |   parent2.display = 'hidden'
1375 |   parent1.display = 'none'
1376 |   expect(parent2.display).toEqual('hidden')
1377 |   expect(aa.display).toEqual('hidden')
1378 |   expect(bb.display).toEqual('hidden')
1379 |   await form.validate()
1380 |   expect(form.invalid).toBeFalsy()
1381 | })
1382 | 
1383 | test('fields unmount and selfValidate', async () => {
1384 |   const form = attach(createForm())
1385 |   const field = attach(
1386 |     form.createField({
1387 |       name: 'parent',
1388 |       required: true,
1389 |     })
1390 |   )
1391 |   try {
1392 |     await form.validate()
1393 |   } catch {}
1394 |   expect(form.invalid).toBeTruthy()
1395 |   field.onUnmount()
1396 |   try {
1397 |     await form.validate()
1398 |   } catch {}
1399 |   expect(form.invalid).toBeTruthy()
1400 |   form.clearFormGraph('parent')
1401 |   await form.validate()
1402 |   expect(form.invalid).toBeFalsy()
1403 | })
1404 | 
1405 | test('auto clean with ArrayField', () => {
1406 |   const form = attach(createForm())
1407 |   attach(
1408 |     form.createArrayField({
1409 |       name: 'array',
1410 |       initialValue: [{}, {}],
1411 |     })
1412 |   )
1413 |   attach(
1414 |     form.createField({
1415 |       name: '0.aa',
1416 |       basePath: 'array',
1417 |     })
1418 |   )
1419 |   attach(
1420 |     form.createField({
1421 |       name: '1.aa',
1422 |       basePath: 'array',
1423 |     })
1424 |   )
1425 |   const array1 = attach(
1426 |     form.createArrayField({
1427 |       name: 'array1',
1428 |       initialValue: [{}, {}],
1429 |     })
1430 |   )
1431 |   attach(
1432 |     form.createField({
1433 |       name: '0.aa',
1434 |       basePath: 'array1',
1435 |     })
1436 |   )
1437 |   attach(
1438 |     form.createField({
1439 |       name: '1.aa',
1440 |       basePath: 'array1',
1441 |     })
1442 |   )
1443 |   const array2 = attach(
1444 |     form.createArrayField({
1445 |       name: 'array2',
1446 |       initialValue: [{}, {}],
1447 |     })
1448 |   )
1449 |   attach(
1450 |     form.createField({
1451 |       name: '0.aa',
1452 |       basePath: 'array2',
1453 |     })
1454 |   )
1455 |   attach(
1456 |     form.createField({
1457 |       name: '1.aa',
1458 |       basePath: 'array2',
1459 |     })
1460 |   )
1461 |   expect(form.fields['array.1.aa']).not.toBeUndefined()
1462 |   expect(form.values.array).toEqual([{}, {}])
1463 |   form.setValues(
1464 |     {
1465 |       array: [{}],
1466 |     },
1467 |     'shallowMerge'
1468 |   )
1469 |   expect(form.values.array).toEqual([{}])
1470 |   expect(form.fields['array.1.aa']).toBeUndefined()
1471 |   expect(form.fields['array1.0.aa']).not.toBeUndefined()
1472 |   expect(form.fields['array1.1.aa']).not.toBeUndefined()
1473 |   expect(form.values.array1).toEqual([{}, {}])
1474 |   array1.setValue([])
1475 |   expect(form.fields['array1.0.aa']).toBeUndefined()
1476 |   expect(form.fields['array1.1.aa']).toBeUndefined()
1477 |   expect(form.fields['array2.0.aa']).not.toBeUndefined()
1478 |   expect(form.fields['array2.1.aa']).not.toBeUndefined()
1479 |   array2.setValue([])
1480 |   expect(form.fields['array2.0.aa']).toBeUndefined()
1481 |   expect(form.fields['array2.1.aa']).toBeUndefined()
1482 | })
1483 | 
1484 | test('auto clean with ObjectField', () => {
1485 |   const form = attach(createForm())
1486 |   attach(
1487 |     form.createObjectField({
1488 |       name: 'obj',
1489 |       initialValue: {
1490 |         aa: 'aa',
1491 |         bb: 'bb',
1492 |       },
1493 |     })
1494 |   )
1495 |   attach(
1496 |     form.createField({
1497 |       name: 'aa',
1498 |       basePath: 'obj',
1499 |     })
1500 |   )
1501 |   attach(
1502 |     form.createField({
1503 |       name: 'bb',
1504 |       basePath: 'obj',
1505 |     })
1506 |   )
1507 |   const obj1 = attach(
1508 |     form.createObjectField({
1509 |       name: 'obj1',
1510 |       initialValue: {
1511 |         aa: 'aa',
1512 |         bb: 'bb',
1513 |       },
1514 |     })
1515 |   )
1516 |   attach(
1517 |     form.createField({
1518 |       name: 'aa',
1519 |       basePath: 'obj1',
1520 |     })
1521 |   )
1522 |   attach(
1523 |     form.createField({
1524 |       name: 'bb',
1525 |       basePath: 'obj1',
1526 |     })
1527 |   )
1528 |   const obj2 = attach(
1529 |     form.createObjectField({
1530 |       name: 'obj2',
1531 |       initialValue: {
1532 |         aa: 'aa',
1533 |         bb: 'bb',
1534 |       },
1535 |     })
1536 |   )
1537 |   attach(
1538 |     form.createField({
1539 |       name: 'aa',
1540 |       basePath: 'obj2',
1541 |     })
1542 |   )
1543 |   attach(
1544 |     form.createField({
1545 |       name: 'bb',
1546 |       basePath: 'obj2',
1547 |     })
1548 |   )
1549 |   expect(form.fields['obj.aa']).not.toBeUndefined()
1550 |   expect(form.fields['obj.bb']).not.toBeUndefined()
1551 |   expect(form.values.obj).toEqual({ aa: 'aa', bb: 'bb' })
1552 |   form.setValues(
1553 |     {
1554 |       obj: {
1555 |         aa: '123',
1556 |       },
1557 |     },
1558 |     'shallowMerge'
1559 |   )
1560 |   expect(form.values.obj).toEqual({ aa: '123' })
1561 |   expect(form.fields['obj.aa']).not.toBeUndefined()
1562 |   expect(form.fields['obj.bb']).not.toBeUndefined()
1563 |   expect(form.fields['obj1.aa']).not.toBeUndefined()
1564 |   expect(form.fields['obj1.bb']).not.toBeUndefined()
1565 |   expect(form.values.obj1).toEqual({ aa: 'aa', bb: 'bb' })
1566 |   obj1.setValue({})
1567 |   expect(form.values.obj1).toEqual({})
1568 |   expect(form.fields['obj1.aa']).not.toBeUndefined()
1569 |   expect(form.fields['obj1.bb']).not.toBeUndefined()
1570 |   expect(form.fields['obj2.aa']).not.toBeUndefined()
1571 |   expect(form.fields['obj2.bb']).not.toBeUndefined()
1572 |   expect(form.values.obj2).toEqual({ aa: 'aa', bb: 'bb' })
1573 |   obj2.setValue({ aa: 'aa', bb: 'bb', cc: 'cc' })
1574 |   expect(form.fields['obj2.aa']).not.toBeUndefined()
1575 |   expect(form.fields['obj2.bb']).not.toBeUndefined()
1576 |   expect(form.fields['obj2.cc']).toBeUndefined()
1577 |   obj2.addProperty('cc', '123')
1578 |   attach(
1579 |     form.createField({
1580 |       name: 'cc',
1581 |       basePath: 'obj2',
1582 |     })
1583 |   )
1584 |   expect(form.fields['obj2.cc']).not.toBeUndefined()
1585 |   obj2.removeProperty('cc')
1586 |   expect(form.fields['obj2.cc']).toBeUndefined()
1587 | })
1588 | 
1589 | test('initial value with empty', () => {
1590 |   const form = attach(createForm())
1591 |   const array = attach(form.createField({ name: 'array', initialValue: '' }))
1592 |   expect(array.value).toEqual('')
1593 | 
1594 |   const beNull = attach(form.createField({ name: 'null', initialValue: null }))
1595 |   expect(beNull.value).toEqual(null)
1596 | })
1597 | 
1598 | test('field submit', async () => {
1599 |   const form = attach(
1600 |     createForm({
1601 |       initialValues: {
1602 |         aa: {
1603 |           cc: 'cc',
1604 |         },
1605 |         bb: 'bb',
1606 |       },
1607 |     })
1608 |   )
1609 |   const childForm = attach(
1610 |     form.createObjectField({
1611 |       name: 'aa',
1612 |     })
1613 |   )
1614 |   attach(
1615 |     form.createField({
1616 |       name: 'bb',
1617 |     })
1618 |   )
1619 |   attach(
1620 |     form.createField({
1621 |       name: 'cc',
1622 |       basePath: 'aa',
1623 |     })
1624 |   )
1625 |   const onSubmit = jest.fn()
1626 |   await childForm.submit(onSubmit)
1627 |   expect(onSubmit).toBeCalledWith({
1628 |     cc: 'cc',
1629 |   })
1630 | })
1631 | 
1632 | test('field submit with error', async () => {
1633 |   const form = attach(createForm())
1634 |   const childForm = attach(
1635 |     form.createObjectField({
1636 |       name: 'aa',
1637 |     })
1638 |   )
1639 |   attach(
1640 |     form.createField({
1641 |       name: 'bb',
1642 |       required: true,
1643 |     })
1644 |   )
1645 |   attach(
1646 |     form.createField({
1647 |       name: 'cc',
1648 |       basePath: 'aa',
1649 |       required: true,
1650 |     })
1651 |   )
1652 |   const onSubmit = jest.fn()
1653 |   try {
1654 |     await childForm.submit(onSubmit)
1655 |   } catch (e) {
1656 |     expect(e).not.toBeUndefined()
1657 |   }
1658 |   expect(onSubmit).toBeCalledTimes(0)
1659 | })
1660 | 
1661 | test('initial display with value', () => {
1662 |   const form = attach(createForm())
1663 |   const aa = attach(
1664 |     form.createField({
1665 |       name: 'aa',
1666 |       value: 123,
1667 |       visible: false,
1668 |     })
1669 |   )
1670 |   const bb = attach(
1671 |     form.createField({
1672 |       name: 'bb',
1673 |       value: 123,
1674 |       visible: true,
1675 |     })
1676 |   )
1677 |   const cc = attach(
1678 |     form.createField({
1679 |       name: 'cc',
1680 |       value: 123,
1681 |       hidden: true,
1682 |     })
1683 |   )
1684 |   expect(aa.value).toBeUndefined()
1685 |   expect(aa.visible).toBeFalsy()
1686 |   expect(bb.value).toEqual(123)
1687 |   expect(bb.visible).toBeTruthy()
1688 |   expect(cc.value).toEqual(123)
1689 |   expect(cc.hidden).toBeTruthy()
1690 | })
1691 | 
1692 | test('state depend field visible value', async () => {
1693 |   const form = attach(createForm())
1694 |   const aa = attach(
1695 |     form.createField({
1696 |       name: 'aa',
1697 |     })
1698 |   )
1699 |   const bb = attach(
1700 |     form.createField({
1701 |       name: 'bb',
1702 |       reactions(field) {
1703 |         field.visible = aa.value === '123'
1704 |       },
1705 |     })
1706 |   )
1707 |   const cc = attach(
1708 |     form.createField({
1709 |       name: 'cc',
1710 |       reactions(field) {
1711 |         field.visible = aa.value === '123'
1712 |         field.disabled = !bb.value
1713 |       },
1714 |     })
1715 |   )
1716 |   expect(bb.visible).toBeFalsy()
1717 |   expect(cc.visible).toBeFalsy()
1718 |   expect(cc.disabled).toBeTruthy()
1719 |   aa.value = '123'
1720 |   await sleep(10)
1721 |   expect(bb.visible).toBeTruthy()
1722 |   expect(cc.visible).toBeTruthy()
1723 |   expect(cc.disabled).toBeTruthy()
1724 |   bb.value = '321'
1725 |   await sleep(10)
1726 |   expect(bb.visible).toBeTruthy()
1727 |   expect(cc.visible).toBeTruthy()
1728 |   expect(cc.disabled).toBeFalsy()
1729 |   aa.value = ''
1730 |   await sleep(10)
1731 |   expect(bb.visible).toBeFalsy()
1732 |   expect(cc.visible).toBeFalsy()
1733 |   expect(cc.disabled).toBeTruthy()
1734 |   aa.value = '123'
1735 |   await sleep(10)
1736 |   expect(bb.visible).toBeTruthy()
1737 |   expect(cc.visible).toBeTruthy()
1738 |   expect(cc.disabled).toBeFalsy()
1739 | })
1740 | 
1741 | test('reactions initialValue and value', () => {
1742 |   const form = attach(
1743 |     createForm({
1744 |       values: {
1745 |         aa: {
1746 |           input: '111',
1747 |         },
1748 |       },
1749 |     })
1750 |   )
1751 |   attach(
1752 |     form.createObjectField({
1753 |       name: 'aa',
1754 |       reactions: [
1755 |         (field) => {
1756 |           field.initialValue = {}
1757 |           field.initialValue.input = 123
1758 |         },
1759 |       ],
1760 |     })
1761 |   )
1762 |   attach(
1763 |     form.createField({
1764 |       name: 'input',
1765 |       basePath: 'aa',
1766 |     })
1767 |   )
1768 |   expect(form.values.aa.input).toEqual('111')
1769 | })
1770 | 
1771 | test('field name is length in initialize', () => {
1772 |   const form = attach(createForm())
1773 |   const field = attach(
1774 |     form.createField({
1775 |       name: 'length',
1776 |       initialValue: 123,
1777 |     })
1778 |   )
1779 |   expect(field.value).toEqual(123)
1780 | })
1781 | 
1782 | test('field name is length in dynamic assign', () => {
1783 |   const form = attach(createForm())
1784 |   const field = attach(
1785 |     form.createField({
1786 |       name: 'length',
1787 |     })
1788 |   )
1789 |   field.initialValue = 123
1790 |   expect(field.value).toEqual(123)
1791 | })
1792 | 
1793 | test('nested field modified', async () => {
1794 |   const form = attach(createForm())
1795 |   const obj = attach(
1796 |     form.createObjectField({
1797 |       name: 'object',
1798 |     })
1799 |   )
1800 |   const child = attach(
1801 |     form.createField({
1802 |       name: 'child',
1803 |       basePath: 'object',
1804 |     })
1805 |   )
1806 |   await child.onInput()
1807 |   expect(child.modified).toBeTruthy()
1808 |   expect(child.selfModified).toBeTruthy()
1809 |   expect(obj.modified).toBeTruthy()
1810 |   expect(obj.selfModified).toBeFalsy()
1811 |   expect(form.modified).toBeTruthy()
1812 |   await obj.reset()
1813 |   expect(child.modified).toBeFalsy()
1814 |   expect(child.selfModified).toBeFalsy()
1815 |   expect(obj.modified).toBeFalsy()
1816 |   expect(obj.selfModified).toBeFalsy()
1817 |   expect(form.modified).toBeTruthy()
1818 |   await form.reset()
1819 |   expect(form.modified).toBeFalsy()
1820 | })
1821 | 
1822 | test('field setValidator repeat call', async () => {
1823 |   const form = attach(createForm())
1824 |   const field = attach(
1825 |     form.createField({
1826 |       name: 'normal',
1827 |     })
1828 |   )
1829 | 
1830 |   const validator1 = jest.fn(() => '')
1831 |   const validator2 = jest.fn(() => '')
1832 |   const validator3 = jest.fn(() => '')
1833 | 
1834 |   field.setValidator([validator1, validator2, validator3])
1835 | 
1836 |   await form.validate()
1837 |   expect(validator1).toBeCalledTimes(1)
1838 | })
1839 | 
1840 | test('custom validator to get ctx.field', async () => {
1841 |   const form = attach(createForm())
1842 |   let ctxField = null
1843 |   let ctxForm = null
1844 |   attach(
1845 |     form.createField({
1846 |       name: 'aaa',
1847 |       validator(value, rule, ctx) {
1848 |         ctxField = ctx.field
1849 |         ctxForm = ctx.form
1850 |         return ''
1851 |       },
1852 |     })
1853 |   )
1854 |   await form.submit()
1855 |   expect(!!ctxField).toBeTruthy()
1856 |   expect(!!ctxForm).toBeTruthy()
1857 | })
1858 | 
1859 | test('single direction linkage effect', async () => {
1860 |   const form = attach(createForm())
1861 | 
1862 |   const input1 = form.createField({
1863 |     name: 'input1',
1864 |     reactions: (field: DataField) => {
1865 |       if (!field.selfModified) {
1866 |         return
1867 |       }
1868 |       input2.value = field.value
1869 |     },
1870 |   })
1871 | 
1872 |   const input2 = form.createField({
1873 |     name: 'input2',
1874 |   })
1875 | 
1876 |   await input1.onInput('123')
1877 |   expect(input2.value).toBe('123')
1878 |   await input2.onInput('321')
1879 |   expect(input2.value).toBe('321')
1880 | })
1881 | 
1882 | test('path change will update computed value', () => {
1883 |   const form = attach(createForm())
1884 | 
1885 |   const input = form.createField({
1886 |     name: 'input',
1887 |   })
1888 | 
1889 |   const value = jest.fn()
1890 | 
1891 |   autorun(() => {
1892 |     value(input.value)
1893 |   })
1894 |   batch(() => {
1895 |     input.locate('select')
1896 |     input.value = '123'
1897 |   })
1898 |   expect(value).nthCalledWith(2, '123')
1899 | })
1900 | 
1901 | test('object field reset', async () => {
1902 |   const form = attach(createForm())
1903 | 
1904 |   attach(
1905 |     form.createObjectField({
1906 |       name: 'obj',
1907 |     })
1908 |   )
1909 | 
1910 |   const input = attach(
1911 |     form.createField({
1912 |       name: 'input',
1913 |       basePath: 'obj',
1914 |     })
1915 |   )
1916 | 
1917 |   await form.reset()
1918 |   form.setValues({
1919 |     obj: {
1920 |       input: '123',
1921 |     },
1922 |   })
1923 |   expect(input.value).toBe('123')
1924 | })
1925 | 
1926 | test('field visible default value should work', () => {
1927 |   const form = attach(
1928 |     createForm({
1929 |       effects(form) {
1930 |         onFieldReact('obj.input1', (field) => {
1931 |           field.pattern = 'disabled'
1932 |         })
1933 |         onFieldReact('obj', (field) => {
1934 |           field.visible = form.values.select !== 'none'
1935 |         })
1936 |         onFieldReact('obj.input1', (field) => {
1937 |           if (isField(field)) {
1938 |             field.initialValue = '123'
1939 |           }
1940 |         })
1941 |         onFieldReact('obj.input2', (field) => {
1942 |           if (isField(field)) {
1943 |             field.value = form.values.select
1944 |           }
1945 |         })
1946 |       },
1947 |     })
1948 |   )
1949 | 
1950 |   const select = attach(
1951 |     form.createField({
1952 |       name: 'select',
1953 |     })
1954 |   )
1955 | 
1956 |   attach(
1957 |     form.createObjectField({
1958 |       name: 'obj',
1959 |     })
1960 |   )
1961 | 
1962 |   attach(
1963 |     form.createField({
1964 |       name: 'input1',
1965 |       basePath: 'obj',
1966 |     })
1967 |   )
1968 | 
1969 |   attach(
1970 |     form.createField({
1971 |       name: 'input2',
1972 |       basePath: 'obj',
1973 |     })
1974 |   )
1975 | 
1976 |   select.value = 'none'
1977 |   expect(form.values.obj?.input1).toBeUndefined()
1978 |   select.value = 'visible'
1979 |   expect(form.values.obj.input1).toBe('123')
1980 | })
1981 | 
1982 | test('query value with sibling path syntax', () => {
1983 |   const form = attach(createForm())
1984 |   const fn = jest.fn()
1985 |   attach(
1986 |     form.createVoidField({
1987 |       name: 'void',
1988 |     })
1989 |   )
1990 |   attach(
1991 |     form.createObjectField({
1992 |       name: 'obj',
1993 |       basePath: 'void',
1994 |     })
1995 |   )
1996 |   attach(
1997 |     form.createField({
1998 |       name: 'input',
1999 |       basePath: 'void.obj',
2000 |       reactions: [
2001 |         (field) => {
2002 |           fn(
2003 |             field.query('.textarea').value(),
2004 |             field.query('.textarea').initialValue()
2005 |           )
2006 |         },
2007 |       ],
2008 |     })
2009 |   )
2010 |   const textarea = attach(
2011 |     form.createField({
2012 |       name: 'textarea',
2013 |       basePath: 'void.obj',
2014 |       initialValue: 'aaa',
2015 |     })
2016 |   )
2017 |   textarea.value = '123'
2018 |   expect(fn).toBeCalledWith('123', 'aaa')
2019 | })
2020 | 
2021 | test('relative query with void field', () => {
2022 |   const form = attach(createForm())
2023 |   attach(
2024 |     form.createVoidField({
2025 |       name: 'void',
2026 |     })
2027 |   )
2028 |   const aa = attach(
2029 |     form.createField({
2030 |       name: 'aa',
2031 |       basePath: 'void',
2032 |     })
2033 |   )
2034 |   attach(
2035 |     form.createVoidField({
2036 |       name: 'mm',
2037 |     })
2038 |   )
2039 |   const bb = attach(
2040 |     form.createField({
2041 |       name: 'bb',
2042 |       basePath: 'mm',
2043 |     })
2044 |   )
2045 | 
2046 |   expect(bb.query('.aa').take()).toBe(aa)
2047 | })
2048 | 
2049 | test('empty string or number or null value need rewrite default value', () => {
2050 |   const form = attach(
2051 |     createForm<any>({
2052 |       values: {
2053 |         aa: '',
2054 |         bb: 0,
2055 |         ee: null,
2056 |       },
2057 |     })
2058 |   )
2059 |   attach(
2060 |     form.createField({
2061 |       name: 'aa',
2062 |       initialValue: 'test',
2063 |     })
2064 |   )
2065 |   attach(
2066 |     form.createField({
2067 |       name: 'bb',
2068 |       initialValue: 123,
2069 |     })
2070 |   )
2071 |   attach(
2072 |     form.createField({
2073 |       name: 'cc',
2074 |       initialValue: 'test',
2075 |     })
2076 |   )
2077 |   attach(
2078 |     form.createField({
2079 |       name: 'dd',
2080 |       initialValue: 123,
2081 |     })
2082 |   )
2083 |   attach(
2084 |     form.createField({
2085 |       name: 'ee',
2086 |       initialValue: 'test',
2087 |     })
2088 |   )
2089 |   expect(form.values.aa).toEqual('')
2090 |   expect(form.values.bb).toEqual(0)
2091 |   expect(form.values.cc).toEqual('test')
2092 |   expect(form.values.dd).toEqual(123)
2093 |   expect(form.values.ee).toEqual(null)
2094 | })
2095 | 
2096 | test('destroy field need auto remove initialValues', () => {
2097 |   const form = attach(createForm<any>())
2098 |   const aa = attach(
2099 |     form.createField({
2100 |       name: 'aa',
2101 |       initialValue: 'test',
2102 |     })
2103 |   )
2104 |   expect(form.initialValues.aa).toEqual('test')
2105 |   expect(form.values.aa).toEqual('test')
2106 |   aa.destroy()
2107 |   expect(form.initialValues.aa).toBeUndefined()
2108 |   expect(form.values.aa).toBeUndefined()
2109 | })
2110 | 
2111 | test('validateFirst', async () => {
2112 |   const form = attach(
2113 |     createForm<any>({
2114 |       validateFirst: false,
2115 |     })
2116 |   )
2117 |   const aaValidate = jest.fn(() => 'aaError')
2118 |   const aa = attach(
2119 |     form.createField({
2120 |       name: 'aa',
2121 |       validateFirst: true,
2122 |       validator: [aaValidate, aaValidate],
2123 |     })
2124 |   )
2125 |   await aa.onInput('aa')
2126 |   const bbValidate = jest.fn(() => 'bbError')
2127 |   const bb = attach(
2128 |     form.createField({
2129 |       name: 'bb',
2130 |       validator: [bbValidate, bbValidate],
2131 |       validateFirst: false,
2132 |     })
2133 |   )
2134 |   await bb.onInput('bb')
2135 |   const ccValidate = jest.fn(() => 'ccError')
2136 |   const cc = attach(
2137 |     form.createField({
2138 |       name: 'cc',
2139 |       validator: [ccValidate, ccValidate],
2140 |     })
2141 |   )
2142 |   await cc.onInput('cc')
2143 | 
2144 |   expect(aaValidate).toBeCalledTimes(1)
2145 |   expect(bbValidate).toBeCalledTimes(2)
2146 |   expect(ccValidate).toBeCalledTimes(2)
2147 | })
2148 | 
2149 | test('reactions should not be triggered when field destroyed', () => {
2150 |   const form = attach(createForm<any>())
2151 |   const handler = jest.fn()
2152 |   const obs = observable({ bb: 123 })
2153 |   const aa = attach(
2154 |     form.createField({
2155 |       name: 'aa',
2156 |       initialValue: 'test',
2157 |       reactions() {
2158 |         handler(obs.bb)
2159 |       },
2160 |     })
2161 |   )
2162 |   obs.bb = 321
2163 |   aa.destroy()
2164 |   obs.bb = 111
2165 |   expect(handler).toBeCalledTimes(2)
2166 | })
2167 | 
2168 | test('parent readPretty will overwrite self disabled or readOnly', () => {
2169 |   const form = attach(
2170 |     createForm<any>({
2171 |       readPretty: true,
2172 |     })
2173 |   )
2174 |   const aa = attach(
2175 |     form.createField({
2176 |       name: 'aa',
2177 |       initialValue: 'test',
2178 |       disabled: true,
2179 |     })
2180 |   )
2181 |   const bb = attach(
2182 |     form.createField({
2183 |       name: 'bb',
2184 |       initialValue: 'test',
2185 |       editable: true,
2186 |     })
2187 |   )
2188 |   expect(aa.pattern).toBe('readPretty')
2189 |   expect(bb.pattern).toBe('editable')
2190 | })
2191 | 
2192 | test('conflict name for errors filter', async () => {
2193 |   const form = attach(createForm<any>())
2194 |   const aa = attach(
2195 |     form.createField({
2196 |       name: 'aa',
2197 |       required: true,
2198 |     })
2199 |   )
2200 |   const aa1 = attach(
2201 |     form.createField({
2202 |       name: 'aa1',
2203 |       required: true,
2204 |     })
2205 |   )
2206 | 
2207 |   await aa1.onInput('')
2208 |   expect(aa.invalid).toBe(false)
2209 | })
2210 | 
2211 | test('field destroyed can not be assign value', () => {
2212 |   const form = attach(createForm<any>())
2213 |   const aa = attach(
2214 |     form.createField({
2215 |       name: 'aa',
2216 |     })
2217 |   )
2218 |   aa.destroy()
2219 |   aa.initialValue = 222
2220 |   aa.value = 111
2221 |   expect(form.values).toEqual({})
2222 |   expect(form.initialValues).toEqual({})
2223 | })
2224 | 
2225 | test('onInput could pass value with target', async () => {
2226 |   const form = attach(createForm<any>())
2227 |   const aa = attach(
2228 |     form.createField({
2229 |       name: 'aa',
2230 |     })
2231 |   )
2232 |   await aa.onInput({
2233 |     target: '123',
2234 |   })
2235 |   expect(aa.value).toEqual({ target: '123' })
2236 | })
2237 | 
2238 | test('field destroyed or display none should not be assign value from patch initialValues', () => {
2239 |   const form = attach(createForm())
2240 |   const aa = attach(
2241 |     form.createField({
2242 |       name: 'aa',
2243 |       display: 'none',
2244 |     })
2245 |   )
2246 | 
2247 |   aa.initialValue = '123'
2248 | 
2249 |   expect(form.values).toEqual({})
2250 | 
2251 |   aa.display = 'visible'
2252 | 
2253 |   expect(aa.value).toBe('123')
2254 |   expect(form.values).toEqual({ aa: '123' })
2255 | })
2256 | 
2257 | test('onFieldReact with field destroyed', () => {
2258 |   const fn = jest.fn()
2259 |   const obs = observable<any>({ value: 123 })
2260 |   const form = attach(
2261 |     createForm({
2262 |       effects() {
2263 |         onFieldReact('aa', () => {
2264 |           fn(obs.value)
2265 |         })
2266 |       },
2267 |     })
2268 |   )
2269 |   const aa = attach(
2270 |     form.createField({
2271 |       name: 'aa',
2272 |     })
2273 |   )
2274 |   obs.value = '321'
2275 |   expect(fn).toBeCalledTimes(2)
2276 |   aa.destroy()
2277 |   obs.value = '111'
2278 |   expect(fn).toBeCalledTimes(2)
2279 | })
2280 | 
2281 | test('field actions', () => {
2282 |   const form = attach(createForm())
2283 |   const aa = attach(
2284 |     form.createField({
2285 |       name: 'aa',
2286 |     })
2287 |   )
2288 |   expect(aa.actions).toEqual({})
2289 |   aa.inject({
2290 |     test: () => 123,
2291 |   })
2292 |   expect(aa.invoke('test')).toEqual(123)
2293 |   aa.inject({
2294 |     test: () => 321,
2295 |   })
2296 |   expect(aa.invoke('test')).toEqual(321)
2297 | })
2298 | 
2299 | test('field hidden value', () => {
2300 |   const form = attach(createForm())
2301 |   const aa = attach(
2302 |     form.createField({
2303 |       name: 'aa',
2304 |       hidden: true,
2305 |       initialValue: '123',
2306 |     })
2307 |   )
2308 |   expect(form.values).toEqual({ aa: '123' })
2309 | 
2310 |   const objectField = attach(
2311 |     form.createObjectField({
2312 |       name: 'object',
2313 |       hidden: true,
2314 |     })
2315 |   )
2316 |   const arrayField = attach(
2317 |     form.createArrayField({
2318 |       name: 'array',
2319 |       hidden: true,
2320 |     })
2321 |   )
2322 | 
2323 |   aa.setDisplay('none')
2324 |   objectField.setDisplay('none')
2325 |   arrayField.setDisplay('none')
2326 |   expect(aa.value).toBeUndefined()
2327 |   expect(objectField.value).toBeUndefined()
2328 |   expect(arrayField.value).toBeUndefined()
2329 | 
2330 |   aa.setDisplay('hidden')
2331 |   objectField.setDisplay('hidden')
2332 |   arrayField.setDisplay('hidden')
2333 |   expect(aa.value).toEqual('123')
2334 |   expect(objectField.value).toEqual({})
2335 |   expect(arrayField.value).toEqual([])
2336 | })
2337 | 
2338 | test('field destructor path with display none', () => {
2339 |   const form = attach(createForm())
2340 |   const aa = attach(
2341 |     form.createArrayField({
2342 |       name: '[aa,bb]',
2343 |     })
2344 |   )
2345 |   aa.setDisplay('none')
2346 |   expect(form.values).toEqual({})
2347 |   expect(aa.value).toEqual([])
2348 | })
2349 | 
2350 | test('onInput should ignore HTMLInputEvent propagation', async () => {
2351 |   const form = attach(createForm<any>())
2352 |   const mockHTMLInput = { value: '321' }
2353 |   const mockDomEvent = { target: mockHTMLInput, currentTarget: mockHTMLInput }
2354 |   const aa = attach(
2355 |     form.createField({
2356 |       name: 'aa',
2357 |     })
2358 |   )
2359 |   await aa.onInput(mockDomEvent)
2360 |   expect(aa.value).toEqual('321')
2361 | 
2362 |   await aa.onInput({ target: { value: '2' }, currentTarget: { value: '4' } })
2363 |   expect(aa.value).toEqual('321')
2364 | 
2365 |   // currentTarget is undefined, skip ignore
2366 |   await aa.onInput({ target: { value: '123' } })
2367 |   expect(aa.value).toEqual('123')
2368 | })
2369 | 
2370 | test('onFocus and onBlur with invalid target value', async () => {
2371 |   const form = attach(createForm<any>())
2372 |   const field = attach(
2373 |     form.createField({
2374 |       name: 'aa',
2375 |       validateFirst: true,
2376 |       value: '111',
2377 |       validator: [
2378 |         {
2379 |           triggerType: 'onFocus',
2380 |           format: 'date',
2381 |         },
2382 |         {
2383 |           triggerType: 'onBlur',
2384 |           format: 'url',
2385 |         },
2386 |       ],
2387 |     })
2388 |   )
2389 | 
2390 |   await field.onFocus({ target: {} })
2391 |   expect(field.selfErrors).toEqual([])
2392 |   await field.onBlur({ target: {} })
2393 |   expect(field.selfErrors).toEqual([])
2394 | 
2395 |   await field.onFocus()
2396 |   expect(field.selfErrors).toEqual([
2397 |     'The field value is not a valid date format',
2398 |   ])
2399 |   await field.onBlur()
2400 |   expect(field.selfErrors).toEqual([
2401 |     'The field value is not a valid date format',
2402 |     'The field value is a invalid url',
2403 |   ])
2404 | })
2405 | 
2406 | test('validatePattern and validateDisplay', async () => {
2407 |   const form = attach(
2408 |     createForm<any>({
2409 |       validatePattern: ['editable'],
2410 |       validateDisplay: ['visible'],
2411 |     })
2412 |   )
2413 |   const field1 = attach(
2414 |     form.createField({
2415 |       name: 'a',
2416 |       required: true,
2417 |     })
2418 |   )
2419 |   const field2 = attach(
2420 |     form.createField({
2421 |       name: 'b',
2422 |       required: true,
2423 |       validatePattern: ['readOnly'],
2424 |       validateDisplay: ['hidden'],
2425 |     })
2426 |   )
2427 |   const field3 = attach(
2428 |     form.createField({
2429 |       name: 'c',
2430 |       required: true,
2431 |       validatePattern: ['readOnly', 'editable'],
2432 |       validateDisplay: ['hidden', 'visible'],
2433 |     })
2434 |   )
2435 | 
2436 |   try {
2437 |     await form.validate()
2438 |   } catch {}
2439 |   expect(field1.selfErrors.length).toBe(1)
2440 |   expect(field2.selfErrors.length).toBe(0)
2441 |   expect(field3.selfErrors.length).toBe(1)
2442 | 
2443 |   form.setPattern('readOnly')
2444 |   form.setDisplay('hidden')
2445 |   try {
2446 |     await form.validate()
2447 |   } catch {}
2448 |   expect(field1.selfErrors.length).toBe(0)
2449 |   expect(field2.selfErrors.length).toBe(1)
2450 |   expect(field3.selfErrors.length).toBe(1)
2451 | })
2452 | 
```
Page 51/52FirstPrevNextLast