This is page 36 of 52. Use http://codebase.md/alibaba/formily?lines=true&page={x} to view the full context. # Directory Structure ``` ├── .all-contributorsrc ├── .codecov.yml ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .github │ ├── CONTRIBUTING.md │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE │ │ └── config.yml │ ├── PULL_REQUEST_TEMPLATE.md │ └── workflows │ ├── check-pr-title.yml │ ├── ci.yml │ ├── commitlint.yml │ ├── issue-open-check.yml │ ├── package-size.yml │ └── pr-welcome.yml ├── .gitignore ├── .prettierrc.js ├── .umirc.js ├── .vscode │ └── cspell.json ├── .yarnrc ├── CHANGELOG.md ├── commitlint.config.js ├── devtools │ ├── .eslintrc │ └── chrome-extension │ ├── .npmignore │ ├── assets │ │ └── img │ │ ├── loading.svg │ │ └── logo │ │ ├── 128x128.png │ │ ├── 16x16.png │ │ ├── 38x38.png │ │ ├── 48x48.png │ │ ├── error.png │ │ ├── gray.png │ │ └── scalable.png │ ├── config │ │ ├── webpack.base.ts │ │ ├── webpack.dev.ts │ │ └── webpack.prod.ts │ ├── LICENSE.md │ ├── package.json │ ├── src │ │ ├── app │ │ │ ├── components │ │ │ │ ├── FieldTree.tsx │ │ │ │ ├── filter.ts │ │ │ │ ├── LeftPanel.tsx │ │ │ │ ├── RightPanel.tsx │ │ │ │ ├── SearchBox.tsx │ │ │ │ └── Tabs.tsx │ │ │ ├── demo.tsx │ │ │ └── index.tsx │ │ └── extension │ │ ├── backend.ts │ │ ├── background.ts │ │ ├── content.ts │ │ ├── devpanel.tsx │ │ ├── devtools.tsx │ │ ├── inject.ts │ │ ├── manifest.json │ │ ├── popup.tsx │ │ └── views │ │ ├── devpanel.ejs │ │ ├── devtools.ejs │ │ └── popup.ejs │ ├── tsconfig.build.json │ └── tsconfig.json ├── docs │ ├── functions │ │ ├── contributors.ts │ │ └── npm-search.ts │ ├── guide │ │ ├── advanced │ │ │ ├── async.md │ │ │ ├── async.zh-CN.md │ │ │ ├── build.md │ │ │ ├── build.zh-CN.md │ │ │ ├── business-logic.md │ │ │ ├── business-logic.zh-CN.md │ │ │ ├── calculator.md │ │ │ ├── calculator.zh-CN.md │ │ │ ├── controlled.md │ │ │ ├── controlled.zh-CN.md │ │ │ ├── custom.md │ │ │ ├── custom.zh-CN.md │ │ │ ├── destructor.md │ │ │ ├── destructor.zh-CN.md │ │ │ ├── input.less │ │ │ ├── layout.md │ │ │ ├── layout.zh-CN.md │ │ │ ├── linkages.md │ │ │ ├── linkages.zh-CN.md │ │ │ ├── validate.md │ │ │ └── validate.zh-CN.md │ │ ├── contribution.md │ │ ├── contribution.zh-CN.md │ │ ├── form-builder.md │ │ ├── form-builder.zh-CN.md │ │ ├── index.md │ │ ├── index.zh-CN.md │ │ ├── issue-helper.md │ │ ├── issue-helper.zh-CN.md │ │ ├── learn-formily.md │ │ ├── learn-formily.zh-CN.md │ │ ├── quick-start.md │ │ ├── quick-start.zh-CN.md │ │ ├── scenes │ │ │ ├── dialog-drawer.md │ │ │ ├── dialog-drawer.zh-CN.md │ │ │ ├── edit-detail.md │ │ │ ├── edit-detail.zh-CN.md │ │ │ ├── index.less │ │ │ ├── login-register.md │ │ │ ├── login-register.zh-CN.md │ │ │ ├── more.md │ │ │ ├── more.zh-CN.md │ │ │ ├── query-list.md │ │ │ ├── query-list.zh-CN.md │ │ │ ├── step-form.md │ │ │ ├── step-form.zh-CN.md │ │ │ ├── tab-form.md │ │ │ ├── tab-form.zh-CN.md │ │ │ └── VerifyCode.tsx │ │ ├── upgrade.md │ │ └── upgrade.zh-CN.md │ ├── index.md │ ├── index.zh-CN.md │ └── site │ ├── Contributors.less │ ├── Contributors.tsx │ ├── QrCode.less │ ├── QrCode.tsx │ ├── Section.less │ ├── Section.tsx │ └── styles.less ├── global.config.ts ├── jest.config.js ├── lerna.json ├── LICENSE.md ├── package.json ├── packages │ ├── .eslintrc │ ├── antd │ │ ├── __tests__ │ │ │ ├── moment.spec.ts │ │ │ └── sideEffects.spec.ts │ │ ├── .npmignore │ │ ├── .umirc.js │ │ ├── build-style.ts │ │ ├── create-style.ts │ │ ├── docs │ │ │ ├── components │ │ │ │ ├── ArrayCards.md │ │ │ │ ├── ArrayCards.zh-CN.md │ │ │ │ ├── ArrayCollapse.md │ │ │ │ ├── ArrayCollapse.zh-CN.md │ │ │ │ ├── ArrayItems.md │ │ │ │ ├── ArrayItems.zh-CN.md │ │ │ │ ├── ArrayTable.md │ │ │ │ ├── ArrayTable.zh-CN.md │ │ │ │ ├── ArrayTabs.md │ │ │ │ ├── ArrayTabs.zh-CN.md │ │ │ │ ├── Cascader.md │ │ │ │ ├── Cascader.zh-CN.md │ │ │ │ ├── Checkbox.md │ │ │ │ ├── Checkbox.zh-CN.md │ │ │ │ ├── DatePicker.md │ │ │ │ ├── DatePicker.zh-CN.md │ │ │ │ ├── Editable.md │ │ │ │ ├── Editable.zh-CN.md │ │ │ │ ├── Form.md │ │ │ │ ├── Form.zh-CN.md │ │ │ │ ├── FormButtonGroup.md │ │ │ │ ├── FormButtonGroup.zh-CN.md │ │ │ │ ├── FormCollapse.md │ │ │ │ ├── FormCollapse.zh-CN.md │ │ │ │ ├── FormDialog.md │ │ │ │ ├── FormDialog.zh-CN.md │ │ │ │ ├── FormDrawer.md │ │ │ │ ├── FormDrawer.zh-CN.md │ │ │ │ ├── FormGrid.md │ │ │ │ ├── FormGrid.zh-CN.md │ │ │ │ ├── FormItem.md │ │ │ │ ├── FormItem.zh-CN.md │ │ │ │ ├── FormLayout.md │ │ │ │ ├── FormLayout.zh-CN.md │ │ │ │ ├── FormStep.md │ │ │ │ ├── FormStep.zh-CN.md │ │ │ │ ├── FormTab.md │ │ │ │ ├── FormTab.zh-CN.md │ │ │ │ ├── index.md │ │ │ │ ├── index.zh-CN.md │ │ │ │ ├── Input.md │ │ │ │ ├── Input.zh-CN.md │ │ │ │ ├── NumberPicker.md │ │ │ │ ├── NumberPicker.zh-CN.md │ │ │ │ ├── Password.md │ │ │ │ ├── Password.zh-CN.md │ │ │ │ ├── PreviewText.md │ │ │ │ ├── PreviewText.zh-CN.md │ │ │ │ ├── Radio.md │ │ │ │ ├── Radio.zh-CN.md │ │ │ │ ├── Reset.md │ │ │ │ ├── Reset.zh-CN.md │ │ │ │ ├── Select.md │ │ │ │ ├── Select.zh-CN.md │ │ │ │ ├── SelectTable.md │ │ │ │ ├── SelectTable.zh-CN.md │ │ │ │ ├── Space.md │ │ │ │ ├── Space.zh-CN.md │ │ │ │ ├── Submit.md │ │ │ │ ├── Submit.zh-CN.md │ │ │ │ ├── Switch.md │ │ │ │ ├── Switch.zh-CN.md │ │ │ │ ├── TimePicker.md │ │ │ │ ├── TimePicker.zh-CN.md │ │ │ │ ├── Transfer.md │ │ │ │ ├── Transfer.zh-CN.md │ │ │ │ ├── TreeSelect.md │ │ │ │ ├── TreeSelect.zh-CN.md │ │ │ │ ├── Upload.md │ │ │ │ └── Upload.zh-CN.md │ │ │ ├── index.md │ │ │ └── index.zh-CN.md │ │ ├── LICENSE.md │ │ ├── package.json │ │ ├── README.md │ │ ├── rollup.config.js │ │ ├── src │ │ │ ├── __builtins__ │ │ │ │ ├── hooks │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── useClickAway.ts │ │ │ │ │ └── usePrefixCls.ts │ │ │ │ ├── index.ts │ │ │ │ ├── loading.ts │ │ │ │ ├── moment.ts │ │ │ │ ├── pickDataProps.ts │ │ │ │ ├── portal.tsx │ │ │ │ ├── render.ts │ │ │ │ └── sort.tsx │ │ │ ├── array-base │ │ │ │ ├── index.tsx │ │ │ │ ├── style.less │ │ │ │ └── style.ts │ │ │ ├── array-cards │ │ │ │ ├── index.tsx │ │ │ │ ├── style.less │ │ │ │ └── style.ts │ │ │ ├── array-collapse │ │ │ │ ├── index.tsx │ │ │ │ ├── style.less │ │ │ │ └── style.ts │ │ │ ├── array-items │ │ │ │ ├── index.tsx │ │ │ │ ├── style.less │ │ │ │ └── style.ts │ │ │ ├── array-table │ │ │ │ ├── index.tsx │ │ │ │ ├── style.less │ │ │ │ └── style.ts │ │ │ ├── array-tabs │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── cascader │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── checkbox │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── date-picker │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── editable │ │ │ │ ├── index.tsx │ │ │ │ ├── style.less │ │ │ │ └── style.ts │ │ │ ├── form │ │ │ │ ├── index.tsx │ │ │ │ ├── style.less │ │ │ │ └── style.ts │ │ │ ├── form-button-group │ │ │ │ ├── index.tsx │ │ │ │ ├── style.less │ │ │ │ └── style.ts │ │ │ ├── form-collapse │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── form-dialog │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── form-drawer │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── form-grid │ │ │ │ ├── index.tsx │ │ │ │ ├── style.less │ │ │ │ └── style.ts │ │ │ ├── form-item │ │ │ │ ├── animation.less │ │ │ │ ├── grid.less │ │ │ │ ├── index.tsx │ │ │ │ ├── style.less │ │ │ │ └── style.ts │ │ │ ├── form-layout │ │ │ │ ├── index.tsx │ │ │ │ ├── style.less │ │ │ │ ├── style.ts │ │ │ │ └── useResponsiveFormLayout.ts │ │ │ ├── form-step │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── form-tab │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── index.ts │ │ │ ├── input │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── number-picker │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── password │ │ │ │ ├── index.tsx │ │ │ │ ├── PasswordStrength.tsx │ │ │ │ └── style.ts │ │ │ ├── preview-text │ │ │ │ ├── index.tsx │ │ │ │ ├── style.less │ │ │ │ └── style.ts │ │ │ ├── radio │ │ │ │ ├── index.tsx │ │ │ │ ├── style.less │ │ │ │ └── style.ts │ │ │ ├── reset │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── select │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── select-table │ │ │ │ ├── index.tsx │ │ │ │ ├── style.less │ │ │ │ ├── style.ts │ │ │ │ ├── useCheckSlackly.tsx │ │ │ │ ├── useFilterOptions.tsx │ │ │ │ ├── useFlatOptions.tsx │ │ │ │ ├── useSize.tsx │ │ │ │ ├── useTitleAddon.tsx │ │ │ │ └── utils.ts │ │ │ ├── space │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── style.less │ │ │ ├── style.ts │ │ │ ├── submit │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── switch │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── time-picker │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── transfer │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── tree-select │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ └── upload │ │ │ ├── index.tsx │ │ │ ├── placeholder.ts │ │ │ └── style.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── benchmark │ │ ├── .npmignore │ │ ├── .umirc.js │ │ ├── LICENSE.md │ │ ├── package.json │ │ ├── README.md │ │ ├── src │ │ │ └── index.tsx │ │ ├── template.ejs │ │ ├── tsconfig.build.json │ │ ├── tsconfig.json │ │ ├── webpack.base.ts │ │ ├── webpack.dev.ts │ │ └── webpack.prod.ts │ ├── core │ │ ├── .npmignore │ │ ├── .umirc.js │ │ ├── docs │ │ │ ├── api │ │ │ │ ├── entry │ │ │ │ │ ├── ActionResponse.less │ │ │ │ │ ├── ActionResponse.tsx │ │ │ │ │ ├── createForm.md │ │ │ │ │ ├── createForm.zh-CN.md │ │ │ │ │ ├── FieldEffectHooks.md │ │ │ │ │ ├── FieldEffectHooks.zh-CN.md │ │ │ │ │ ├── FormChecker.md │ │ │ │ │ ├── FormChecker.zh-CN.md │ │ │ │ │ ├── FormEffectHooks.md │ │ │ │ │ ├── FormEffectHooks.zh-CN.md │ │ │ │ │ ├── FormHooksAPI.md │ │ │ │ │ ├── FormHooksAPI.zh-CN.md │ │ │ │ │ ├── FormPath.md │ │ │ │ │ ├── FormPath.zh-CN.md │ │ │ │ │ ├── FormValidatorRegistry.md │ │ │ │ │ └── FormValidatorRegistry.zh-CN.md │ │ │ │ └── models │ │ │ │ ├── ArrayField.md │ │ │ │ ├── ArrayField.zh-CN.md │ │ │ │ ├── Field.md │ │ │ │ ├── Field.zh-CN.md │ │ │ │ ├── Form.md │ │ │ │ ├── Form.zh-CN.md │ │ │ │ ├── ObjectField.md │ │ │ │ ├── ObjectField.zh-CN.md │ │ │ │ ├── Query.md │ │ │ │ ├── Query.zh-CN.md │ │ │ │ ├── VoidField.md │ │ │ │ └── VoidField.zh-CN.md │ │ │ ├── guide │ │ │ │ ├── architecture.md │ │ │ │ ├── architecture.zh-CN.md │ │ │ │ ├── field.md │ │ │ │ ├── field.zh-CN.md │ │ │ │ ├── form.md │ │ │ │ ├── form.zh-CN.md │ │ │ │ ├── index.md │ │ │ │ ├── index.zh-CN.md │ │ │ │ ├── mvvm.md │ │ │ │ ├── mvvm.zh-CN.md │ │ │ │ ├── values.md │ │ │ │ └── values.zh-CN.md │ │ │ ├── index.md │ │ │ └── index.zh-CN.md │ │ ├── LICENSE.md │ │ ├── package.json │ │ ├── README.md │ │ ├── rollup.config.js │ │ ├── src │ │ │ ├── __tests__ │ │ │ │ ├── array.spec.ts │ │ │ │ ├── effects.spec.ts │ │ │ │ ├── externals.spec.ts │ │ │ │ ├── field.spec.ts │ │ │ │ ├── form.spec.ts │ │ │ │ ├── graph.spec.ts │ │ │ │ ├── heart.spec.ts │ │ │ │ ├── internals.spec.ts │ │ │ │ ├── lifecycle.spec.ts │ │ │ │ ├── object.spec.ts │ │ │ │ ├── shared.ts │ │ │ │ └── void.spec.ts │ │ │ ├── effects │ │ │ │ ├── index.ts │ │ │ │ ├── onFieldEffects.ts │ │ │ │ └── onFormEffects.ts │ │ │ ├── global.d.ts │ │ │ ├── index.ts │ │ │ ├── models │ │ │ │ ├── ArrayField.ts │ │ │ │ ├── BaseField.ts │ │ │ │ ├── Field.ts │ │ │ │ ├── Form.ts │ │ │ │ ├── Graph.ts │ │ │ │ ├── Heart.ts │ │ │ │ ├── index.ts │ │ │ │ ├── LifeCycle.ts │ │ │ │ ├── ObjectField.ts │ │ │ │ ├── Query.ts │ │ │ │ ├── types.ts │ │ │ │ └── VoidField.ts │ │ │ ├── shared │ │ │ │ ├── checkers.ts │ │ │ │ ├── constants.ts │ │ │ │ ├── effective.ts │ │ │ │ ├── externals.ts │ │ │ │ └── internals.ts │ │ │ └── types.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── element │ │ ├── .npmignore │ │ ├── build-style.ts │ │ ├── create-style.ts │ │ ├── docs │ │ │ ├── .vuepress │ │ │ │ ├── components │ │ │ │ │ ├── createCodeSandBox.js │ │ │ │ │ ├── dumi-previewer.vue │ │ │ │ │ └── highlight.js │ │ │ │ ├── config.js │ │ │ │ ├── enhanceApp.js │ │ │ │ ├── styles │ │ │ │ │ └── index.styl │ │ │ │ └── util.js │ │ │ ├── demos │ │ │ │ ├── guide │ │ │ │ │ ├── array-cards │ │ │ │ │ │ ├── effects-json-schema.vue │ │ │ │ │ │ ├── effects-markup-schema.vue │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ └── markup-schema.vue │ │ │ │ │ ├── array-collapse │ │ │ │ │ │ ├── effects-json-schema.vue │ │ │ │ │ │ ├── effects-markup-schema.vue │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ └── markup-schema.vue │ │ │ │ │ ├── array-items │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ └── markup-schema.vue │ │ │ │ │ ├── array-table │ │ │ │ │ │ ├── effects-json-schema.vue │ │ │ │ │ │ ├── effects-markup-schema.vue │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ └── markup-schema.vue │ │ │ │ │ ├── array-tabs │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ └── markup-schema.vue │ │ │ │ │ ├── cascader │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── checkbox │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── date-picker │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── editable │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── form-button-group.vue │ │ │ │ │ ├── form-collapse │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ └── markup-schema.vue │ │ │ │ │ ├── form-dialog │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── form-drawer │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── form-grid │ │ │ │ │ │ ├── form.vue │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── native.vue │ │ │ │ │ ├── form-item │ │ │ │ │ │ ├── bordered-none.vue │ │ │ │ │ │ ├── common.vue │ │ │ │ │ │ ├── feedback.vue │ │ │ │ │ │ ├── inset.vue │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ ├── size.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── form-layout │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── form-step │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ └── markup-schema.vue │ │ │ │ │ ├── form-tab │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ └── markup-schema.vue │ │ │ │ │ ├── form.vue │ │ │ │ │ ├── input │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── input-number │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── password │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── preview-text │ │ │ │ │ │ ├── base.vue │ │ │ │ │ │ └── extend.vue │ │ │ │ │ ├── radio │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── reset │ │ │ │ │ │ ├── base.vue │ │ │ │ │ │ ├── force.vue │ │ │ │ │ │ └── validate.vue │ │ │ │ │ ├── select │ │ │ │ │ │ ├── json-schema-async.vue │ │ │ │ │ │ ├── json-schema-sync.vue │ │ │ │ │ │ ├── markup-schema-async-search.vue │ │ │ │ │ │ ├── markup-schema-async.vue │ │ │ │ │ │ ├── markup-schema-sync.vue │ │ │ │ │ │ ├── template-async.vue │ │ │ │ │ │ └── template-sync.vue │ │ │ │ │ ├── space │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── submit │ │ │ │ │ │ ├── base.vue │ │ │ │ │ │ └── loading.vue │ │ │ │ │ ├── switch │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── time-picker │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── transfer │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ └── upload │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ └── template.vue │ │ │ │ └── index.vue │ │ │ ├── guide │ │ │ │ ├── array-cards.md │ │ │ │ ├── array-collapse.md │ │ │ │ ├── array-items.md │ │ │ │ ├── array-table.md │ │ │ │ ├── array-tabs.md │ │ │ │ ├── cascader.md │ │ │ │ ├── checkbox.md │ │ │ │ ├── date-picker.md │ │ │ │ ├── editable.md │ │ │ │ ├── form-button-group.md │ │ │ │ ├── form-collapse.md │ │ │ │ ├── form-dialog.md │ │ │ │ ├── form-drawer.md │ │ │ │ ├── form-grid.md │ │ │ │ ├── form-item.md │ │ │ │ ├── form-layout.md │ │ │ │ ├── form-step.md │ │ │ │ ├── form-tab.md │ │ │ │ ├── form.md │ │ │ │ ├── index.md │ │ │ │ ├── input-number.md │ │ │ │ ├── input.md │ │ │ │ ├── password.md │ │ │ │ ├── preview-text.md │ │ │ │ ├── radio.md │ │ │ │ ├── reset.md │ │ │ │ ├── select.md │ │ │ │ ├── space.md │ │ │ │ ├── submit.md │ │ │ │ ├── switch.md │ │ │ │ ├── time-picker.md │ │ │ │ ├── transfer.md │ │ │ │ └── upload.md │ │ │ └── README.md │ │ ├── package.json │ │ ├── README.md │ │ ├── rollup.config.js │ │ ├── src │ │ │ ├── __builtins__ │ │ │ │ ├── configs │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── shared │ │ │ │ │ ├── create-context.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── loading.ts │ │ │ │ │ ├── portal.ts │ │ │ │ │ ├── resolve-component.ts │ │ │ │ │ ├── transform-component.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ └── utils.ts │ │ │ │ └── styles │ │ │ │ └── common.scss │ │ │ ├── array-base │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ └── style.ts │ │ │ ├── array-cards │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ └── style.ts │ │ │ ├── array-collapse │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ └── style.ts │ │ │ ├── array-items │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ └── style.ts │ │ │ ├── array-table │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ └── style.ts │ │ │ ├── array-tabs │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ └── style.ts │ │ │ ├── cascader │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── checkbox │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── date-picker │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── editable │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ └── style.ts │ │ │ ├── el-form │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── el-form-item │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── form │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ └── style.ts │ │ │ ├── form-button-group │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ └── style.ts │ │ │ ├── form-collapse │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ └── style.ts │ │ │ ├── form-dialog │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── form-drawer │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ └── style.ts │ │ │ ├── form-grid │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ └── style.ts │ │ │ ├── form-item │ │ │ │ ├── animation.scss │ │ │ │ ├── grid.scss │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ ├── style.ts │ │ │ │ └── var.scss │ │ │ ├── form-layout │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ ├── style.ts │ │ │ │ └── useResponsiveFormLayout.ts │ │ │ ├── form-step │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── form-tab │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ └── style.ts │ │ │ ├── index.ts │ │ │ ├── input │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── input-number │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── password │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── preview-text │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── radio │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── reset │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── select │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── space │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ └── style.ts │ │ │ ├── style.ts │ │ │ ├── submit │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── switch │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── time-picker │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── transfer │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ └── upload │ │ │ ├── index.ts │ │ │ └── style.ts │ │ ├── transformer.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── grid │ │ ├── .npmignore │ │ ├── LICENSE.md │ │ ├── package.json │ │ ├── README.md │ │ ├── rollup.config.js │ │ ├── src │ │ │ ├── index.ts │ │ │ └── observer.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── json-schema │ │ ├── .npmignore │ │ ├── LICENSE.md │ │ ├── package.json │ │ ├── README.md │ │ ├── rollup.config.js │ │ ├── src │ │ │ ├── __tests__ │ │ │ │ ├── __snapshots__ │ │ │ │ │ └── schema.spec.ts.snap │ │ │ │ ├── compiler.spec.ts │ │ │ │ ├── patches.spec.ts │ │ │ │ ├── schema.spec.ts │ │ │ │ ├── server-validate.spec.ts │ │ │ │ ├── shared.spec.ts │ │ │ │ ├── transformer.spec.ts │ │ │ │ └── traverse.spec.ts │ │ │ ├── compiler.ts │ │ │ ├── global.d.ts │ │ │ ├── index.ts │ │ │ ├── patches.ts │ │ │ ├── polyfills │ │ │ │ ├── index.ts │ │ │ │ └── SPECIFICATION_1_0.ts │ │ │ ├── schema.ts │ │ │ ├── shared.ts │ │ │ ├── transformer.ts │ │ │ └── types.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── next │ │ ├── __tests__ │ │ │ ├── moment.spec.ts │ │ │ └── sideEffects.spec.ts │ │ ├── .npmignore │ │ ├── .umirc.js │ │ ├── build-style.ts │ │ ├── create-style.ts │ │ ├── docs │ │ │ ├── components │ │ │ │ ├── ArrayCards.md │ │ │ │ ├── ArrayCards.zh-CN.md │ │ │ │ ├── ArrayCollapse.md │ │ │ │ ├── ArrayCollapse.zh-CN.md │ │ │ │ ├── ArrayItems.md │ │ │ │ ├── ArrayItems.zh-CN.md │ │ │ │ ├── ArrayTable.md │ │ │ │ ├── ArrayTable.zh-CN.md │ │ │ │ ├── Cascader.md │ │ │ │ ├── Cascader.zh-CN.md │ │ │ │ ├── Checkbox.md │ │ │ │ ├── Checkbox.zh-CN.md │ │ │ │ ├── DatePicker.md │ │ │ │ ├── DatePicker.zh-CN.md │ │ │ │ ├── DatePicker2.md │ │ │ │ ├── DatePicker2.zh-CN.md │ │ │ │ ├── Editable.md │ │ │ │ ├── Editable.zh-CN.md │ │ │ │ ├── Form.md │ │ │ │ ├── Form.zh-CN.md │ │ │ │ ├── FormButtonGroup.md │ │ │ │ ├── FormButtonGroup.zh-CN.md │ │ │ │ ├── FormCollapse.md │ │ │ │ ├── FormCollapse.zh-CN.md │ │ │ │ ├── FormDialog.md │ │ │ │ ├── FormDialog.zh-CN.md │ │ │ │ ├── FormDrawer.md │ │ │ │ ├── FormDrawer.zh-CN.md │ │ │ │ ├── FormGrid.md │ │ │ │ ├── FormGrid.zh-CN.md │ │ │ │ ├── FormItem.md │ │ │ │ ├── FormItem.zh-CN.md │ │ │ │ ├── FormLayout.md │ │ │ │ ├── FormLayout.zh-CN.md │ │ │ │ ├── FormStep.md │ │ │ │ ├── FormStep.zh-CN.md │ │ │ │ ├── FormTab.md │ │ │ │ ├── FormTab.zh-CN.md │ │ │ │ ├── index.md │ │ │ │ ├── index.zh-CN.md │ │ │ │ ├── Input.md │ │ │ │ ├── Input.zh-CN.md │ │ │ │ ├── NumberPicker.md │ │ │ │ ├── NumberPicker.zh-CN.md │ │ │ │ ├── Password.md │ │ │ │ ├── Password.zh-CN.md │ │ │ │ ├── PreviewText.md │ │ │ │ ├── PreviewText.zh-CN.md │ │ │ │ ├── Radio.md │ │ │ │ ├── Radio.zh-CN.md │ │ │ │ ├── Reset.md │ │ │ │ ├── Reset.zh-CN.md │ │ │ │ ├── Select.md │ │ │ │ ├── Select.zh-CN.md │ │ │ │ ├── SelectTable.md │ │ │ │ ├── SelectTable.zh-CN.md │ │ │ │ ├── Space.md │ │ │ │ ├── Space.zh-CN.md │ │ │ │ ├── Submit.md │ │ │ │ ├── Submit.zh-CN.md │ │ │ │ ├── Switch.md │ │ │ │ ├── Switch.zh-CN.md │ │ │ │ ├── TimePicker.md │ │ │ │ ├── TimePicker.zh-CN.md │ │ │ │ ├── TimePicker2.md │ │ │ │ ├── TimePicker2.zh-CN.md │ │ │ │ ├── Transfer.md │ │ │ │ ├── Transfer.zh-CN.md │ │ │ │ ├── TreeSelect.md │ │ │ │ ├── TreeSelect.zh-CN.md │ │ │ │ ├── Upload.md │ │ │ │ └── Upload.zh-CN.md │ │ │ ├── index.md │ │ │ └── index.zh-CN.md │ │ ├── LESENCE.md │ │ ├── package.json │ │ ├── README.md │ │ ├── rollup.config.js │ │ ├── src │ │ │ ├── __builtins__ │ │ │ │ ├── empty.tsx │ │ │ │ ├── hooks │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── useClickAway.ts │ │ │ │ │ └── usePrefixCls.ts │ │ │ │ ├── icons.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── loading.ts │ │ │ │ ├── mapSize.ts │ │ │ │ ├── mapStatus.ts │ │ │ │ ├── moment.ts │ │ │ │ ├── pickDataProps.ts │ │ │ │ ├── portal.tsx │ │ │ │ ├── render.ts │ │ │ │ └── toArray.ts │ │ │ ├── array-base │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ └── style.ts │ │ │ ├── array-cards │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ └── style.ts │ │ │ ├── array-collapse │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ └── style.ts │ │ │ ├── array-items │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ └── style.ts │ │ │ ├── array-table │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ └── style.ts │ │ │ ├── cascader │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── checkbox │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── date-picker │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── date-picker2 │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ └── style.ts │ │ │ ├── editable │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ └── style.ts │ │ │ ├── form │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ └── style.ts │ │ │ ├── form-button-group │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ └── style.ts │ │ │ ├── form-collapse │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── form-dialog │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── form-drawer │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── form-grid │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ └── style.ts │ │ │ ├── form-item │ │ │ │ ├── animation.scss │ │ │ │ ├── grid.scss │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ ├── scss │ │ │ │ │ └── variable.scss │ │ │ │ └── style.ts │ │ │ ├── form-layout │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ ├── style.ts │ │ │ │ └── useResponsiveFormLayout.ts │ │ │ ├── form-step │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── form-tab │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── index.ts │ │ │ ├── input │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── main.scss │ │ │ ├── number-picker │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── password │ │ │ │ ├── index.tsx │ │ │ │ ├── PasswordStrength.tsx │ │ │ │ └── style.ts │ │ │ ├── preview-text │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ └── style.ts │ │ │ ├── radio │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── reset │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── select │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── select-table │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ ├── style.ts │ │ │ │ ├── useCheckSlackly.tsx │ │ │ │ ├── useFilterOptions.tsx │ │ │ │ ├── useFlatOptions.tsx │ │ │ │ ├── useSize.tsx │ │ │ │ ├── useTitleAddon.tsx │ │ │ │ └── utils.ts │ │ │ ├── space │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ └── style.ts │ │ │ ├── style.ts │ │ │ ├── submit │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── switch │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── time-picker │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── time-picker2 │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── transfer │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── tree-select │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ └── upload │ │ │ ├── index.tsx │ │ │ ├── main.scss │ │ │ ├── placeholder.ts │ │ │ └── style.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── path │ │ ├── .npmignore │ │ ├── benchmark.ts │ │ ├── LICENSE.md │ │ ├── package.json │ │ ├── README.md │ │ ├── rollup.config.js │ │ ├── src │ │ │ ├── __tests__ │ │ │ │ ├── accessor.spec.ts │ │ │ │ ├── basic.spec.ts │ │ │ │ ├── match.spec.ts │ │ │ │ ├── parser.spec.ts │ │ │ │ └── share.spec.ts │ │ │ ├── contexts.ts │ │ │ ├── destructor.ts │ │ │ ├── index.ts │ │ │ ├── matcher.ts │ │ │ ├── parser.ts │ │ │ ├── shared.ts │ │ │ ├── tokenizer.ts │ │ │ ├── tokens.ts │ │ │ └── types.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── react │ │ ├── .npmignore │ │ ├── .umirc.js │ │ ├── docs │ │ │ ├── api │ │ │ │ ├── components │ │ │ │ │ ├── ArrayField.md │ │ │ │ │ ├── ArrayField.zh-CN.md │ │ │ │ │ ├── ExpressionScope.md │ │ │ │ │ ├── ExpressionScope.zh-CN.md │ │ │ │ │ ├── Field.md │ │ │ │ │ ├── Field.zh-CN.md │ │ │ │ │ ├── FormConsumer.md │ │ │ │ │ ├── FormConsumer.zh-CN.md │ │ │ │ │ ├── FormProvider.md │ │ │ │ │ ├── FormProvider.zh-CN.md │ │ │ │ │ ├── ObjectField.md │ │ │ │ │ ├── ObjectField.zh-CN.md │ │ │ │ │ ├── RecordScope.md │ │ │ │ │ ├── RecordScope.zh-CN.md │ │ │ │ │ ├── RecordsScope.md │ │ │ │ │ ├── RecordsScope.zh-CN.md │ │ │ │ │ ├── RecursionField.md │ │ │ │ │ ├── RecursionField.zh-CN.md │ │ │ │ │ ├── SchemaField.md │ │ │ │ │ ├── SchemaField.zh-CN.md │ │ │ │ │ ├── VoidField.md │ │ │ │ │ └── VoidField.zh-CN.md │ │ │ │ ├── hooks │ │ │ │ │ ├── useExpressionScope.md │ │ │ │ │ ├── useExpressionScope.zh-CN.md │ │ │ │ │ ├── useField.md │ │ │ │ │ ├── useField.zh-CN.md │ │ │ │ │ ├── useFieldSchema.md │ │ │ │ │ ├── useFieldSchema.zh-CN.md │ │ │ │ │ ├── useForm.md │ │ │ │ │ ├── useForm.zh-CN.md │ │ │ │ │ ├── useFormEffects.md │ │ │ │ │ ├── useFormEffects.zh-CN.md │ │ │ │ │ ├── useParentForm.md │ │ │ │ │ └── useParentForm.zh-CN.md │ │ │ │ └── shared │ │ │ │ ├── connect.md │ │ │ │ ├── connect.zh-CN.md │ │ │ │ ├── context.md │ │ │ │ ├── context.zh-CN.md │ │ │ │ ├── mapProps.md │ │ │ │ ├── mapProps.zh-CN.md │ │ │ │ ├── mapReadPretty.md │ │ │ │ ├── mapReadPretty.zh-CN.md │ │ │ │ ├── observer.md │ │ │ │ ├── observer.zh-CN.md │ │ │ │ ├── Schema.md │ │ │ │ └── Schema.zh-CN.md │ │ │ ├── guide │ │ │ │ ├── architecture.md │ │ │ │ ├── architecture.zh-CN.md │ │ │ │ ├── concept.md │ │ │ │ ├── concept.zh-CN.md │ │ │ │ ├── index.md │ │ │ │ └── index.zh-CN.md │ │ │ ├── index.md │ │ │ └── index.zh-CN.md │ │ ├── LICENSE.md │ │ ├── package.json │ │ ├── README.md │ │ ├── rollup.config.js │ │ ├── src │ │ │ ├── __tests__ │ │ │ │ ├── expression.spec.tsx │ │ │ │ ├── field.spec.tsx │ │ │ │ ├── form.spec.tsx │ │ │ │ ├── schema.json.spec.tsx │ │ │ │ ├── schema.markup.spec.tsx │ │ │ │ └── shared.tsx │ │ │ ├── components │ │ │ │ ├── ArrayField.tsx │ │ │ │ ├── ExpressionScope.tsx │ │ │ │ ├── Field.tsx │ │ │ │ ├── FormConsumer.tsx │ │ │ │ ├── FormProvider.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── ObjectField.tsx │ │ │ │ ├── ReactiveField.tsx │ │ │ │ ├── RecordScope.tsx │ │ │ │ ├── RecordsScope.tsx │ │ │ │ ├── RecursionField.tsx │ │ │ │ ├── SchemaField.tsx │ │ │ │ └── VoidField.tsx │ │ │ ├── global.d.ts │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ ├── useAttach.ts │ │ │ │ ├── useExpressionScope.ts │ │ │ │ ├── useField.ts │ │ │ │ ├── useFieldSchema.ts │ │ │ │ ├── useForm.ts │ │ │ │ ├── useFormEffects.ts │ │ │ │ └── useParentForm.ts │ │ │ ├── index.ts │ │ │ ├── shared │ │ │ │ ├── connect.ts │ │ │ │ ├── context.ts │ │ │ │ ├── index.ts │ │ │ │ └── render.ts │ │ │ └── types.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── reactive │ │ ├── .npmignore │ │ ├── .umirc.js │ │ ├── benchmark.ts │ │ ├── docs │ │ │ ├── api │ │ │ │ ├── action.md │ │ │ │ ├── action.zh-CN.md │ │ │ │ ├── autorun.md │ │ │ │ ├── autorun.zh-CN.md │ │ │ │ ├── batch.md │ │ │ │ ├── batch.zh-CN.md │ │ │ │ ├── define.md │ │ │ │ ├── define.zh-CN.md │ │ │ │ ├── hasCollected.md │ │ │ │ ├── hasCollected.zh-CN.md │ │ │ │ ├── markObservable.md │ │ │ │ ├── markObservable.zh-CN.md │ │ │ │ ├── markRaw.md │ │ │ │ ├── markRaw.zh-CN.md │ │ │ │ ├── model.md │ │ │ │ ├── model.zh-CN.md │ │ │ │ ├── observable.md │ │ │ │ ├── observable.zh-CN.md │ │ │ │ ├── observe.md │ │ │ │ ├── observe.zh-CN.md │ │ │ │ ├── raw.md │ │ │ │ ├── raw.zh-CN.md │ │ │ │ ├── react │ │ │ │ │ ├── observer.md │ │ │ │ │ └── observer.zh-CN.md │ │ │ │ ├── reaction.md │ │ │ │ ├── reaction.zh-CN.md │ │ │ │ ├── toJS.md │ │ │ │ ├── toJS.zh-CN.md │ │ │ │ ├── tracker.md │ │ │ │ ├── tracker.zh-CN.md │ │ │ │ ├── typeChecker.md │ │ │ │ ├── typeChecker.zh-CN.md │ │ │ │ ├── untracked.md │ │ │ │ ├── untracked.zh-CN.md │ │ │ │ └── vue │ │ │ │ ├── observer.md │ │ │ │ └── observer.zh-CN.md │ │ │ ├── guide │ │ │ │ ├── best-practice.md │ │ │ │ ├── best-practice.zh-CN.md │ │ │ │ ├── concept.md │ │ │ │ ├── concept.zh-CN.md │ │ │ │ ├── index.md │ │ │ │ └── index.zh-CN.md │ │ │ ├── index.md │ │ │ └── index.zh-CN.md │ │ ├── LICENSE.md │ │ ├── package.json │ │ ├── README.md │ │ ├── rollup.config.js │ │ ├── src │ │ │ ├── __tests__ │ │ │ │ ├── action.spec.ts │ │ │ │ ├── annotations.spec.ts │ │ │ │ ├── array.spec.ts │ │ │ │ ├── autorun.spec.ts │ │ │ │ ├── batch.spec.ts │ │ │ │ ├── collections-map.spec.ts │ │ │ │ ├── collections-set.spec.ts │ │ │ │ ├── collections-weakmap.spec.ts │ │ │ │ ├── collections-weakset.spec.ts │ │ │ │ ├── define.spec.ts │ │ │ │ ├── externals.spec.ts │ │ │ │ ├── hasCollected.spec.ts │ │ │ │ ├── observable.spec.ts │ │ │ │ ├── observe.spec.ts │ │ │ │ ├── tracker.spec.ts │ │ │ │ └── untracked.spec.ts │ │ │ ├── action.ts │ │ │ ├── annotations │ │ │ │ ├── box.ts │ │ │ │ ├── computed.ts │ │ │ │ ├── index.ts │ │ │ │ ├── observable.ts │ │ │ │ ├── ref.ts │ │ │ │ └── shallow.ts │ │ │ ├── array.ts │ │ │ ├── autorun.ts │ │ │ ├── batch.ts │ │ │ ├── checkers.ts │ │ │ ├── environment.ts │ │ │ ├── externals.ts │ │ │ ├── global.d.ts │ │ │ ├── handlers.ts │ │ │ ├── index.ts │ │ │ ├── internals.ts │ │ │ ├── model.ts │ │ │ ├── observable.ts │ │ │ ├── observe.ts │ │ │ ├── reaction.ts │ │ │ ├── tracker.ts │ │ │ ├── tree.ts │ │ │ ├── types.ts │ │ │ └── untracked.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── reactive-react │ │ ├── .npmignore │ │ ├── .umirc.js │ │ ├── LICENSE.md │ │ ├── package.json │ │ ├── README.md │ │ ├── rollup.config.js │ │ ├── src │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ ├── useCompatEffect.ts │ │ │ │ ├── useCompatFactory.ts │ │ │ │ ├── useDidUpdate.ts │ │ │ │ ├── useForceUpdate.ts │ │ │ │ ├── useLayoutEffect.ts │ │ │ │ └── useObserver.ts │ │ │ ├── index.ts │ │ │ ├── observer.ts │ │ │ ├── shared │ │ │ │ ├── gc.ts │ │ │ │ ├── global.ts │ │ │ │ ├── immediate.ts │ │ │ │ └── index.ts │ │ │ └── types.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── reactive-test-cases-for-react18 │ │ ├── .npmignore │ │ ├── .umirc.js │ │ ├── LICENSE.md │ │ ├── package.json │ │ ├── README.md │ │ ├── src │ │ │ ├── index.js │ │ │ └── MySlowList.js │ │ ├── template.ejs │ │ ├── tsconfig.build.json │ │ ├── tsconfig.json │ │ ├── webpack.base.ts │ │ ├── webpack.dev.ts │ │ └── webpack.prod.ts │ ├── reactive-vue │ │ ├── .npmignore │ │ ├── LICENSE.md │ │ ├── package.json │ │ ├── README.md │ │ ├── rollup.config.js │ │ ├── src │ │ │ ├── __tests__ │ │ │ │ └── observer.spec.ts │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ └── useObserver.ts │ │ │ ├── index.ts │ │ │ ├── observer │ │ │ │ ├── collectData.ts │ │ │ │ ├── index.ts │ │ │ │ ├── observerInVue2.ts │ │ │ │ └── observerInVue3.ts │ │ │ └── types.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── shared │ │ ├── .npmignore │ │ ├── LICENSE.md │ │ ├── package.json │ │ ├── README.md │ │ ├── rollup.config.js │ │ ├── src │ │ │ ├── __tests__ │ │ │ │ └── index.spec.ts │ │ │ ├── array.ts │ │ │ ├── case.ts │ │ │ ├── checkers.ts │ │ │ ├── clone.ts │ │ │ ├── compare.ts │ │ │ ├── defaults.ts │ │ │ ├── deprecate.ts │ │ │ ├── global.ts │ │ │ ├── index.ts │ │ │ ├── instanceof.ts │ │ │ ├── isEmpty.ts │ │ │ ├── merge.ts │ │ │ ├── middleware.ts │ │ │ ├── path.ts │ │ │ ├── string.ts │ │ │ ├── subscribable.ts │ │ │ └── uid.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── validator │ │ ├── .npmignore │ │ ├── LICENSE.md │ │ ├── package.json │ │ ├── README.md │ │ ├── rollup.config.js │ │ ├── src │ │ │ ├── __tests__ │ │ │ │ ├── parser.spec.ts │ │ │ │ ├── registry.spec.ts │ │ │ │ └── validator.spec.ts │ │ │ ├── formats.ts │ │ │ ├── index.ts │ │ │ ├── locale.ts │ │ │ ├── parser.ts │ │ │ ├── registry.ts │ │ │ ├── rules.ts │ │ │ ├── template.ts │ │ │ ├── types.ts │ │ │ └── validator.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ └── vue │ ├── .npmignore │ ├── bin │ │ ├── formily-vue-fix.js │ │ └── formily-vue-switch.js │ ├── docs │ │ ├── .vuepress │ │ │ ├── components │ │ │ │ ├── createCodeSandBox.js │ │ │ │ ├── dumi-previewer.vue │ │ │ │ └── highlight.js │ │ │ ├── config.js │ │ │ ├── enhanceApp.js │ │ │ └── styles │ │ │ └── index.styl │ │ ├── api │ │ │ ├── components │ │ │ │ ├── array-field.md │ │ │ │ ├── expression-scope.md │ │ │ │ ├── field.md │ │ │ │ ├── form-consumer.md │ │ │ │ ├── form-provider.md │ │ │ │ ├── object-field.md │ │ │ │ ├── recursion-field-with-component.md │ │ │ │ ├── recursion-field.md │ │ │ │ ├── schema-field-with-schema.md │ │ │ │ ├── schema-field.md │ │ │ │ └── void-field.md │ │ │ ├── hooks │ │ │ │ ├── use-field-schema.md │ │ │ │ ├── use-field.md │ │ │ │ ├── use-form-effects.md │ │ │ │ ├── use-form.md │ │ │ │ └── use-parent-form.md │ │ │ └── shared │ │ │ ├── connect.md │ │ │ ├── injections.md │ │ │ ├── map-props.md │ │ │ ├── map-read-pretty.md │ │ │ ├── observer.md │ │ │ └── schema.md │ │ ├── demos │ │ │ ├── api │ │ │ │ ├── components │ │ │ │ │ ├── array-field.vue │ │ │ │ │ ├── expression-scope.vue │ │ │ │ │ ├── field.vue │ │ │ │ │ ├── form-consumer.vue │ │ │ │ │ ├── form-provider.vue │ │ │ │ │ ├── object-field.vue │ │ │ │ │ ├── recursion-field-with-component.vue │ │ │ │ │ ├── recursion-field.vue │ │ │ │ │ ├── schema-field-with-schema.vue │ │ │ │ │ ├── schema-field.vue │ │ │ │ │ └── void-field.vue │ │ │ │ ├── hooks │ │ │ │ │ ├── use-field-schema.vue │ │ │ │ │ ├── use-field.vue │ │ │ │ │ ├── use-form-effects.vue │ │ │ │ │ ├── use-form.vue │ │ │ │ │ └── use-parent-form.vue │ │ │ │ └── shared │ │ │ │ ├── connect.vue │ │ │ │ ├── map-props.vue │ │ │ │ ├── map-read-pretty.vue │ │ │ │ └── observer.vue │ │ │ ├── index.vue │ │ │ └── questions │ │ │ ├── default-slot.vue │ │ │ ├── events.vue │ │ │ ├── named-slot.vue │ │ │ └── scoped-slot.vue │ │ ├── guide │ │ │ ├── architecture.md │ │ │ ├── concept.md │ │ │ └── README.md │ │ ├── questions │ │ │ └── README.md │ │ └── README.md │ ├── package.json │ ├── README.md │ ├── rollup.config.js │ ├── scripts │ │ ├── postinstall.js │ │ ├── switch-cli.js │ │ └── utils.js │ ├── src │ │ ├── __tests__ │ │ │ ├── expression.scope.spec.ts │ │ │ ├── field.spec.ts │ │ │ ├── form.spec.ts │ │ │ ├── schema.json.spec.ts │ │ │ ├── schema.markup.spec.ts │ │ │ ├── shared.spec.ts │ │ │ └── utils.spec.ts │ │ ├── components │ │ │ ├── ArrayField.ts │ │ │ ├── ExpressionScope.ts │ │ │ ├── Field.ts │ │ │ ├── FormConsumer.ts │ │ │ ├── FormProvider.ts │ │ │ ├── index.ts │ │ │ ├── ObjectField.ts │ │ │ ├── ReactiveField.ts │ │ │ ├── RecursionField.ts │ │ │ ├── SchemaField.ts │ │ │ └── VoidField.ts │ │ ├── global.d.ts │ │ ├── hooks │ │ │ ├── index.ts │ │ │ ├── useAttach.ts │ │ │ ├── useField.ts │ │ │ ├── useFieldSchema.ts │ │ │ ├── useForm.ts │ │ │ ├── useFormEffects.ts │ │ │ ├── useInjectionCleaner.ts │ │ │ └── useParentForm.ts │ │ ├── index.ts │ │ ├── shared │ │ │ ├── connect.ts │ │ │ ├── context.ts │ │ │ ├── createForm.ts │ │ │ ├── fragment.ts │ │ │ ├── h.ts │ │ │ └── index.ts │ │ ├── types │ │ │ └── index.ts │ │ ├── utils │ │ │ ├── formatVNodeData.ts │ │ │ ├── getFieldProps.ts │ │ │ ├── getRawComponent.ts │ │ │ └── resolveSchemaProps.ts │ │ └── vue2-components.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── tsconfig.types.json ├── README.md ├── README.zh-cn.md ├── scripts │ ├── build-style │ │ ├── buildAllStyles.ts │ │ ├── copy.ts │ │ ├── helper.ts │ │ └── index.ts │ └── rollup.base.js ├── tsconfig.build.json ├── tsconfig.jest.json ├── tsconfig.json └── yarn.lock ``` # Files -------------------------------------------------------------------------------- /packages/core/docs/api/models/Form.md: -------------------------------------------------------------------------------- ```markdown 1 | --- 2 | order: 0 3 | --- 4 | 5 | # Form 6 | 7 | Call the core [Form Model](/guide/form) API returned by [createForm](/api/entry/create-form), the following will list all model attributes, if the attribute is writable, then we can directly The reference is to modify the attribute, and @formily/reactive will respond to trigger the UI update. 8 | 9 | ## Attributes 10 | 11 | | Property | Description | Type | Read-only or not | Default value | 12 | | ------------- | ------------------------------------------------- | ------------------------------------- | ---------------- | ----------------- | 13 | | initialized | Whether the form is initialized | Boolean | No | `false` | 14 | | validating | Is the form being validated | Boolean | No | `false` | 15 | | submitting | Is the form being submitted | Boolean | No | `false` | 16 | | modified | Whether the form value has been manually modified | Boolean | No | `false` | 17 | | pattern | Form interaction mode | [FormPatternTypes](#formpatterntypes) | No | `"editable"` | 18 | | display | Form display form | [FormDisplayTypes](#formdisplaytypes) | No | `"visible"` | 19 | | mounted | Is the form mounted | Boolean | No | `false` | 20 | | unmounted | Is the form unmounted | Boolean | No | `false` | 21 | | values | form values | Object | No | `{}` | 22 | | initialValues | Form default values | Object | No | `{}` | 23 | | valid | Is the form valid | Boolean | Yes | `true` | 24 | | invalid | Is the form illegal | Boolean | Yes | `false` | 25 | | errors | Form validation error message | [IFormFeedback](#iformfeedback)[] | Yes | `[]` | 26 | | warnings | Form verification warning message | [IFormFeedback](#iformfeedback)[] | Yes | `[]` | 27 | | successes | Form verification success message | [IFormFeedback](#iformfeedback)[] | Yes | `[]` | 28 | | hidden | Whether the form is hidden | Boolean | No | `false` | 29 | | visible | Whether the form is displayed | Boolean | No | `true` | 30 | | editable | Is the form editable | Boolean | No | `true` | 31 | | readOnly | Is the form read-only | Boolean | No | `false` | 32 | | disabled | Whether the form is disabled | Boolean | No | `false` | 33 | | readPretty | Is the form in a read state | Boolean | No | `false` | 34 | | id | Form ID | String | No | `{RANDOM_STRING}` | 35 | | displayName | Model label | String | No | `"Form"` | 36 | 37 | ## Method 38 | 39 | ### createField 40 | 41 | #### Description 42 | 43 | Create a factory function for a Field instance. If the path is the same and called multiple times, the instance object will be reused 44 | 45 | #### Signature 46 | 47 | ```ts 48 | interface createField { 49 | (props: IFieldFactoryProps): Field 50 | } 51 | ``` 52 | 53 | For function entry, please refer to [IFieldFactoryProps](#ifieldfactoryprops) 54 | 55 | ### createArrayField 56 | 57 | #### Description 58 | 59 | A factory function for creating an ArrayField instance. If the path is the same and called multiple times, the instance object will be reused 60 | 61 | #### Signature 62 | 63 | ```ts 64 | interface createArrayField { 65 | (props: IFieldFactoryProps): ArrayField 66 | } 67 | ``` 68 | 69 | For function entry, please refer to [IFieldFactoryProps](#ifieldfactoryprops) 70 | 71 | ### createObjectField 72 | 73 | #### Description 74 | 75 | A factory function to create an ObjectField instance. If the path is the same and called multiple times, it will reuse the instance object 76 | 77 | #### Signature 78 | 79 | ```ts 80 | interface createObjectField { 81 | (props: IFieldFactoryProps): ArrayField 82 | } 83 | ``` 84 | 85 | For function entry, please refer to [IFieldFactoryProps](#ifieldfactoryprops) 86 | 87 | ### createVoidField 88 | 89 | #### Description 90 | 91 | A factory function to create a VoidField instance. If the path is the same and called multiple times, the instance object will be reused 92 | 93 | #### Signature 94 | 95 | ```ts 96 | interface createVoidField { 97 | (props: IVoidFieldFactoryProps): ArrayField 98 | } 99 | ``` 100 | 101 | For function entry, please refer to [IVoidFieldFactoryProps](#ivoidfieldfactoryprops) 102 | 103 | ### setValues 104 | 105 | #### Description 106 | 107 | Set the form value, you can set the merge strategy [IFormMergeStrategy](#iformmergestrategy) 108 | 109 | #### Signature 110 | 111 | ```ts 112 | interface setValues { 113 | (values: object, strategy: IFormMergeStrategy = 'merge'): void 114 | } 115 | ``` 116 | 117 | ### setInitialValues 118 | 119 | #### Description 120 | 121 | Set the default value of the form, you can set the merge strategy 122 | 123 | #### Signature 124 | 125 | ```ts 126 | interface setInitialValues { 127 | (initialValues: object, strategy: IFormMergeStrategy = 'merge'): void 128 | } 129 | ``` 130 | 131 | ### setValuesIn 132 | 133 | #### Description 134 | 135 | Precisely set form values 136 | 137 | #### Signature 138 | 139 | ```ts 140 | interface setValuesIn { 141 | (path: FormPathPattern, value: any): void 142 | } 143 | ``` 144 | 145 | FormPathPattern API Reference [FormPath](/api/entry/form-path#formpathpattern) 146 | 147 | ### setInitialValuesIn 148 | 149 | #### Description 150 | 151 | Precisely set the form default value 152 | 153 | #### Signature 154 | 155 | ```ts 156 | interface setInitialValuesIn { 157 | (path: FormPathPattern, initialValue: any): void 158 | } 159 | ``` 160 | 161 | FormPathPattern API Reference [FormPath](/api/entry/form-path#formpathpattern) 162 | 163 | ### existValuesIn 164 | 165 | #### Description 166 | 167 | Determine whether the value exists according to the specified path 168 | 169 | #### Signature 170 | 171 | ```ts 172 | interface existValuesIn { 173 | (path: FormPathPattern): boolean 174 | } 175 | ``` 176 | 177 | FormPathPattern API Reference [FormPath](/api/entry/form-path#formpathpattern) 178 | 179 | ### existInitialValuesIn 180 | 181 | #### Description 182 | 183 | Determine whether the default value exists according to the specified path 184 | 185 | #### Signature 186 | 187 | ```ts 188 | interface existInitialValuesIn { 189 | (path: FormPathPattern): boolean 190 | } 191 | ``` 192 | 193 | FormPathPattern API Reference [FormPath](/api/entry/form-path#formpathpattern) 194 | 195 | ### getValuesIn 196 | 197 | #### Description 198 | 199 | Get the form value according to the specified path 200 | 201 | #### Signature 202 | 203 | ```ts 204 | interface getValuesIn { 205 | (path: FormPathPattern): any 206 | } 207 | ``` 208 | 209 | FormPathPattern API Reference [FormPath](/api/entry/form-path#formpathpattern) 210 | 211 | ### getInitialValuesIn 212 | 213 | #### Description 214 | 215 | Get the default value of the form according to the specified path 216 | 217 | #### Signature 218 | 219 | ```ts 220 | interface getInitialValuesIn { 221 | (path: FormPathPattern): any 222 | } 223 | ``` 224 | 225 | FormPathPattern API Reference [FormPath](/api/entry/form-path#formpathpattern) 226 | 227 | ### deleteValuesIn 228 | 229 | #### Description 230 | 231 | Delete the form value according to the specified path 232 | 233 | #### Signature 234 | 235 | ```ts 236 | interface deleteValuesIn { 237 | (path: FormPathPattern): void 238 | } 239 | ``` 240 | 241 | FormPathPattern API Reference [FormPath](/api/entry/form-path#formpathpattern) 242 | 243 | ### deleteInitialValuesIn 244 | 245 | #### Description 246 | 247 | Delete the default value of the form according to the specified path 248 | 249 | #### Signature 250 | 251 | ```ts 252 | interface deleteInitialValuesIn { 253 | (path: FormPathPattern): void 254 | } 255 | ``` 256 | 257 | FormPathPattern API Reference [FormPath](/api/entry/form-path#formpathpattern) 258 | 259 | ### setSubmitting 260 | 261 | #### Description 262 | 263 | Set whether the form is being submitted 264 | 265 | #### Signature 266 | 267 | ```ts 268 | interface setSubmitting { 269 | (submitting: boolean): void 270 | } 271 | ``` 272 | 273 | ### setValidating 274 | 275 | #### Description 276 | 277 | Set whether the form is verifying status 278 | 279 | #### Signature 280 | 281 | ```ts 282 | interface setValidating { 283 | (validating: boolean): void 284 | } 285 | ``` 286 | 287 | ### setDisplay 288 | 289 | #### Description 290 | 291 | Set form display status 292 | 293 | #### Signature 294 | 295 | ```ts 296 | interface setDisplay { 297 | (display: FormDisplayTypes): void 298 | } 299 | ``` 300 | 301 | For function entry, please refer to [FormDisplayTypes](#formdisplaytypes) 302 | 303 | ### setPattern 304 | 305 | #### Description 306 | 307 | Set the form interaction mode 308 | 309 | #### Signature 310 | 311 | ```ts 312 | interface setPattern { 313 | (pattern: FormPatternTypes): void 314 | } 315 | ``` 316 | 317 | For function entry, please refer to [FormPatternTypes](#formpatterntypes) 318 | 319 | ### addEffects 320 | 321 | #### Description 322 | 323 | Add side effects 324 | 325 | #### Signature 326 | 327 | ```ts 328 | interface addEffects { 329 | (id: string, effects: (form: Form) => void): void 330 | } 331 | ``` 332 | 333 | ### removeEffects 334 | 335 | #### Description 336 | 337 | Remove side effects, the id is consistent with the id of addEffects 338 | 339 | #### Signature 340 | 341 | ```ts 342 | interface removeEffects { 343 | (id: string): void 344 | } 345 | ``` 346 | 347 | ### setEffects 348 | 349 | #### Description 350 | 351 | Overwrite update side effects 352 | 353 | #### Signature 354 | 355 | ```ts 356 | interface setEffects { 357 | (effects: (form: Form) => void): void 358 | } 359 | ``` 360 | 361 | ### clearErrors 362 | 363 | #### Description 364 | 365 | Clear error message 366 | 367 | #### Signature 368 | 369 | ```ts 370 | interface clearErrors { 371 | (pattern?: FormPathPattern): void 372 | } 373 | ``` 374 | 375 | FormPathPattern API Reference [FormPath](/api/entry/form-path#formpathpattern) 376 | 377 | ### clearWarnings 378 | 379 | #### Description 380 | 381 | Clear warning message 382 | 383 | #### Signature 384 | 385 | ```ts 386 | interface clearWarnings { 387 | (pattern?: FormPathPattern): void 388 | } 389 | ``` 390 | 391 | FormPathPattern API Reference [FormPath](/api/entry/form-path#formpathpattern) 392 | 393 | ### clearSuccesses 394 | 395 | #### Description 396 | 397 | Clear success message 398 | 399 | #### Signature 400 | 401 | ```ts 402 | interface clearSuccesses { 403 | (pattern?: FormPathPattern): void 404 | } 405 | ``` 406 | 407 | FormPathPattern API Reference [FormPath](/api/entry/form-path#formpathpattern) 408 | 409 | ### query 410 | 411 | #### Description 412 | 413 | Query field node 414 | 415 | #### Signature 416 | 417 | ```ts 418 | interface query { 419 | (pattern: FormPathPattern): Query 420 | } 421 | ``` 422 | 423 | FormPathPattern API Reference [FormPath](/api/entry/form-path#formpathpattern) 424 | 425 | Query object API reference [Query](/api/models/query) 426 | 427 | ### queryFeedbacks 428 | 429 | #### Description 430 | 431 | Query message feedback 432 | 433 | #### Signature 434 | 435 | ```ts 436 | interface queryFeedbacks { 437 | (search: ISearchFeedback): IFormFeedback[] 438 | } 439 | ``` 440 | 441 | ISearchFeedback Reference [ISearchFeedback](/api/models/field#isearchfeedback) 442 | 443 | IFormFeedback Reference [IFormFeedback](#iformfeedback) 444 | 445 | ### notify 446 | 447 | #### Description 448 | 449 | Broadcast message 450 | 451 | #### Signature 452 | 453 | ```ts 454 | interface notify<T> { 455 | (type?: string, payload: T): void 456 | } 457 | ``` 458 | 459 | ### subscribe 460 | 461 | #### Description 462 | 463 | Subscribe to news 464 | 465 | #### Signature 466 | 467 | ```ts 468 | interface subscribe<T> { 469 | (callback: (payload: T) => void): number 470 | } 471 | ``` 472 | 473 | ### unsubscribe 474 | 475 | #### Description 476 | 477 | unsubscribe 478 | 479 | #### Signature 480 | 481 | ```ts 482 | interface unsubscribe { 483 | (id: number): void 484 | } 485 | ``` 486 | 487 | ### onInit 488 | 489 | #### Description 490 | 491 | Trigger form initialization, no need to manually call by default 492 | 493 | #### Signature 494 | 495 | ```ts 496 | interface onInit { 497 | (): void 498 | } 499 | ``` 500 | 501 | ### onMount 502 | 503 | #### Description 504 | 505 | Trigger mount 506 | 507 | #### Signature 508 | 509 | ```ts 510 | interface onMount { 511 | (): void 512 | } 513 | ``` 514 | 515 | ### onUnmount 516 | 517 | #### Description 518 | 519 | Trigger offload 520 | 521 | #### Signature 522 | 523 | ```ts 524 | interface onUnmount { 525 | (): void 526 | } 527 | ``` 528 | 529 | ### setState 530 | 531 | #### Description 532 | 533 | Set form status 534 | 535 | #### Signature 536 | 537 | ```ts 538 | interface setState { 539 | (callback: (state: IFormState) => void): void 540 | (state: IFormState): void 541 | } 542 | ``` 543 | 544 | IFormState Reference [IFormState](#iformstate) 545 | 546 | ### getState 547 | 548 | #### Description 549 | 550 | Get form status 551 | 552 | #### Signature 553 | 554 | ```ts 555 | interface getState<T> { 556 | (): IFormState 557 | (callback: (state: IFormState) => T): T 558 | } 559 | ``` 560 | 561 | IFormState Reference [IFormState](#iformstate) 562 | 563 | ### setFormState 564 | 565 | Consistent with setState API 566 | 567 | ### getFormState 568 | 569 | Consistent with getState API 570 | 571 | ### setFieldState 572 | 573 | #### Description 574 | 575 | Set field status 576 | 577 | #### Signature 578 | 579 | ```ts 580 | interface setFieldState { 581 | (pattern: FormPathPattern, setter: (state: IGeneralFieldState) => void): void 582 | (pattern: FormPathPattern, setter: IGeneralFieldState): void 583 | } 584 | ``` 585 | 586 | FormPathPattern API Reference [FormPath](/api/entry/form-path#formpathpattern) 587 | 588 | IGeneralFieldState Reference [IGeneralFieldState](/api/models/field/#igeneralfieldstate) 589 | 590 | ### getFieldState 591 | 592 | #### Description 593 | 594 | Get field status 595 | 596 | #### Signature 597 | 598 | ```ts 599 | interface getFieldState<T> { 600 | (pattern: FormPathPattern): IGeneralFieldState 601 | (pattern: FormPathPattern, callback: (state: IGeneralFieldState) => T): T 602 | } 603 | ``` 604 | 605 | FormPathPattern API Reference [FormPath](/api/entry/form-path#formpathpattern) 606 | 607 | IGeneralFieldState Reference [IGeneralFieldState](/api/models/field/#igeneralfieldstate) 608 | 609 | ### getFormGraph 610 | 611 | #### Description 612 | 613 | Get form field set 614 | 615 | #### Signature 616 | 617 | ```ts 618 | interface getFormGraph { 619 | (): { 620 | [key: string]: GeneralFieldState | FormState 621 | } 622 | } 623 | ``` 624 | 625 | ### setFormGraph 626 | 627 | #### Description 628 | 629 | Set the form field set 630 | 631 | #### Signature 632 | 633 | ```ts 634 | interface setFormGraph { 635 | (graph: { [key: string]: GeneralFieldState | FormState }): void 636 | } 637 | ``` 638 | 639 | ### clearFormGraph 640 | 641 | #### Description 642 | 643 | Clear the field set 644 | 645 | #### Signature 646 | 647 | ```ts 648 | interface clearFormGraph { 649 | (pattern: FormPathPattern): void 650 | } 651 | ``` 652 | 653 | ### validate 654 | 655 | #### Description 656 | 657 | The form verification trigger can be verified according to the specified path. If the verification is successful, there will be no return, and the verification failure will be returned in the promise reject [IFormFeedback](#iformfeedback)[] 658 | 659 | #### Signature 660 | 661 | ```ts 662 | interface validate { 663 | (pattern: FormPathPattern): Promise<void> 664 | } 665 | ``` 666 | 667 | ### submit 668 | 669 | #### Description 670 | 671 | In the form submission method, if the Promise is returned in the onSubmit callback function, the form will set the submitting status to true at the beginning of the submission, and then set it to false when the Promise resolves. The view layer can consume the submitting status to prevent repeated submissions. 672 | 673 | #### Signature 674 | 675 | ```ts 676 | interface submit<T> { 677 | (): Promise<Form['values']> 678 | (onSubmit?: (values: Form['values']) => Promise<T> | void): Promise<T> 679 | } 680 | ``` 681 | 682 | ### reset 683 | 684 | #### Description 685 | 686 | Form reset method, you can specify the specific field to be reset, or you can specify automatic verification when reset 687 | 688 | #### Description 689 | 690 | ```ts 691 | interface reset { 692 | (pattern: FormPathPattern, options?: IFieldResetOptions): Promise<void> 693 | } 694 | ``` 695 | 696 | FormPathPattern API Reference [FormPath](/api/entry/form-path#formpathpattern) 697 | 698 | IFieldResetOptions Reference [IFieldResetOptions](/api/models/field/#ifieldresetoptions) 699 | 700 | ## Types of 701 | 702 | <Alert> 703 | Note: If you want to manually consume the type, just export it directly from the package module 704 | </Alert> 705 | 706 | ### FormPatternTypes 707 | 708 | ```ts 709 | type FormPatternTypes = 'editable' | 'disabled' | 'readOnly' | 'readPretty' 710 | ``` 711 | 712 | ### FormDisplayTypes 713 | 714 | ```ts 715 | type FormDisplayTypes = 'none' | 'hidden' | 'visible' 716 | ``` 717 | 718 | ### IFormFeedback 719 | 720 | ```ts 721 | interface IFormFeedback { 722 | path?: string //Check field data path 723 | address?: string //The absolute path of the verification field 724 | triggerType?: 'onInput' | 'onFocus' | 'onBlur' //Verify the trigger type 725 | type?: 'error' | 'success' | 'warning' //feedback type 726 | code?: //Feedback code 727 | | 'ValidateError' 728 | | 'ValidateSuccess' 729 | | 'ValidateWarning' 730 | | 'EffectError' 731 | | 'EffectSuccess' 732 | | 'EffectWarning' 733 | messages?: string[] //Feedback message 734 | } 735 | ``` 736 | 737 | ### IFormState 738 | 739 | ```ts 740 | interface IFormState { 741 | editable?: boolean 742 | readOnly?: boolean 743 | disabled?: boolean 744 | readPretty?: boolean 745 | hidden?: boolean 746 | visible?: boolean 747 | initialized?: boolean 748 | validating?: boolean 749 | submitting?: boolean 750 | modified?: boolean 751 | pattern?: FormPatternTypes 752 | display?: FormDisplayTypes 753 | values?: any 754 | initialValues?: any 755 | mounted?: boolean 756 | unmounted?: boolean 757 | readonly valid?: boolean 758 | readonly invalid?: boolean 759 | readonly errors?: IFormFeedback[] 760 | readonly warnings?: IFormFeedback[] 761 | readonly successes?: IFormFeedback[] 762 | } 763 | ``` 764 | 765 | ### IFormMergeStrategy 766 | 767 | ```ts 768 | type IFormMergeStrategy = 'overwrite' | 'merge' | 'deepMerge' | 'shallowMerge' 769 | ``` 770 | 771 | ### IFieldFactoryProps 772 | 773 | ```ts 774 | interface IFieldFactoryProps { 775 | name: FormPathPattern //Field name, the path name of the current node 776 | basePath?: FormPathPattern //base path 777 | title?: string | JSXElement //Field title 778 | description?: string | JSXElement //Field description 779 | value?: any //Field value 780 | initialValue?: any //Field default value 781 | required?: boolean //Is the field required 782 | display?: 'none' | 'hidden' | 'visible' //Field display form 783 | pattern?: 'editable' | 'disabled' | 'readOnly' | 'readPretty' //Field interaction mode 784 | hidden?: boolean //whether the field is hidden 785 | visible?: boolean //Whether the field is displayed 786 | editable?: boolean //Is the field editable 787 | disabled?: boolean //Whether the field is disabled 788 | readOnly?: boolean //Is the field read-only 789 | readPretty?: boolean //Whether the field is in the read state 790 | dataSource?: any[] //Field data source 791 | validateFirst?: boolean //Does the field verification only verify the first illegal rule? 792 | validatePattern?: ('editable' | 'disabled' | 'readOnly' | 'readPretty')[] // Which patterns the validator can run in 793 | validateDisplay?: ('none' | 'hidden' | 'visible')[] // Which displays the validator can run in 794 | validator?: FieldValidator //Field validator 795 | decorator?: any[] //Field decorator, the first element represents the component reference, the second element represents the component attribute 796 | component?: any[] //Field component, the first element represents the component reference, the second element represents the component attribute 797 | reactions?: FieldReaction[] | FieldReaction //Field responder 798 | } 799 | ``` 800 | 801 | FormPathPattern API Reference [FormPath](/api/entry/form-path#formpathpattern) 802 | 803 | FieldValidator Reference [FieldValidator](/api/models/field#fieldvalidator) 804 | 805 | FieldReaction Reference [FieldReaction](/api/models/field#fieldreaction) 806 | 807 | ### IVoidFieldFactoryProps 808 | 809 | ```ts 810 | interface IFieldFactoryProps { 811 | name: FormPathPattern //Field name, the path name of the current node 812 | basePath?: FormPathPattern //base path 813 | title?: string | JSXElement //Field title 814 | description?: string | JSXElement //Field description 815 | required?: boolean //Is the field required 816 | display?: 'none' | 'hidden' | 'visible' //Field display form 817 | pattern?: 'editable' | 'disabled' | 'readOnly' | 'readPretty' //Field interaction mode 818 | hidden?: boolean //whether the field is hidden 819 | visible?: boolean //Whether the field is displayed 820 | editable?: boolean //Is the field editable 821 | disabled?: boolean //Whether the field is disabled 822 | readOnly?: boolean //Is the field read-only 823 | readPretty?: boolean //Whether the field is in the read state 824 | decorator?: any[] //Field decorator, the first element represents the component reference, the second element represents the component attribute 825 | component?: any[] //Field component, the first element represents the component reference, the second element represents the component attribute 826 | reactions?: FieldReaction[] | FieldReaction //Field responder 827 | } 828 | ``` 829 | 830 | FormPathPattern API Reference [FormPath](/api/entry/form-path#formpathpattern) 831 | 832 | FieldReaction Reference [FieldReaction](/api/models/field#fieldreaction) 833 | 834 | > Formily Typescript type convention 835 | > 836 | > - Simple non-object data types or Union data types use type to define the type, and cannot start with an uppercase `I` character 837 | > - Simple object types use interface to define the type uniformly, and start with an uppercase `I` character. If there are combinations of different interfaces (Intersection or Extends), use type to define the type, and also start with an uppercase `I` character 838 | ``` -------------------------------------------------------------------------------- /packages/next/docs/components/ArrayTable.zh-CN.md: -------------------------------------------------------------------------------- ```markdown 1 | # ArrayTable 2 | 3 | > 自增表格,对于数据量超大的场景比较适合使用该组件,虽然数据量大到一定程度会有些许卡顿,但是不会影响基本操作 4 | > 5 | > 注意:该组件只适用于 Schema 场景,且只能是对象数组 6 | 7 | ## Markup Schema 案例 8 | 9 | ```tsx 10 | import React from 'react' 11 | import { 12 | FormItem, 13 | Input, 14 | ArrayTable, 15 | Editable, 16 | FormButtonGroup, 17 | Submit, 18 | } from '@formily/next' 19 | import { createForm } from '@formily/core' 20 | import { FormProvider, createSchemaField } from '@formily/react' 21 | import { Button, Message } from '@alifd/next' 22 | 23 | const SchemaField = createSchemaField({ 24 | components: { 25 | FormItem, 26 | Editable, 27 | Input, 28 | ArrayTable, 29 | }, 30 | }) 31 | 32 | const form = createForm() 33 | 34 | const range = (count: number) => 35 | Array.from(new Array(count)).map((_, key) => ({ 36 | aaa: key, 37 | })) 38 | 39 | export default () => { 40 | return ( 41 | <FormProvider form={form}> 42 | <SchemaField> 43 | <SchemaField.Array 44 | name="array" 45 | x-decorator="FormItem" 46 | x-component="ArrayTable" 47 | x-component-props={{ 48 | pagination: { pageSize: 10 }, 49 | style: { width: '100%' }, 50 | }} 51 | > 52 | <SchemaField.Object> 53 | <SchemaField.Void 54 | x-component="ArrayTable.Column" 55 | x-component-props={{ width: 80, title: 'Sort', align: 'center' }} 56 | > 57 | <SchemaField.Void 58 | x-decorator="FormItem" 59 | required 60 | x-component="ArrayTable.SortHandle" 61 | /> 62 | </SchemaField.Void> 63 | <SchemaField.Void 64 | x-component="ArrayTable.Column" 65 | x-component-props={{ 66 | width: 120, 67 | title: 'Index', 68 | align: 'center', 69 | }} 70 | > 71 | <SchemaField.Void 72 | x-decorator="FormItem" 73 | required 74 | x-component="ArrayTable.Index" 75 | /> 76 | </SchemaField.Void> 77 | <SchemaField.Void 78 | x-component="ArrayTable.Column" 79 | x-component-props={{ title: 'A1', dataIndex: 'a1', width: 200 }} 80 | > 81 | <SchemaField.String 82 | name="a1" 83 | x-decorator="Editable" 84 | required 85 | x-component="Input" 86 | /> 87 | </SchemaField.Void> 88 | <SchemaField.Void 89 | x-component="ArrayTable.Column" 90 | x-component-props={{ title: 'A2', width: 200 }} 91 | > 92 | <SchemaField.String 93 | x-decorator="FormItem" 94 | name="a2" 95 | required 96 | x-component="Input" 97 | /> 98 | </SchemaField.Void> 99 | <SchemaField.Void 100 | x-component="ArrayTable.Column" 101 | x-component-props={{ title: 'A3', width: 200 }} 102 | > 103 | <SchemaField.String 104 | x-decorator="FormItem" 105 | name="a3" 106 | required 107 | x-component="Input" 108 | /> 109 | </SchemaField.Void> 110 | <SchemaField.Void 111 | x-component="ArrayTable.Column" 112 | x-component-props={{ 113 | title: 'Operations', 114 | dataIndex: 'operations', 115 | width: 200, 116 | fixed: 'right', 117 | }} 118 | > 119 | <SchemaField.Void x-component="FormItem"> 120 | <SchemaField.Void x-component="ArrayTable.Remove" /> 121 | <SchemaField.Void x-component="ArrayTable.MoveDown" /> 122 | <SchemaField.Void x-component="ArrayTable.MoveUp" /> 123 | </SchemaField.Void> 124 | </SchemaField.Void> 125 | </SchemaField.Object> 126 | <SchemaField.Void 127 | x-component="ArrayTable.Addition" 128 | title="添加条目" 129 | /> 130 | </SchemaField.Array> 131 | </SchemaField> 132 | <FormButtonGroup> 133 | <Submit onSubmit={console.log}>提交</Submit> 134 | <Button 135 | onClick={() => { 136 | form.setInitialValues({ 137 | array: range(100000), 138 | }) 139 | }} 140 | > 141 | 加载10W条超大数据 142 | </Button> 143 | </FormButtonGroup> 144 | <Message style={{ marginTop: 10 }} type="warning"> 145 | 注意:开启formily插件的页面,因为后台有数据通信,会占用浏览器算力,最好在无痕模式(无formily插件)下测试 146 | </Message> 147 | </FormProvider> 148 | ) 149 | } 150 | ``` 151 | 152 | ## JSON Schema 案例 153 | 154 | ```tsx 155 | import React from 'react' 156 | import { 157 | FormItem, 158 | Input, 159 | ArrayTable, 160 | Editable, 161 | FormButtonGroup, 162 | Submit, 163 | } from '@formily/next' 164 | import { createForm } from '@formily/core' 165 | import { FormProvider, createSchemaField } from '@formily/react' 166 | 167 | const SchemaField = createSchemaField({ 168 | components: { 169 | FormItem, 170 | Editable, 171 | Input, 172 | ArrayTable, 173 | }, 174 | }) 175 | 176 | const form = createForm() 177 | 178 | const schema = { 179 | type: 'object', 180 | properties: { 181 | array: { 182 | type: 'array', 183 | 'x-decorator': 'FormItem', 184 | 'x-component': 'ArrayTable', 185 | 'x-component-props': { 186 | pagination: { pageSize: 10 }, 187 | style: { width: '100%' }, 188 | }, 189 | items: { 190 | type: 'object', 191 | properties: { 192 | column1: { 193 | type: 'void', 194 | 'x-component': 'ArrayTable.Column', 195 | 'x-component-props': { width: 80, title: 'Sort', align: 'center' }, 196 | properties: { 197 | sort: { 198 | type: 'void', 199 | 'x-component': 'ArrayTable.SortHandle', 200 | }, 201 | }, 202 | }, 203 | column2: { 204 | type: 'void', 205 | 'x-component': 'ArrayTable.Column', 206 | 'x-component-props': { 207 | width: 120, 208 | title: 'Index', 209 | align: 'center', 210 | }, 211 | properties: { 212 | index: { 213 | type: 'void', 214 | 'x-component': 'ArrayTable.Index', 215 | }, 216 | }, 217 | }, 218 | column3: { 219 | type: 'void', 220 | 'x-component': 'ArrayTable.Column', 221 | 'x-component-props': { width: 200, title: 'A1' }, 222 | properties: { 223 | a1: { 224 | type: 'string', 225 | 'x-decorator': 'Editable', 226 | 'x-component': 'Input', 227 | }, 228 | }, 229 | }, 230 | column4: { 231 | type: 'void', 232 | 'x-component': 'ArrayTable.Column', 233 | 'x-component-props': { width: 200, title: 'A2' }, 234 | properties: { 235 | a2: { 236 | type: 'string', 237 | 'x-decorator': 'FormItem', 238 | 'x-component': 'Input', 239 | }, 240 | }, 241 | }, 242 | column5: { 243 | type: 'void', 244 | 'x-component': 'ArrayTable.Column', 245 | 'x-component-props': { width: 200, title: 'A3' }, 246 | properties: { 247 | a3: { 248 | type: 'string', 249 | 'x-decorator': 'FormItem', 250 | 'x-component': 'Input', 251 | }, 252 | }, 253 | }, 254 | column6: { 255 | type: 'void', 256 | 'x-component': 'ArrayTable.Column', 257 | 'x-component-props': { 258 | title: 'Operations', 259 | dataIndex: 'operations', 260 | width: 200, 261 | fixed: 'right', 262 | }, 263 | properties: { 264 | item: { 265 | type: 'void', 266 | 'x-component': 'FormItem', 267 | properties: { 268 | remove: { 269 | type: 'void', 270 | 'x-component': 'ArrayTable.Remove', 271 | }, 272 | moveDown: { 273 | type: 'void', 274 | 'x-component': 'ArrayTable.MoveDown', 275 | }, 276 | moveUp: { 277 | type: 'void', 278 | 'x-component': 'ArrayTable.MoveUp', 279 | }, 280 | }, 281 | }, 282 | }, 283 | }, 284 | }, 285 | }, 286 | properties: { 287 | add: { 288 | type: 'void', 289 | 'x-component': 'ArrayTable.Addition', 290 | title: '添加条目', 291 | }, 292 | }, 293 | }, 294 | }, 295 | } 296 | 297 | export default () => { 298 | return ( 299 | <FormProvider form={form}> 300 | <SchemaField schema={schema} /> 301 | <FormButtonGroup> 302 | <Submit onSubmit={console.log}>提交</Submit> 303 | </FormButtonGroup> 304 | </FormProvider> 305 | ) 306 | } 307 | ``` 308 | 309 | ## Effects 联动案例 310 | 311 | ```tsx 312 | import React from 'react' 313 | import { 314 | FormItem, 315 | Input, 316 | ArrayTable, 317 | Switch, 318 | FormButtonGroup, 319 | Submit, 320 | } from '@formily/next' 321 | import { createForm, onFieldChange, onFieldReact } from '@formily/core' 322 | import { FormProvider, createSchemaField } from '@formily/react' 323 | import { Button } from '@alifd/next' 324 | 325 | const SchemaField = createSchemaField({ 326 | components: { 327 | FormItem, 328 | Switch, 329 | Input, 330 | Button, 331 | ArrayTable, 332 | }, 333 | }) 334 | 335 | const form = createForm({ 336 | effects: () => { 337 | //主动联动模式 338 | onFieldChange('hideFirstColumn', ['value'], (field) => { 339 | field.query('array.column4').take((target) => { 340 | target.visible = !field.value 341 | }) 342 | field.query('array.*.a2').take((target) => { 343 | target.visible = !field.value 344 | }) 345 | }) 346 | //被动联动模式 347 | onFieldReact('array.*.a2', (field) => { 348 | field.visible = !field.query('.a1').get('value') 349 | }) 350 | }, 351 | }) 352 | 353 | export default () => { 354 | return ( 355 | <FormProvider form={form}> 356 | <SchemaField> 357 | <SchemaField.Boolean 358 | name="hideFirstColumn" 359 | x-decorator="FormItem" 360 | x-component="Switch" 361 | title="隐藏A2" 362 | /> 363 | <SchemaField.Array 364 | name="array" 365 | x-decorator="FormItem" 366 | x-component="ArrayTable" 367 | x-component-props={{ 368 | pagination: { pageSize: 10 }, 369 | style: { width: '100%' }, 370 | }} 371 | > 372 | <SchemaField.Object> 373 | <SchemaField.Void 374 | x-component="ArrayTable.Column" 375 | name="column1" 376 | x-component-props={{ width: 80, title: 'Sort', align: 'center' }} 377 | > 378 | <SchemaField.Void 379 | x-decorator="FormItem" 380 | required 381 | x-component="ArrayTable.SortHandle" 382 | /> 383 | </SchemaField.Void> 384 | <SchemaField.Void 385 | x-component="ArrayTable.Column" 386 | name="column2" 387 | x-component-props={{ 388 | width: 120, 389 | title: 'Index', 390 | align: 'center', 391 | }} 392 | > 393 | <SchemaField.String 394 | x-decorator="FormItem" 395 | required 396 | x-component="ArrayTable.Index" 397 | /> 398 | </SchemaField.Void> 399 | <SchemaField.Void 400 | x-component="ArrayTable.Column" 401 | name="column3" 402 | x-component-props={{ 403 | title: '显隐->A2', 404 | dataIndex: 'a1', 405 | width: 100, 406 | }} 407 | > 408 | <SchemaField.Boolean 409 | name="a1" 410 | x-decorator="FormItem" 411 | required 412 | x-component="Switch" 413 | /> 414 | </SchemaField.Void> 415 | <SchemaField.Void 416 | x-component="ArrayTable.Column" 417 | name="column4" 418 | x-component-props={{ title: 'A2', width: 200 }} 419 | > 420 | <SchemaField.String 421 | x-decorator="FormItem" 422 | name="a2" 423 | required 424 | x-component="Input" 425 | /> 426 | </SchemaField.Void> 427 | <SchemaField.Void 428 | x-component="ArrayTable.Column" 429 | name="column5" 430 | x-component-props={{ title: 'A3', width: 200 }} 431 | > 432 | <SchemaField.String 433 | x-decorator="FormItem" 434 | name="a3" 435 | required 436 | x-component="Input" 437 | /> 438 | </SchemaField.Void> 439 | <SchemaField.Void 440 | x-component="ArrayTable.Column" 441 | name="column6" 442 | x-component-props={{ 443 | title: 'Operations', 444 | dataIndex: 'operations', 445 | width: 200, 446 | fixed: 'right', 447 | }} 448 | > 449 | <SchemaField.Void x-component="FormItem"> 450 | <SchemaField.Void x-component="ArrayTable.Remove" /> 451 | <SchemaField.Void x-component="ArrayTable.MoveDown" /> 452 | <SchemaField.Void x-component="ArrayTable.MoveUp" /> 453 | </SchemaField.Void> 454 | </SchemaField.Void> 455 | </SchemaField.Object> 456 | <SchemaField.Void 457 | x-component="ArrayTable.Addition" 458 | title="添加条目" 459 | /> 460 | </SchemaField.Array> 461 | </SchemaField> 462 | <FormButtonGroup> 463 | <Submit onSubmit={console.log}>提交</Submit> 464 | </FormButtonGroup> 465 | </FormProvider> 466 | ) 467 | } 468 | ``` 469 | 470 | ## JSON Schema 联动案例 471 | 472 | ```tsx 473 | import React from 'react' 474 | import { 475 | FormItem, 476 | Input, 477 | ArrayTable, 478 | Switch, 479 | FormButtonGroup, 480 | Submit, 481 | } from '@formily/next' 482 | import { createForm } from '@formily/core' 483 | import { FormProvider, createSchemaField } from '@formily/react' 484 | 485 | const SchemaField = createSchemaField({ 486 | components: { 487 | FormItem, 488 | Switch, 489 | Input, 490 | ArrayTable, 491 | }, 492 | }) 493 | 494 | const form = createForm() 495 | 496 | const schema = { 497 | type: 'object', 498 | properties: { 499 | hideFirstColumn: { 500 | type: 'boolean', 501 | title: '隐藏A2', 502 | 'x-decorator': 'FormItem', 503 | 'x-component': 'Switch', 504 | }, 505 | array: { 506 | type: 'array', 507 | 'x-decorator': 'FormItem', 508 | 'x-component': 'ArrayTable', 509 | 'x-component-props': { 510 | pagination: { pageSize: 10 }, 511 | style: { width: '100%' }, 512 | }, 513 | items: { 514 | type: 'object', 515 | properties: { 516 | column1: { 517 | type: 'void', 518 | 'x-component': 'ArrayTable.Column', 519 | 'x-component-props': { width: 80, title: 'Sort', align: 'center' }, 520 | 521 | properties: { 522 | sort: { 523 | type: 'void', 524 | 'x-component': 'ArrayTable.SortHandle', 525 | }, 526 | }, 527 | }, 528 | column2: { 529 | type: 'void', 530 | 'x-component': 'ArrayTable.Column', 531 | 'x-component-props': { 532 | width: 120, 533 | title: 'Index', 534 | align: 'center', 535 | }, 536 | properties: { 537 | index: { 538 | type: 'void', 539 | 'x-component': 'ArrayTable.Index', 540 | }, 541 | }, 542 | }, 543 | column3: { 544 | type: 'void', 545 | 'x-component': 'ArrayTable.Column', 546 | 'x-component-props': { width: 100, title: '显隐->A2' }, 547 | properties: { 548 | a1: { 549 | type: 'boolean', 550 | 'x-decorator': 'FormItem', 551 | 'x-component': 'Switch', 552 | }, 553 | }, 554 | }, 555 | column4: { 556 | type: 'void', 557 | 'x-component': 'ArrayTable.Column', 558 | 'x-component-props': { width: 200, title: 'A2' }, 559 | 'x-reactions': [ 560 | { 561 | dependencies: ['hideFirstColumn'], 562 | when: '{{$deps[0]}}', 563 | fulfill: { 564 | schema: { 565 | 'x-visible': false, 566 | }, 567 | }, 568 | otherwise: { 569 | schema: { 570 | 'x-visible': true, 571 | }, 572 | }, 573 | }, 574 | ], 575 | properties: { 576 | a2: { 577 | type: 'string', 578 | 'x-decorator': 'FormItem', 579 | 'x-component': 'Input', 580 | required: true, 581 | 'x-reactions': [ 582 | { 583 | dependencies: ['.a1', 'hideFirstColumn'], 584 | when: '{{$deps[1] || $deps[0]}}', 585 | fulfill: { 586 | schema: { 587 | 'x-visible': false, 588 | }, 589 | }, 590 | otherwise: { 591 | schema: { 592 | 'x-visible': true, 593 | }, 594 | }, 595 | }, 596 | ], 597 | }, 598 | }, 599 | }, 600 | column5: { 601 | type: 'void', 602 | 'x-component': 'ArrayTable.Column', 603 | 'x-component-props': { width: 200, title: 'A3' }, 604 | properties: { 605 | a3: { 606 | type: 'string', 607 | required: true, 608 | 'x-decorator': 'FormItem', 609 | 'x-component': 'Input', 610 | }, 611 | }, 612 | }, 613 | column6: { 614 | type: 'void', 615 | 'x-component': 'ArrayTable.Column', 616 | 'x-component-props': { 617 | title: 'Operations', 618 | dataIndex: 'operations', 619 | width: 200, 620 | fixed: 'right', 621 | }, 622 | properties: { 623 | item: { 624 | type: 'void', 625 | 'x-component': 'FormItem', 626 | properties: { 627 | remove: { 628 | type: 'void', 629 | 'x-component': 'ArrayTable.Remove', 630 | }, 631 | moveDown: { 632 | type: 'void', 633 | 'x-component': 'ArrayTable.MoveDown', 634 | }, 635 | moveUp: { 636 | type: 'void', 637 | 'x-component': 'ArrayTable.MoveUp', 638 | }, 639 | }, 640 | }, 641 | }, 642 | }, 643 | }, 644 | }, 645 | properties: { 646 | add: { 647 | type: 'void', 648 | 'x-component': 'ArrayTable.Addition', 649 | title: '添加条目', 650 | }, 651 | }, 652 | }, 653 | }, 654 | } 655 | 656 | export default () => { 657 | return ( 658 | <FormProvider form={form}> 659 | <SchemaField schema={schema} /> 660 | <FormButtonGroup> 661 | <Submit onSubmit={console.log}>提交</Submit> 662 | </FormButtonGroup> 663 | </FormProvider> 664 | ) 665 | } 666 | ``` 667 | 668 | ## API 669 | 670 | ### ArrayTable 671 | 672 | > 表格组件 673 | 674 | 扩展属性 675 | 676 | | 属性名 | 类型 | 描述 | 默认值 | 677 | | ---------- | ------------------------- | ------------ | ------ | 678 | | onAdd | `(index: number) => void` | 增加方法 | | 679 | | onRemove | `(index: number) => void` | 删除方法 | | 680 | | onCopy | `(index: number) => void` | 复制方法 | | 681 | | onMoveUp | `(index: number) => void` | 向上移动方法 | | 682 | | onMoveDown | `(index: number) => void` | 向下移动方法 | | 683 | 684 | 其余参考 https://fusion.design/pc/component/basic/table 685 | 686 | ### ArrayTable.Column 687 | 688 | > 表格列 689 | 690 | 参考 https://fusion.design/pc/component/basic/table 691 | 692 | ### ArrayTable.SortHandle 693 | 694 | > 拖拽手柄 695 | 696 | 参考 https://ant.design/components/icon-cn/ 697 | 698 | ### ArrayTable.Addition 699 | 700 | > 添加按钮 701 | 702 | 扩展属性 703 | 704 | | 属性名 | 类型 | 描述 | 默认值 | 705 | | ------------ | --------------------- | -------- | -------- | 706 | | title | ReactText | 文案 | | 707 | | method | `'push' \| 'unshift'` | 添加方式 | `'push'` | 708 | | defaultValue | `any` | 默认值 | | 709 | 710 | 其余参考 https://fusion.design/pc/component/basic/button 711 | 712 | 注意:title 属性可以接收 Field 模型中的 title 映射,也就是在 Field 上传 title 也是生效的 713 | 714 | ### ArrayTable.Remove 715 | 716 | > 删除按钮 717 | 718 | | 属性名 | 类型 | 描述 | 默认值 | 719 | | ------ | --------- | ---- | ------ | 720 | | title | ReactText | 文案 | | 721 | 722 | 其余参考 https://ant.design/components/icon-cn/ 723 | 724 | 注意:title 属性可以接收 Field 模型中的 title 映射,也就是在 Field 上传 title 也是生效的 725 | 726 | ### ArrayTable.MoveDown 727 | 728 | > 下移按钮 729 | 730 | | 属性名 | 类型 | 描述 | 默认值 | 731 | | ------ | --------- | ---- | ------ | 732 | | title | ReactText | 文案 | | 733 | 734 | 其余参考 https://ant.design/components/icon-cn/ 735 | 736 | 注意:title 属性可以接收 Field 模型中的 title 映射,也就是在 Field 上传 title 也是生效的 737 | 738 | ### ArrayTable.MoveUp 739 | 740 | > 上移按钮 741 | 742 | | 属性名 | 类型 | 描述 | 默认值 | 743 | | ------ | --------- | ---- | ------ | 744 | | title | ReactText | 文案 | | 745 | 746 | 其余参考 https://ant.design/components/icon-cn/ 747 | 748 | 注意:title 属性可以接收 Field 模型中的 title 映射,也就是在 Field 上传 title 也是生效的 749 | 750 | ### ArrayTable.Index 751 | 752 | > 索引渲染器 753 | 754 | 无属性 755 | 756 | ### ArrayTable.useIndex 757 | 758 | > 读取当前渲染行索引的 React Hook 759 | 760 | ### ArrayTable.useRecord 761 | 762 | > 读取当前渲染记录的 React Hook 763 | ``` -------------------------------------------------------------------------------- /packages/core/docs/api/entry/FormEffectHooks.md: -------------------------------------------------------------------------------- ```markdown 1 | --- 2 | order: 1 3 | --- 4 | 5 | # Form Effect Hooks 6 | 7 | ## onFormInit 8 | 9 | #### Description 10 | 11 | Used to monitor the side effect hook of a form initialization, we will trigger the initialization event when we call createForm 12 | 13 | #### Signature 14 | 15 | ```ts 16 | interface onFormInit { 17 | (callback: (form: Form) => void) 18 | } 19 | ``` 20 | 21 | #### Example 22 | 23 | ```tsx 24 | import React, { useMemo, useState } from 'react' 25 | import { createForm, onFormInit } from '@formily/core' 26 | import { ActionResponse } from './ActionResponse' 27 | 28 | export default () => { 29 | const [response, setResponse] = useState('') 30 | useMemo( 31 | () => 32 | createForm({ 33 | effects() { 34 | onFormInit(() => { 35 | setResponse('The form has been initialized') 36 | }) 37 | }, 38 | }), 39 | [] 40 | ) 41 | return <ActionResponse response={response} /> 42 | } 43 | ``` 44 | 45 | ## onFormMount 46 | 47 | #### Description 48 | 49 | Used to monitor the side-effect hook that the form has been mounted, we will trigger the mount event when we call onMount 50 | 51 | #### Signature 52 | 53 | ```ts 54 | interface onFormMount { 55 | (callback: (form: Form) => void) 56 | } 57 | ``` 58 | 59 | #### Example 60 | 61 | ```tsx 62 | import React, { useMemo, useState } from 'react' 63 | import { createForm, onFormMount } from '@formily/core' 64 | import { ActionResponse } from './ActionResponse' 65 | 66 | export default () => { 67 | const [response, setResponse] = useState('') 68 | const form = useMemo( 69 | () => 70 | createForm({ 71 | effects() { 72 | onFormMount(() => { 73 | setResponse('The form has been mounted') 74 | }) 75 | }, 76 | }), 77 | [] 78 | ) 79 | return ( 80 | <ActionResponse response={response}> 81 | <button 82 | onClick={() => { 83 | form.onMount() 84 | }} 85 | > 86 | Mount form 87 | </button> 88 | </ActionResponse> 89 | ) 90 | } 91 | ``` 92 | 93 | ## onFormUnmount 94 | 95 | #### Description 96 | 97 | Used to monitor the side effect hook that the form has been unloaded, we will trigger the unmount event when we call onUnmount 98 | 99 | #### Signature 100 | 101 | ```ts 102 | interface onFormUnmount { 103 | (callback: (form: Form) => void) 104 | } 105 | ``` 106 | 107 | #### Example 108 | 109 | ```tsx 110 | import React, { useMemo, useState } from 'react' 111 | import { createForm, onFormUnmount } from '@formily/core' 112 | import { ActionResponse } from './ActionResponse' 113 | 114 | export default () => { 115 | const [response, setResponse] = useState('') 116 | const form = useMemo( 117 | () => 118 | createForm({ 119 | effects() { 120 | onFormUnmount(() => { 121 | setResponse('Form has been uninstalled') 122 | }) 123 | }, 124 | }), 125 | [] 126 | ) 127 | return ( 128 | <ActionResponse response={response}> 129 | <button 130 | onClick={() => { 131 | form.onUnmount() 132 | }} 133 | > 134 | Uninstall form 135 | </button> 136 | </ActionResponse> 137 | ) 138 | } 139 | ``` 140 | 141 | ## onFormReact 142 | 143 | #### Description 144 | 145 | The side effect hook used to implement form response logic. Its core principle is that the callback function will be executed when the form is initialized, and dependencies will be automatically tracked at the same time. The callback function will be executed repeatedly when the dependent data changes. 146 | 147 | #### Signature 148 | 149 | ```ts 150 | interface onFormReact { 151 | (callback: (form: Form) => void) 152 | } 153 | ``` 154 | 155 | #### Example 156 | 157 | ```tsx 158 | import React, { useMemo, useState } from 'react' 159 | import { createForm, onFormReact } from '@formily/core' 160 | import { ActionResponse } from './ActionResponse' 161 | 162 | export default () => { 163 | const [response, setResponse] = useState('') 164 | const form = useMemo( 165 | () => 166 | createForm({ 167 | effects() { 168 | onFormReact((form) => { 169 | if (form.values.input == 'Hello') { 170 | setResponse('Response Hello') 171 | } else if (form.values.input == 'World') { 172 | setResponse('Response to World') 173 | } 174 | }) 175 | }, 176 | }), 177 | [] 178 | ) 179 | return ( 180 | <ActionResponse response={response}> 181 | <button 182 | onClick={() => { 183 | form.setValuesIn('input', 'Hello') 184 | }} 185 | > 186 | Hello 187 | </button> 188 | <button 189 | onClick={() => { 190 | form.setValuesIn('input', 'World') 191 | }} 192 | > 193 | World 194 | </button> 195 | </ActionResponse> 196 | ) 197 | } 198 | ``` 199 | 200 | ## onFormValuesChange 201 | 202 | #### Description 203 | 204 | Side effect hooks for monitoring form value changes 205 | 206 | <Alert> 207 | It should be noted that this hook is triggered synchronously. For some behaviors that trigger `set` operation of `Proxy` multiple times, the results may not be as expected. For example, when deleting elements from array by `splice`, the array length will be the same as before deletion. (<a href="https://github.com/alibaba/formily/issues/2128">#2128</a>) 208 | </Alert> 209 | 210 | #### Signature 211 | 212 | ```ts 213 | interface onFormValuesChange { 214 | (callback: (form: Form) => void) 215 | } 216 | ``` 217 | 218 | #### Example 219 | 220 | ```tsx 221 | import React, { useMemo, useState } from 'react' 222 | import { createForm, onFormValuesChange } from '@formily/core' 223 | import { ActionResponse } from './ActionResponse' 224 | 225 | export default () => { 226 | const [response, setResponse] = useState('') 227 | const form = useMemo( 228 | () => 229 | createForm({ 230 | effects() { 231 | onFormValuesChange((form) => { 232 | setResponse('Form value change: ' + form.values.input) 233 | }) 234 | }, 235 | }), 236 | [] 237 | ) 238 | return ( 239 | <ActionResponse response={response}> 240 | <button 241 | onClick={() => { 242 | form.setValuesIn('input', 'Hello World') 243 | }} 244 | > 245 | Hello World 246 | </button> 247 | </ActionResponse> 248 | ) 249 | } 250 | ``` 251 | 252 | ## onFormInitialValuesChange 253 | 254 | #### Description 255 | 256 | Side effect hooks used to monitor the changes of the default value of the form 257 | 258 | #### Signature 259 | 260 | ```ts 261 | interface onFormInitialValuesChange { 262 | (callback: (form: Form) => void) 263 | } 264 | ``` 265 | 266 | #### Example 267 | 268 | ```tsx 269 | import React, { useMemo, useState } from 'react' 270 | import { createForm, onFormInitialValuesChange } from '@formily/core' 271 | import { ActionResponse } from './ActionResponse' 272 | 273 | export default () => { 274 | const [response, setResponse] = useState('') 275 | const form = useMemo( 276 | () => 277 | createForm({ 278 | effects() { 279 | onFormInitialValuesChange((form) => { 280 | setResponse('Form default value change: ' + form.values.input) 281 | }) 282 | }, 283 | }), 284 | [] 285 | ) 286 | return ( 287 | <ActionResponse response={response}> 288 | <button 289 | onClick={() => { 290 | form.setInitialValuesIn('input', 'Hello World') 291 | }} 292 | > 293 | Hello World 294 | </button> 295 | </ActionResponse> 296 | ) 297 | } 298 | ``` 299 | 300 | ## onFormInputChange 301 | 302 | #### Description 303 | 304 | Side effect hook for listening to field input 305 | 306 | #### Signature 307 | 308 | ```ts 309 | interface onFormInputChange { 310 | (callback: (form: Form) => void) 311 | } 312 | ``` 313 | 314 | #### Example 315 | 316 | ```tsx 317 | import React, { useMemo, useState } from 'react' 318 | import { createForm, onFormInputChange } from '@formily/core' 319 | import { ActionResponse } from './ActionResponse' 320 | 321 | export default () => { 322 | const [response, setResponse] = useState('') 323 | const form = useMemo( 324 | () => 325 | createForm({ 326 | effects() { 327 | onFormInputChange((form) => { 328 | setResponse('Character input change: ' + form.values.input) 329 | }) 330 | }, 331 | }), 332 | [] 333 | ) 334 | return ( 335 | <ActionResponse response={response}> 336 | <button 337 | onClick={() => { 338 | form 339 | .createField({ 340 | name: 'input', 341 | }) 342 | .onInput('Hello World') 343 | }} 344 | > 345 | Hello World 346 | </button> 347 | </ActionResponse> 348 | ) 349 | } 350 | ``` 351 | 352 | ## onFormSubmit 353 | 354 | #### Description 355 | 356 | Side effect hook for monitoring form submission 357 | 358 | #### Signature 359 | 360 | ```ts 361 | interface onFormSubmit { 362 | (callback: (form: Form) => void) 363 | } 364 | ``` 365 | 366 | #### Example 367 | 368 | ```tsx 369 | import React, { useMemo, useState } from 'react' 370 | import { createForm, onFormSubmit } from '@formily/core' 371 | import { ActionResponse } from './ActionResponse' 372 | 373 | export default () => { 374 | const [response, setResponse] = useState('') 375 | const form = useMemo( 376 | () => 377 | createForm({ 378 | effects() { 379 | onFormSubmit(() => { 380 | setResponse('Form has been submitted') 381 | }) 382 | }, 383 | }), 384 | [] 385 | ) 386 | return ( 387 | <ActionResponse response={response}> 388 | <button 389 | onClick={() => { 390 | form.submit() 391 | }} 392 | > 393 | Submit 394 | </button> 395 | </ActionResponse> 396 | ) 397 | } 398 | ``` 399 | 400 | ## onFormSubmitStart 401 | 402 | #### Description 403 | 404 | Side effect hook for monitoring the start of form submission 405 | 406 | #### Signature 407 | 408 | ```ts 409 | interface onFormSubmitStart { 410 | (callback: (form: Form) => void) 411 | } 412 | ``` 413 | 414 | #### Example 415 | 416 | ```tsx 417 | import React, { useMemo, useState } from 'react' 418 | import { createForm, onFormSubmitStart } from '@formily/core' 419 | import { ActionResponse } from './ActionResponse' 420 | 421 | export default () => { 422 | const [response, setResponse] = useState('') 423 | const form = useMemo( 424 | () => 425 | createForm({ 426 | effects() { 427 | onFormSubmitStart(() => { 428 | setResponse('form submission start') 429 | }) 430 | }, 431 | }), 432 | [] 433 | ) 434 | return ( 435 | <ActionResponse response={response}> 436 | <button 437 | onClick={() => { 438 | form.submit() 439 | }} 440 | > 441 | Submit 442 | </button> 443 | </ActionResponse> 444 | ) 445 | } 446 | ``` 447 | 448 | ## onFormSubmitEnd 449 | 450 | #### Description 451 | 452 | Side effect hook for monitoring the end of form submission 453 | 454 | #### Signature 455 | 456 | ```ts 457 | interface onFormSubmitEnd { 458 | (callback: (form: Form) => void) 459 | } 460 | ``` 461 | 462 | #### Example 463 | 464 | ```tsx 465 | import React, { useMemo, useState } from 'react' 466 | import { createForm, onFormSubmitEnd } from '@formily/core' 467 | import { ActionResponse } from './ActionResponse' 468 | 469 | export default () => { 470 | const [response, setResponse] = useState('') 471 | const form = useMemo( 472 | () => 473 | createForm({ 474 | effects() { 475 | onFormSubmitEnd(() => { 476 | setResponse('End of form submission') 477 | }) 478 | }, 479 | }), 480 | [] 481 | ) 482 | return ( 483 | <ActionResponse response={response}> 484 | <button 485 | onClick={() => { 486 | form.submit() 487 | }} 488 | > 489 | Submit 490 | </button> 491 | </ActionResponse> 492 | ) 493 | } 494 | ``` 495 | 496 | ## onFormSubmitFailed 497 | 498 | #### Description 499 | 500 | Side-effect hooks used to monitor form submission failures 501 | 502 | #### Signature 503 | 504 | ```ts 505 | interface onFormSubmitFailed { 506 | (callback: (form: Form) => void) 507 | } 508 | ``` 509 | 510 | #### Example 511 | 512 | ```tsx 513 | import React, { useMemo, useState } from 'react' 514 | import { createForm, onFormSubmitFailed } from '@formily/core' 515 | import { ActionResponse } from './ActionResponse' 516 | 517 | export default () => { 518 | const [response, setResponse] = useState('') 519 | const form = useMemo( 520 | () => 521 | createForm({ 522 | effects() { 523 | onFormSubmitFailed(() => { 524 | setResponse('Form submission failed') 525 | }) 526 | }, 527 | }), 528 | [] 529 | ) 530 | const form2 = useMemo( 531 | () => 532 | createForm({ 533 | effects() { 534 | onFormSubmitFailed(() => { 535 | setResponse('Form verification failed') 536 | }) 537 | }, 538 | }), 539 | [] 540 | ) 541 | return ( 542 | <ActionResponse response={response}> 543 | <button 544 | onClick={() => { 545 | form.submit(() => { 546 | return Promise.reject('Runtime Error') 547 | }) 548 | }} 549 | > 550 | Submit Runtime Error 551 | </button> 552 | <button 553 | onClick={() => { 554 | form2.createField({ 555 | name: 'input', 556 | required: true, 557 | }) 558 | form2.submit() 559 | }} 560 | > 561 | Submit Validate Error 562 | </button> 563 | </ActionResponse> 564 | ) 565 | } 566 | ``` 567 | 568 | ## onFormSubmitSuccess 569 | 570 | #### Description 571 | 572 | Side effect hook used to monitor the success of form submission 573 | 574 | #### Signature 575 | 576 | ```ts 577 | interface onFormSubmitSuccess { 578 | (callback: (form: Form) => void) 579 | } 580 | ``` 581 | 582 | #### Example 583 | 584 | ```tsx 585 | import React, { useMemo, useState } from 'react' 586 | import { createForm, onFormSubmitSuccess } from '@formily/core' 587 | import { ActionResponse } from './ActionResponse' 588 | 589 | export default () => { 590 | const [response, setResponse] = useState('') 591 | const form = useMemo( 592 | () => 593 | createForm({ 594 | effects() { 595 | onFormSubmitSuccess(() => { 596 | setResponse('Form submission is successful') 597 | }) 598 | }, 599 | }), 600 | [] 601 | ) 602 | return ( 603 | <ActionResponse response={response}> 604 | <button 605 | onClick={() => { 606 | form.submit() 607 | }} 608 | > 609 | Submit 610 | </button> 611 | </ActionResponse> 612 | ) 613 | } 614 | ``` 615 | 616 | ## onFormSubmitValidateStart 617 | 618 | #### Description 619 | 620 | Side effect hook used to monitor the start of field validation of the form submission process 621 | 622 | #### Signature 623 | 624 | ```ts 625 | interface onFormSubmitValidateStart { 626 | (callback: (form: Form) => void) 627 | } 628 | ``` 629 | 630 | #### Example 631 | 632 | ```tsx 633 | import React, { useMemo, useState } from 'react' 634 | import { createForm, onFormSubmitValidateStart } from '@formily/core' 635 | import { ActionResponse } from './ActionResponse' 636 | 637 | export default () => { 638 | const [response, setResponse] = useState('') 639 | const form = useMemo( 640 | () => 641 | createForm({ 642 | effects() { 643 | onFormSubmitValidateStart(() => { 644 | setResponse('Form submission verification starts') 645 | }) 646 | }, 647 | }), 648 | [] 649 | ) 650 | return ( 651 | <ActionResponse response={response}> 652 | <button 653 | onClick={() => { 654 | form.createField({ 655 | name: 'input', 656 | required: true, 657 | }) 658 | form.submit() 659 | }} 660 | > 661 | Submit 662 | </button> 663 | </ActionResponse> 664 | ) 665 | } 666 | ``` 667 | 668 | ## onFormSubmitValidateEnd 669 | 670 | #### Description 671 | 672 | Side effect hook used to monitor the end of the field validation of the form submission process 673 | 674 | #### Signature 675 | 676 | ```ts 677 | interface onFormSubmitValidateEnd { 678 | (callback: (form: Form) => void) 679 | } 680 | ``` 681 | 682 | #### Example 683 | 684 | ```tsx 685 | import React, { useMemo, useState } from 'react' 686 | import { createForm, onFormSubmitValidateEnd } from '@formily/core' 687 | import { ActionResponse } from './ActionResponse' 688 | 689 | export default () => { 690 | const [response, setResponse] = useState('') 691 | const form = useMemo( 692 | () => 693 | createForm({ 694 | effects() { 695 | onFormSubmitValidateEnd(() => { 696 | setResponse('Form submission verification is over') 697 | }) 698 | }, 699 | }), 700 | [] 701 | ) 702 | return ( 703 | <ActionResponse response={response}> 704 | <button 705 | onClick={() => { 706 | form.createField({ 707 | name: 'input', 708 | required: true, 709 | }) 710 | form.submit() 711 | }} 712 | > 713 | Submit 714 | </button> 715 | </ActionResponse> 716 | ) 717 | } 718 | ``` 719 | 720 | ## onFormSubmitValidateFailed 721 | 722 | #### Description 723 | 724 | Side effect hook used to monitor the field validation failure of the form submission process 725 | 726 | #### Signature 727 | 728 | ```ts 729 | interface onFormSubmitValidateFailed { 730 | (callback: (form: Form) => void) 731 | } 732 | ``` 733 | 734 | #### Example 735 | 736 | ```tsx 737 | import React, { useMemo, useState } from 'react' 738 | import { createForm, onFormSubmitValidateFailed } from '@formily/core' 739 | import { ActionResponse } from './ActionResponse' 740 | 741 | export default () => { 742 | const [response, setResponse] = useState('') 743 | const form = useMemo( 744 | () => 745 | createForm({ 746 | effects() { 747 | onFormSubmitValidateFailed(() => { 748 | setResponse('Form submission verification failed') 749 | }) 750 | }, 751 | }), 752 | [] 753 | ) 754 | return ( 755 | <ActionResponse response={response}> 756 | <button 757 | onClick={() => { 758 | form.createField({ 759 | name: 'input', 760 | required: true, 761 | }) 762 | form.submit() 763 | }} 764 | > 765 | Submit 766 | </button> 767 | </ActionResponse> 768 | ) 769 | } 770 | ``` 771 | 772 | ## onFormSubmitValidateSuccess 773 | 774 | #### Description 775 | 776 | Side-effect hook used to monitor the successful field verification of the form submission process 777 | 778 | #### Signature 779 | 780 | ```ts 781 | interface onFormSubmitValidateSuccess { 782 | (callback: (form: Form) => void) 783 | } 784 | ``` 785 | 786 | #### Example 787 | 788 | ```tsx 789 | import React, { useMemo, useState } from 'react' 790 | import { createForm, onFormSubmitValidateSuccess } from '@formily/core' 791 | import { ActionResponse } from './ActionResponse' 792 | 793 | export default () => { 794 | const [response, setResponse] = useState('') 795 | const form = useMemo( 796 | () => 797 | createForm({ 798 | effects() { 799 | onFormSubmitValidateSuccess(() => { 800 | setResponse('Form submission verification succeeded') 801 | }) 802 | }, 803 | }), 804 | [] 805 | ) 806 | return ( 807 | <ActionResponse response={response}> 808 | <button 809 | onClick={() => { 810 | form.createField({ 811 | name: 'input', 812 | }) 813 | form.submit() 814 | }} 815 | > 816 | Submit 817 | </button> 818 | </ActionResponse> 819 | ) 820 | } 821 | ``` 822 | 823 | ## onFormValidateStart 824 | 825 | #### Description 826 | 827 | Side effect hook for monitoring the start of form validation 828 | 829 | #### Signature 830 | 831 | ```ts 832 | interface onFormValidateStart { 833 | (callback: (form: Form) => void) 834 | } 835 | ``` 836 | 837 | #### Example 838 | 839 | ```tsx 840 | import React, { useMemo, useState } from 'react' 841 | import { createForm, onFormValidateStart } from '@formily/core' 842 | import { ActionResponse } from './ActionResponse' 843 | 844 | export default () => { 845 | const [response, setResponse] = useState('') 846 | const form = useMemo( 847 | () => 848 | createForm({ 849 | effects() { 850 | onFormValidateStart(() => { 851 | setResponse('Form verification starts') 852 | }) 853 | }, 854 | }), 855 | [] 856 | ) 857 | return ( 858 | <ActionResponse response={response}> 859 | <button 860 | onClick={() => { 861 | form.createField({ 862 | name: 'input', 863 | required: true, 864 | }) 865 | form.validate() 866 | }} 867 | > 868 | Submit 869 | </button> 870 | </ActionResponse> 871 | ) 872 | } 873 | ``` 874 | 875 | ## onFormValidateEnd 876 | 877 | #### Description 878 | 879 | Side effect hook for monitoring the end of form validation 880 | 881 | #### Signature 882 | 883 | ```ts 884 | interface onFormValidateEnd { 885 | (callback: (form: Form) => void) 886 | } 887 | ``` 888 | 889 | #### Example 890 | 891 | ```tsx 892 | import React, { useMemo, useState } from 'react' 893 | import { createForm, onFormValidateEnd } from '@formily/core' 894 | import { ActionResponse } from './ActionResponse' 895 | 896 | export default () => { 897 | const [response, setResponse] = useState('') 898 | const form = useMemo( 899 | () => 900 | createForm({ 901 | effects() { 902 | onFormValidateEnd(() => { 903 | setResponse('Form verification end') 904 | }) 905 | }, 906 | }), 907 | [] 908 | ) 909 | return ( 910 | <ActionResponse response={response}> 911 | <button 912 | onClick={() => { 913 | form.createField({ 914 | name: 'input', 915 | required: true, 916 | }) 917 | form.validate() 918 | }} 919 | > 920 | Submit 921 | </button> 922 | </ActionResponse> 923 | ) 924 | } 925 | ``` 926 | 927 | ## onFormValidateFailed 928 | 929 | #### Description 930 | 931 | Side-effect hooks used to monitor form validation failures 932 | 933 | #### Signature 934 | 935 | ```ts 936 | interface onFormValidateFailed { 937 | (callback: (form: Form) => void) 938 | } 939 | ``` 940 | 941 | #### Example 942 | 943 | ```tsx 944 | import React, { useMemo, useState } from 'react' 945 | import { createForm, onFormValidateFailed } from '@formily/core' 946 | import { ActionResponse } from './ActionResponse' 947 | 948 | export default () => { 949 | const [response, setResponse] = useState('') 950 | const form = useMemo( 951 | () => 952 | createForm({ 953 | effects() { 954 | onFormValidateFailed(() => { 955 | setResponse('Form verification failed') 956 | }) 957 | }, 958 | }), 959 | [] 960 | ) 961 | return ( 962 | <ActionResponse response={response}> 963 | <button 964 | onClick={() => { 965 | form.createField({ 966 | name: 'input', 967 | required: true, 968 | }) 969 | form.validate() 970 | }} 971 | > 972 | Submit 973 | </button> 974 | </ActionResponse> 975 | ) 976 | } 977 | ``` 978 | 979 | ## onFormValidateSuccess 980 | 981 | #### Description 982 | 983 | Side effect hook for monitoring the start of form validation 984 | 985 | #### Signature 986 | 987 | ```ts 988 | interface onFormValidateSuccess { 989 | (callback: (form: Form) => void) 990 | } 991 | ``` 992 | 993 | #### Example 994 | 995 | ```tsx 996 | import React, { useMemo, useState } from 'react' 997 | import { createForm, onFormValidateSuccess } from '@formily/core' 998 | import { ActionResponse } from './ActionResponse' 999 | 1000 | export default () => { 1001 | const [response, setResponse] = useState('') 1002 | const form = useMemo( 1003 | () => 1004 | createForm({ 1005 | effects() { 1006 | onFormValidateSuccess(() => { 1007 | setResponse('Form verification succeeded') 1008 | }) 1009 | }, 1010 | }), 1011 | [] 1012 | ) 1013 | return ( 1014 | <ActionResponse response={response}> 1015 | <button 1016 | onClick={() => { 1017 | form.createField({ 1018 | name: 'input', 1019 | }) 1020 | form.validate() 1021 | }} 1022 | > 1023 | Submit 1024 | </button> 1025 | </ActionResponse> 1026 | ) 1027 | } 1028 | ``` 1029 | ``` -------------------------------------------------------------------------------- /packages/next/docs/components/ArrayItems.zh-CN.md: -------------------------------------------------------------------------------- ```markdown 1 | # ArrayItems 2 | 3 | > 自增列表,对于简单的自增编辑场景比较适合,或者对于空间要求高的场景比较适合 4 | > 5 | > 注意:该组件只适用于 Schema 场景 6 | 7 | ## Markup Schema 案例 8 | 9 | ```tsx 10 | import React from 'react' 11 | import { 12 | FormItem, 13 | Input, 14 | Editable, 15 | Select, 16 | DatePicker, 17 | ArrayItems, 18 | FormButtonGroup, 19 | Submit, 20 | Space, 21 | } from '@formily/next' 22 | import { createForm } from '@formily/core' 23 | import { FormProvider, createSchemaField } from '@formily/react' 24 | 25 | const SchemaField = createSchemaField({ 26 | components: { 27 | FormItem, 28 | DatePicker, 29 | Editable, 30 | Space, 31 | Input, 32 | Select, 33 | ArrayItems, 34 | }, 35 | }) 36 | 37 | const form = createForm() 38 | 39 | export default () => { 40 | return ( 41 | <FormProvider form={form}> 42 | <SchemaField> 43 | <SchemaField.Array 44 | name="string_array" 45 | title="字符串数组" 46 | x-decorator="FormItem" 47 | x-component="ArrayItems" 48 | > 49 | <SchemaField.Void x-component="Space"> 50 | <SchemaField.Void 51 | x-decorator="FormItem" 52 | x-component="ArrayItems.SortHandle" 53 | /> 54 | <SchemaField.String 55 | x-decorator="FormItem" 56 | required 57 | name="input" 58 | x-component="Input" 59 | /> 60 | <SchemaField.Void 61 | x-decorator="FormItem" 62 | x-component="ArrayItems.Remove" 63 | /> 64 | <SchemaField.Void 65 | x-decorator="FormItem" 66 | x-component="ArrayItems.Copy" 67 | /> 68 | </SchemaField.Void> 69 | <SchemaField.Void 70 | x-component="ArrayItems.Addition" 71 | x-component-props={{ method: 'unshift' }} 72 | title="添加条目" 73 | /> 74 | </SchemaField.Array> 75 | <SchemaField.Array 76 | name="array" 77 | title="对象数组" 78 | x-decorator="FormItem" 79 | x-component="ArrayItems" 80 | > 81 | <SchemaField.Object> 82 | <SchemaField.Void x-component="Space"> 83 | <SchemaField.Void 84 | x-decorator="FormItem" 85 | x-component="ArrayItems.SortHandle" 86 | /> 87 | <SchemaField.String 88 | x-decorator="FormItem" 89 | required 90 | title="日期" 91 | name="date" 92 | x-component="DatePicker.RangePicker" 93 | x-component-props={{ 94 | style: { 95 | width: 160, 96 | }, 97 | }} 98 | /> 99 | <SchemaField.String 100 | x-decorator="FormItem" 101 | required 102 | title="输入框" 103 | name="input" 104 | x-component="Input" 105 | /> 106 | <SchemaField.String 107 | x-decorator="FormItem" 108 | required 109 | title="选择框" 110 | name="select" 111 | enum={[ 112 | { label: '选项1', value: 1 }, 113 | { label: '选项2', value: 2 }, 114 | ]} 115 | x-component="Select" 116 | x-component-props={{ 117 | style: { 118 | width: 160, 119 | }, 120 | }} 121 | /> 122 | <SchemaField.Void 123 | x-decorator="FormItem" 124 | x-component="ArrayItems.Remove" 125 | /> 126 | </SchemaField.Void> 127 | </SchemaField.Object> 128 | <SchemaField.Void 129 | x-component="ArrayItems.Addition" 130 | title="添加条目" 131 | /> 132 | </SchemaField.Array> 133 | <SchemaField.Array 134 | name="array2" 135 | title="对象数组" 136 | x-decorator="FormItem" 137 | x-component="ArrayItems" 138 | x-component-props={{ style: { width: 300 } }} 139 | > 140 | <SchemaField.Object x-decorator="ArrayItems.Item"> 141 | <SchemaField.Void 142 | x-decorator="FormItem" 143 | x-component="ArrayItems.SortHandle" 144 | /> 145 | <SchemaField.String 146 | x-decorator="Editable" 147 | title="输入框" 148 | name="input" 149 | x-component="Input" 150 | /> 151 | <SchemaField.Object 152 | name="config" 153 | x-component="Editable.Popover" 154 | required 155 | title="配置复杂数据" 156 | x-reactions={(field) => 157 | (field.title = field.value?.input || field.title) 158 | } 159 | > 160 | <SchemaField.String 161 | x-decorator="FormItem" 162 | required 163 | title="日期" 164 | name="date" 165 | x-component="DatePicker.RangePicker" 166 | x-component-props={{ 167 | style: { width: '100%' }, 168 | followTrigger: true, 169 | }} 170 | /> 171 | <SchemaField.String 172 | x-decorator="FormItem" 173 | required 174 | title="输入框" 175 | name="input" 176 | x-component="Input" 177 | /> 178 | </SchemaField.Object> 179 | <SchemaField.Void 180 | x-decorator="FormItem" 181 | x-component="ArrayItems.Remove" 182 | /> 183 | </SchemaField.Object> 184 | <SchemaField.Void 185 | x-component="ArrayItems.Addition" 186 | title="添加条目" 187 | /> 188 | </SchemaField.Array> 189 | </SchemaField> 190 | <FormButtonGroup> 191 | <Submit onSubmit={console.log}>提交</Submit> 192 | </FormButtonGroup> 193 | </FormProvider> 194 | ) 195 | } 196 | ``` 197 | 198 | ## JSON Schema 案例 199 | 200 | ```tsx 201 | import React from 'react' 202 | import { 203 | FormItem, 204 | Editable, 205 | Input, 206 | Select, 207 | Radio, 208 | DatePicker, 209 | ArrayItems, 210 | FormButtonGroup, 211 | Submit, 212 | Space, 213 | } from '@formily/next' 214 | import { createForm } from '@formily/core' 215 | import { FormProvider, createSchemaField } from '@formily/react' 216 | 217 | const SchemaField = createSchemaField({ 218 | components: { 219 | FormItem, 220 | Editable, 221 | DatePicker, 222 | Space, 223 | Radio, 224 | Input, 225 | Select, 226 | ArrayItems, 227 | }, 228 | }) 229 | 230 | const form = createForm() 231 | 232 | const schema = { 233 | type: 'object', 234 | properties: { 235 | string_array: { 236 | type: 'array', 237 | 'x-component': 'ArrayItems', 238 | 'x-decorator': 'FormItem', 239 | title: '字符串数组', 240 | items: { 241 | type: 'void', 242 | 'x-component': 'Space', 243 | properties: { 244 | sort: { 245 | type: 'void', 246 | 'x-decorator': 'FormItem', 247 | 'x-component': 'ArrayItems.SortHandle', 248 | }, 249 | input: { 250 | type: 'string', 251 | 'x-decorator': 'FormItem', 252 | 'x-component': 'Input', 253 | }, 254 | remove: { 255 | type: 'void', 256 | 'x-decorator': 'FormItem', 257 | 'x-component': 'ArrayItems.Remove', 258 | }, 259 | }, 260 | }, 261 | properties: { 262 | add: { 263 | type: 'void', 264 | title: '添加条目', 265 | 'x-component': 'ArrayItems.Addition', 266 | }, 267 | }, 268 | }, 269 | array: { 270 | type: 'array', 271 | 'x-component': 'ArrayItems', 272 | 'x-decorator': 'FormItem', 273 | title: '对象数组', 274 | items: { 275 | type: 'object', 276 | properties: { 277 | space: { 278 | type: 'void', 279 | 'x-component': 'Space', 280 | properties: { 281 | sort: { 282 | type: 'void', 283 | 'x-decorator': 'FormItem', 284 | 'x-component': 'ArrayItems.SortHandle', 285 | }, 286 | date: { 287 | type: 'string', 288 | title: '日期', 289 | 'x-decorator': 'FormItem', 290 | 'x-component': 'DatePicker.RangePicker', 291 | 'x-component-props': { 292 | style: { 293 | width: 160, 294 | }, 295 | }, 296 | }, 297 | input: { 298 | type: 'string', 299 | title: '输入框', 300 | 'x-decorator': 'FormItem', 301 | 'x-component': 'Input', 302 | }, 303 | select: { 304 | type: 'string', 305 | title: '下拉框', 306 | enum: [ 307 | { label: '选项1', value: 1 }, 308 | { label: '选项2', value: 2 }, 309 | ], 310 | 'x-decorator': 'FormItem', 311 | 'x-component': 'Select', 312 | 'x-component-props': { 313 | style: { 314 | width: 160, 315 | }, 316 | }, 317 | }, 318 | remove: { 319 | type: 'void', 320 | 'x-decorator': 'FormItem', 321 | 'x-component': 'ArrayItems.Remove', 322 | }, 323 | }, 324 | }, 325 | }, 326 | }, 327 | properties: { 328 | add: { 329 | type: 'void', 330 | title: '添加条目', 331 | 'x-component': 'ArrayItems.Addition', 332 | }, 333 | }, 334 | }, 335 | array2: { 336 | type: 'array', 337 | 'x-component': 'ArrayItems', 338 | 'x-decorator': 'FormItem', 339 | 'x-component-props': { style: { width: 300 } }, 340 | title: '对象数组', 341 | items: { 342 | type: 'object', 343 | 'x-decorator': 'ArrayItems.Item', 344 | properties: { 345 | sort: { 346 | type: 'void', 347 | 'x-decorator': 'FormItem', 348 | 'x-component': 'ArrayItems.SortHandle', 349 | }, 350 | 351 | input: { 352 | type: 'string', 353 | title: '输入框', 354 | 'x-decorator': 'Editable', 355 | 'x-component': 'Input', 356 | }, 357 | config: { 358 | type: 'object', 359 | title: '配置复杂数据', 360 | 'x-component': 'Editable.Popover', 361 | 'x-reactions': 362 | '{{(field)=>field.title = field.value && field.value.input || field.title}}', 363 | properties: { 364 | date: { 365 | type: 'string', 366 | title: '日期', 367 | 'x-decorator': 'FormItem', 368 | 'x-component': 'DatePicker.RangePicker', 369 | 'x-component-props': { 370 | style: { 371 | width: 160, 372 | }, 373 | followTrigger: true, 374 | }, 375 | }, 376 | input: { 377 | type: 'string', 378 | title: '输入框', 379 | 'x-decorator': 'FormItem', 380 | 'x-component': 'Input', 381 | }, 382 | select: { 383 | type: 'string', 384 | title: '下拉框', 385 | enum: [ 386 | { label: '选项1', value: 1 }, 387 | { label: '选项2', value: 2 }, 388 | ], 389 | 'x-decorator': 'FormItem', 390 | 'x-component': 'Select', 391 | 'x-component-props': { 392 | style: { 393 | width: 160, 394 | }, 395 | }, 396 | }, 397 | }, 398 | }, 399 | remove: { 400 | type: 'void', 401 | 'x-decorator': 'FormItem', 402 | 'x-component': 'ArrayItems.Remove', 403 | }, 404 | }, 405 | }, 406 | properties: { 407 | add: { 408 | type: 'void', 409 | title: '添加条目', 410 | 'x-component': 'ArrayItems.Addition', 411 | }, 412 | }, 413 | }, 414 | }, 415 | } 416 | 417 | export default () => { 418 | return ( 419 | <FormProvider form={form}> 420 | <SchemaField schema={schema} /> 421 | <FormButtonGroup> 422 | <Submit onSubmit={console.log}>提交</Submit> 423 | </FormButtonGroup> 424 | </FormProvider> 425 | ) 426 | } 427 | ``` 428 | 429 | ## Effects 联动案例 430 | 431 | ```tsx 432 | import React from 'react' 433 | import { 434 | FormItem, 435 | Input, 436 | ArrayItems, 437 | Editable, 438 | FormButtonGroup, 439 | Submit, 440 | Space, 441 | } from '@formily/next' 442 | import { createForm, onFieldChange, onFieldReact } from '@formily/core' 443 | import { FormProvider, createSchemaField } from '@formily/react' 444 | 445 | const SchemaField = createSchemaField({ 446 | components: { 447 | Space, 448 | Editable, 449 | FormItem, 450 | Input, 451 | ArrayItems, 452 | }, 453 | }) 454 | 455 | const form = createForm({ 456 | effects: () => { 457 | //主动联动模式 458 | onFieldChange('array.*.aa', ['value'], (field, form) => { 459 | form.setFieldState(field.query('.bb'), (state) => { 460 | state.visible = field.value != '123' 461 | }) 462 | }) 463 | //被动联动模式 464 | onFieldReact('array.*.dd', (field) => { 465 | field.visible = field.query('.cc').get('value') != '123' 466 | }) 467 | }, 468 | }) 469 | 470 | export default () => { 471 | return ( 472 | <FormProvider form={form}> 473 | <SchemaField> 474 | <SchemaField.Array 475 | name="array" 476 | title="对象数组" 477 | maxItems={3} 478 | x-decorator="FormItem" 479 | x-component="ArrayItems" 480 | x-component-props={{ 481 | style: { 482 | width: 300, 483 | }, 484 | }} 485 | > 486 | <SchemaField.Object x-decorator="ArrayItems.Item"> 487 | <SchemaField.Void x-component="Space"> 488 | <SchemaField.Void 489 | x-decorator="FormItem" 490 | x-component="ArrayItems.SortHandle" 491 | /> 492 | <SchemaField.Void 493 | x-decorator="FormItem" 494 | x-component="ArrayItems.Index" 495 | /> 496 | </SchemaField.Void> 497 | <SchemaField.Void x-component="Editable.Popover" title="配置数据"> 498 | <SchemaField.String 499 | name="aa" 500 | x-decorator="FormItem" 501 | title="AA" 502 | required 503 | description="AA输入123时隐藏BB" 504 | x-component="Input" 505 | /> 506 | <SchemaField.String 507 | name="bb" 508 | x-decorator="FormItem" 509 | title="BB" 510 | required 511 | x-component="Input" 512 | /> 513 | <SchemaField.String 514 | name="cc" 515 | x-decorator="FormItem" 516 | title="CC" 517 | required 518 | description="CC输入123时隐藏DD" 519 | x-component="Input" 520 | /> 521 | <SchemaField.String 522 | name="dd" 523 | x-decorator="FormItem" 524 | title="DD" 525 | required 526 | x-component="Input" 527 | /> 528 | </SchemaField.Void> 529 | <SchemaField.Void x-component="Space"> 530 | <SchemaField.Void 531 | x-decorator="FormItem" 532 | x-component="ArrayItems.Remove" 533 | /> 534 | <SchemaField.Void 535 | x-decorator="FormItem" 536 | x-component="ArrayItems.MoveUp" 537 | /> 538 | <SchemaField.Void 539 | x-decorator="FormItem" 540 | x-component="ArrayItems.MoveDown" 541 | /> 542 | </SchemaField.Void> 543 | </SchemaField.Object> 544 | <SchemaField.Void 545 | x-component="ArrayItems.Addition" 546 | title="添加条目" 547 | /> 548 | </SchemaField.Array> 549 | </SchemaField> 550 | <FormButtonGroup> 551 | <Submit onSubmit={console.log}>提交</Submit> 552 | </FormButtonGroup> 553 | </FormProvider> 554 | ) 555 | } 556 | ``` 557 | 558 | ## JSON Schema 联动案例 559 | 560 | ```tsx 561 | import React from 'react' 562 | import { 563 | FormItem, 564 | Input, 565 | ArrayItems, 566 | Editable, 567 | FormButtonGroup, 568 | Submit, 569 | Space, 570 | } from '@formily/next' 571 | import { createForm } from '@formily/core' 572 | import { FormProvider, createSchemaField } from '@formily/react' 573 | 574 | const SchemaField = createSchemaField({ 575 | components: { 576 | Space, 577 | Editable, 578 | FormItem, 579 | Input, 580 | ArrayItems, 581 | }, 582 | }) 583 | 584 | const form = createForm() 585 | 586 | const schema = { 587 | type: 'object', 588 | properties: { 589 | array: { 590 | type: 'array', 591 | 'x-component': 'ArrayItems', 592 | 'x-decorator': 'FormItem', 593 | maxItems: 3, 594 | title: '对象数组', 595 | 'x-component-props': { style: { width: 300 } }, 596 | items: { 597 | type: 'object', 598 | 'x-decorator': 'ArrayItems.Item', 599 | properties: { 600 | left: { 601 | type: 'void', 602 | 'x-component': 'Space', 603 | properties: { 604 | sort: { 605 | type: 'void', 606 | 'x-decorator': 'FormItem', 607 | 'x-component': 'ArrayItems.SortHandle', 608 | }, 609 | index: { 610 | type: 'void', 611 | 'x-decorator': 'FormItem', 612 | 'x-component': 'ArrayItems.Index', 613 | }, 614 | }, 615 | }, 616 | edit: { 617 | type: 'void', 618 | 'x-component': 'Editable.Popover', 619 | title: '配置数据', 620 | properties: { 621 | aa: { 622 | type: 'string', 623 | 'x-decorator': 'FormItem', 624 | title: 'AA', 625 | required: true, 626 | 'x-component': 'Input', 627 | description: '输入123', 628 | }, 629 | bb: { 630 | type: 'string', 631 | title: 'BB', 632 | required: true, 633 | 'x-decorator': 'FormItem', 634 | 'x-component': 'Input', 635 | 'x-reactions': [ 636 | { 637 | dependencies: ['.aa'], 638 | when: "{{$deps[0] != '123'}}", 639 | fulfill: { 640 | schema: { 641 | title: 'BB', 642 | 'x-disabled': true, 643 | }, 644 | }, 645 | otherwise: { 646 | schema: { 647 | title: 'Changed', 648 | 'x-disabled': false, 649 | }, 650 | }, 651 | }, 652 | ], 653 | }, 654 | }, 655 | }, 656 | right: { 657 | type: 'void', 658 | 'x-component': 'Space', 659 | properties: { 660 | remove: { 661 | type: 'void', 662 | 'x-component': 'ArrayItems.Remove', 663 | }, 664 | moveUp: { 665 | type: 'void', 666 | 'x-component': 'ArrayItems.MoveUp', 667 | }, 668 | moveDown: { 669 | type: 'void', 670 | 'x-component': 'ArrayItems.MoveDown', 671 | }, 672 | }, 673 | }, 674 | }, 675 | }, 676 | properties: { 677 | addition: { 678 | type: 'void', 679 | title: '添加条目', 680 | 'x-component': 'ArrayItems.Addition', 681 | }, 682 | }, 683 | }, 684 | }, 685 | } 686 | 687 | export default () => { 688 | return ( 689 | <FormProvider form={form}> 690 | <SchemaField schema={schema} /> 691 | <FormButtonGroup> 692 | <Submit onSubmit={console.log}>提交</Submit> 693 | </FormButtonGroup> 694 | </FormProvider> 695 | ) 696 | } 697 | ``` 698 | 699 | ## API 700 | 701 | ### ArrayItems 702 | 703 | 扩展属性 704 | 705 | | 属性名 | 类型 | 描述 | 默认值 | 706 | | ---------- | ------------------------- | ------------ | ------ | 707 | | onAdd | `(index: number) => void` | 增加方法 | | 708 | | onRemove | `(index: number) => void` | 删除方法 | | 709 | | onCopy | `(index: number) => void` | 复制方法 | | 710 | | onMoveUp | `(index: number) => void` | 向上移动方法 | | 711 | | onMoveDown | `(index: number) => void` | 向下移动方法 | | 712 | 713 | 其余继承 HTMLDivElement Props 714 | 715 | ### ArrayItems.Item 716 | 717 | > 列表区块 718 | 719 | 继承 HTMLDivElement Props 720 | 721 | 扩展属性 722 | 723 | | 属性名 | 类型 | 描述 | 默认值 | 724 | | ------ | -------------------- | -------------- | ------ | 725 | | type | `'card' \| 'divide'` | 卡片或者分割线 | | 726 | 727 | ### ArrayItems.SortHandle 728 | 729 | > 拖拽手柄 730 | 731 | 参考 https://ant.design/components/icon-cn/ 732 | 733 | ### ArrayItems.Addition 734 | 735 | > 添加按钮 736 | 737 | 扩展属性 738 | 739 | | 属性名 | 类型 | 描述 | 默认值 | 740 | | ------------ | --------------------- | -------- | -------- | 741 | | title | ReactText | 文案 | | 742 | | method | `'push' \| 'unshift'` | 添加方式 | `'push'` | 743 | | defaultValue | `any` | 默认值 | | 744 | 745 | 其余参考 https://fusion.design/pc/component/basic/button 746 | 747 | 注意:title 属性可以接收 Field 模型中的 title 映射,也就是在 Field 上传 title 也是生效的 748 | 749 | ### ArrayItems.Copy 750 | 751 | > 复制按钮 752 | 753 | 扩展属性 754 | 755 | | 属性名 | 类型 | 描述 | 默认值 | 756 | | ------ | --------------------- | -------- | -------- | 757 | | title | ReactText | 文案 | | 758 | | method | `'push' \| 'unshift'` | 添加方式 | `'push'` | 759 | 760 | 其余参考 https://fusion.design/pc/component/basic/button 761 | 762 | 注意:title 属性可以接收 Field 模型中的 title 映射,也就是在 Field 上传 title 也是生效的 763 | 764 | ### ArrayItems.Remove 765 | 766 | > 删除按钮 767 | 768 | | 属性名 | 类型 | 描述 | 默认值 | 769 | | ------ | --------- | ---- | ------ | 770 | | title | ReactText | 文案 | | 771 | 772 | 其余参考 https://ant.design/components/icon-cn/ 773 | 774 | 注意:title 属性可以接收 Field 模型中的 title 映射,也就是在 Field 上传 title 也是生效的 775 | 776 | ### ArrayItems.MoveDown 777 | 778 | > 下移按钮 779 | 780 | | 属性名 | 类型 | 描述 | 默认值 | 781 | | ------ | --------- | ---- | ------ | 782 | | title | ReactText | 文案 | | 783 | 784 | 其余参考 https://ant.design/components/icon-cn/ 785 | 786 | 注意:title 属性可以接收 Field 模型中的 title 映射,也就是在 Field 上传 title 也是生效的 787 | 788 | ### ArrayItems.MoveUp 789 | 790 | > 上移按钮 791 | 792 | | 属性名 | 类型 | 描述 | 默认值 | 793 | | ------ | --------- | ---- | ------ | 794 | | title | ReactText | 文案 | | 795 | 796 | 其余参考 https://ant.design/components/icon-cn/ 797 | 798 | 注意:title 属性可以接收 Field 模型中的 title 映射,也就是在 Field 上传 title 也是生效的 799 | 800 | ### ArrayItems.Index 801 | 802 | > 索引渲染器 803 | 804 | 无属性 805 | 806 | ### ArrayItems.useIndex 807 | 808 | > 读取当前渲染行索引的 React Hook 809 | 810 | ### ArrayItems.useRecord 811 | 812 | > 读取当前渲染记录的 React Hook 813 | ```