This is page 35 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/next/docs/components/SelectTable.zh-CN.md: -------------------------------------------------------------------------------- ```markdown 1 | # SelectTable 2 | 3 | > 表格选择组件 4 | 5 | ## Markup Schema 单选案例 6 | 7 | ```tsx 8 | import React from 'react' 9 | import { FormItem, FormButtonGroup, Submit, SelectTable } from '@formily/next' 10 | import { createForm } from '@formily/core' 11 | import { FormProvider, createSchemaField } from '@formily/react' 12 | 13 | const SchemaField = createSchemaField({ 14 | components: { 15 | FormItem, 16 | SelectTable, 17 | }, 18 | }) 19 | 20 | const form = createForm() 21 | 22 | export default () => { 23 | return ( 24 | <FormProvider form={form}> 25 | <SchemaField> 26 | <SchemaField.Object 27 | type="string" 28 | name="selectTable" 29 | x-decorator="FormItem" 30 | x-component="SelectTable" 31 | x-component-props={{ 32 | hasBorder: false, 33 | mode: 'single', 34 | }} 35 | enum={[ 36 | { key: '1', name: '标题1', description: '描述1' }, 37 | { key: '2', name: '标题2', description: '描述2' }, 38 | ]} 39 | > 40 | <SchemaField.Void 41 | name="name" 42 | title="标题" 43 | x-component="SelectTable.Column" 44 | /> 45 | <SchemaField.Void 46 | name="description" 47 | title="描述" 48 | x-component="SelectTable.Column" 49 | /> 50 | </SchemaField.Object> 51 | </SchemaField> 52 | <FormButtonGroup.FormItem> 53 | <Submit onSubmit={console.log}>提交</Submit> 54 | </FormButtonGroup.FormItem> 55 | </FormProvider> 56 | ) 57 | } 58 | ``` 59 | 60 | ## Markup Schema 筛选案例 61 | 62 | ```tsx 63 | import React from 'react' 64 | import { FormItem, FormButtonGroup, Submit, SelectTable } from '@formily/next' 65 | import { createForm } from '@formily/core' 66 | import { FormProvider, createSchemaField } from '@formily/react' 67 | 68 | const SchemaField = createSchemaField({ 69 | components: { 70 | FormItem, 71 | SelectTable, 72 | }, 73 | }) 74 | 75 | const form = createForm() 76 | 77 | export default () => { 78 | return ( 79 | <FormProvider form={form}> 80 | <SchemaField> 81 | <SchemaField.Array 82 | type="array" 83 | name="selectTable" 84 | x-decorator="FormItem" 85 | x-component="SelectTable" 86 | x-component-props={{ 87 | hasBorder: false, 88 | showSearch: true, 89 | optionAsValue: true, 90 | }} 91 | enum={[ 92 | { key: '1', name: '标题1', description: '描述1' }, 93 | { key: '2', name: '标题2', description: '描述2' }, 94 | ]} 95 | > 96 | <SchemaField.Object> 97 | <SchemaField.Void 98 | name="name" 99 | title="标题" 100 | x-component="SelectTable.Column" 101 | /> 102 | <SchemaField.Void 103 | name="description" 104 | title="描述" 105 | x-component="SelectTable.Column" 106 | /> 107 | </SchemaField.Object> 108 | </SchemaField.Array> 109 | </SchemaField> 110 | <FormButtonGroup.FormItem> 111 | <Submit onSubmit={console.log}>提交</Submit> 112 | </FormButtonGroup.FormItem> 113 | </FormProvider> 114 | ) 115 | } 116 | ``` 117 | 118 | ## Markup Schema 异步数据源案例 119 | 120 | ```tsx 121 | import React from 'react' 122 | import { FormItem, FormButtonGroup, Submit, SelectTable } from '@formily/next' 123 | import { createForm } from '@formily/core' 124 | import { FormProvider, createSchemaField } from '@formily/react' 125 | 126 | const SchemaField = createSchemaField({ 127 | components: { 128 | FormItem, 129 | SelectTable, 130 | }, 131 | }) 132 | 133 | const form = createForm() 134 | 135 | export default () => { 136 | const onSearch = (value) => { 137 | const field = form.query('selectTable').take() 138 | field.loading = true 139 | setTimeout(() => { 140 | field.setState({ 141 | dataSource: [ 142 | { 143 | key: '3', 144 | name: 'AAA' + value, 145 | description: 'aaa', 146 | }, 147 | { 148 | key: '4', 149 | name: 'BBB' + value, 150 | description: 'bbb', 151 | }, 152 | ], 153 | loading: false, 154 | }) 155 | }, 1500) 156 | } 157 | 158 | return ( 159 | <FormProvider form={form}> 160 | <SchemaField> 161 | <SchemaField.Object 162 | type="object" 163 | name="selectTable" 164 | x-decorator="FormItem" 165 | x-component="SelectTable" 166 | x-component-props={{ 167 | hasBorder: false, 168 | showSearch: true, 169 | filterOption: false, 170 | onSearch, 171 | }} 172 | enum={[ 173 | { key: '1', name: '标题1', description: '描述1' }, 174 | { key: '2', name: '标题2', description: '描述2' }, 175 | ]} 176 | > 177 | <SchemaField.Void 178 | name="name" 179 | title="标题" 180 | x-component="SelectTable.Column" 181 | /> 182 | <SchemaField.Void 183 | name="description" 184 | title="描述" 185 | x-component="SelectTable.Column" 186 | /> 187 | </SchemaField.Object> 188 | </SchemaField> 189 | <FormButtonGroup.FormItem> 190 | <Submit onSubmit={console.log}>提交</Submit> 191 | </FormButtonGroup.FormItem> 192 | </FormProvider> 193 | ) 194 | } 195 | ``` 196 | 197 | ## Markup Schema 阅读态案例 198 | 199 | ```tsx 200 | import React from 'react' 201 | import { 202 | Form, 203 | FormItem, 204 | FormButtonGroup, 205 | Submit, 206 | SelectTable, 207 | } from '@formily/next' 208 | import { createForm } from '@formily/core' 209 | import { createSchemaField } from '@formily/react' 210 | 211 | const SchemaField = createSchemaField({ 212 | components: { 213 | FormItem, 214 | SelectTable, 215 | }, 216 | }) 217 | 218 | const form = createForm() 219 | 220 | export default () => { 221 | return ( 222 | <Form form={form} layout="vertical"> 223 | <SchemaField> 224 | <SchemaField.Object 225 | title="单选" 226 | type="string" 227 | name="selectTable1" 228 | x-decorator="FormItem" 229 | x-component="SelectTable" 230 | x-component-props={{ 231 | hasBorder: false, 232 | mode: 'single', 233 | }} 234 | default="1" 235 | enum={[ 236 | { key: '1', name: '标题1', description: '描述1' }, 237 | { key: '2', name: '标题2', description: '描述2' }, 238 | ]} 239 | x-read-pretty={true} 240 | > 241 | <SchemaField.Void 242 | name="name" 243 | title="标题" 244 | x-component="SelectTable.Column" 245 | /> 246 | <SchemaField.Void 247 | name="description" 248 | title="描述" 249 | x-component="SelectTable.Column" 250 | /> 251 | </SchemaField.Object> 252 | <SchemaField.Object 253 | title="单选 + optionAsValue" 254 | type="string" 255 | name="selectTable2" 256 | x-decorator="FormItem" 257 | x-component="SelectTable" 258 | x-component-props={{ 259 | hasBorder: false, 260 | mode: 'single', 261 | optionAsValue: true, 262 | }} 263 | default={{ key: '1', name: '标题1', description: '描述1' }} 264 | enum={[ 265 | { key: '1', name: '标题1', description: '描述1' }, 266 | { key: '2', name: '标题2', description: '描述2' }, 267 | ]} 268 | x-read-pretty={true} 269 | > 270 | <SchemaField.Void 271 | name="name" 272 | title="标题" 273 | x-component="SelectTable.Column" 274 | /> 275 | <SchemaField.Void 276 | name="description" 277 | title="描述" 278 | x-component="SelectTable.Column" 279 | /> 280 | </SchemaField.Object> 281 | <SchemaField.Array 282 | title="多选" 283 | type="array" 284 | name="selectTable3" 285 | x-decorator="FormItem" 286 | x-component="SelectTable" 287 | x-component-props={{ 288 | hasBorder: false, 289 | }} 290 | default={['1', '3']} 291 | enum={[ 292 | { key: '1', name: '标题1', description: '描述1' }, 293 | { key: '2', name: '标题2', description: '描述2' }, 294 | { key: '3', name: '标题3', description: '描述3' }, 295 | ]} 296 | x-read-pretty={true} 297 | > 298 | <SchemaField.Object> 299 | <SchemaField.Void 300 | name="name" 301 | title="标题" 302 | x-component="SelectTable.Column" 303 | /> 304 | <SchemaField.Void 305 | name="description" 306 | title="描述" 307 | x-component="SelectTable.Column" 308 | /> 309 | </SchemaField.Object> 310 | </SchemaField.Array> 311 | <SchemaField.Array 312 | title="多选 + optionAsValue" 313 | type="array" 314 | name="selectTable4" 315 | x-decorator="FormItem" 316 | x-component="SelectTable" 317 | x-component-props={{ 318 | hasBorder: false, 319 | optionAsValue: true, 320 | }} 321 | default={[ 322 | { key: '1', name: '标题1', description: '描述1' }, 323 | { key: '3', name: '标题3', description: '描述3' }, 324 | ]} 325 | enum={[ 326 | { key: '1', name: '标题1', description: '描述1' }, 327 | { key: '2', name: '标题2', description: '描述2' }, 328 | { key: '3', name: '标题3', description: '描述3' }, 329 | ]} 330 | x-read-pretty={true} 331 | > 332 | <SchemaField.Object> 333 | <SchemaField.Void 334 | name="name" 335 | title="标题" 336 | x-component="SelectTable.Column" 337 | /> 338 | <SchemaField.Void 339 | name="description" 340 | title="描述" 341 | x-component="SelectTable.Column" 342 | /> 343 | </SchemaField.Object> 344 | </SchemaField.Array> 345 | </SchemaField> 346 | <FormButtonGroup.FormItem> 347 | <Submit onSubmit={console.log}>提交</Submit> 348 | </FormButtonGroup.FormItem> 349 | </Form> 350 | ) 351 | } 352 | ``` 353 | 354 | ## JSON Schema 多选案例 355 | 356 | ```tsx 357 | import React from 'react' 358 | import { FormItem, FormButtonGroup, Submit, SelectTable } from '@formily/next' 359 | import { createForm } from '@formily/core' 360 | import { FormProvider, createSchemaField } from '@formily/react' 361 | 362 | const SchemaField = createSchemaField({ 363 | components: { 364 | SelectTable, 365 | FormItem, 366 | }, 367 | }) 368 | 369 | const form = createForm() 370 | 371 | const schema = { 372 | type: 'object', 373 | properties: { 374 | selectTable: { 375 | type: 'array', 376 | 'x-decorator': 'FormItem', 377 | 'x-component': 'SelectTable', 378 | 'x-component-props': { 379 | hasBorder: false, 380 | mode: 'multiple', 381 | }, 382 | enum: [ 383 | { key: '1', name: '标题1', description: '描述1' }, 384 | { key: '2', name: '标题2', description: '描述2' }, 385 | ], 386 | properties: { 387 | name: { 388 | title: '标题', 389 | type: 'string', 390 | 'x-component': 'SelectTable.Column', 391 | 'x-component-props': { 392 | width: '40%', 393 | }, 394 | }, 395 | description: { 396 | title: '描述', 397 | type: 'string', 398 | 'x-component': 'SelectTable.Column', 399 | 'x-component-props': { 400 | width: '60%', 401 | }, 402 | }, 403 | }, 404 | }, 405 | }, 406 | } 407 | 408 | export default () => ( 409 | <FormProvider form={form}> 410 | <SchemaField schema={schema} /> 411 | <FormButtonGroup> 412 | <Submit onSubmit={console.log}>提交</Submit> 413 | </FormButtonGroup> 414 | </FormProvider> 415 | ) 416 | ``` 417 | 418 | ## JSON Schema 自定义筛选案例 419 | 420 | ```tsx 421 | import React from 'react' 422 | import { FormItem, FormButtonGroup, Submit, SelectTable } from '@formily/next' 423 | import { createForm } from '@formily/core' 424 | import { FormProvider, createSchemaField } from '@formily/react' 425 | 426 | const SchemaField = createSchemaField({ 427 | components: { 428 | SelectTable, 429 | FormItem, 430 | }, 431 | }) 432 | 433 | const form = createForm() 434 | 435 | const schema = { 436 | type: 'object', 437 | properties: { 438 | selectTable: { 439 | type: 'array', 440 | 'x-decorator': 'FormItem', 441 | 'x-component': 'SelectTable', 442 | 'x-component-props': { 443 | hasBorder: false, 444 | showSearch: true, 445 | primaryKey: 'key', 446 | isTree: true, 447 | filterOption: (input, option) => 448 | option.description.toLowerCase().indexOf(input.toLowerCase()) >= 0, 449 | filterSort: (optionA, optionB) => 450 | optionA.description 451 | .toLowerCase() 452 | .localeCompare(optionB.description.toLowerCase()), 453 | optionAsValue: true, 454 | rowSelection: { 455 | checkStrictly: false, 456 | }, 457 | }, 458 | enum: [ 459 | { key: '1', name: '标题1', description: 'A-描述' }, 460 | { 461 | key: '2', 462 | name: '标题2', 463 | description: 'X-描述', 464 | children: [ 465 | { 466 | key: '2-1', 467 | name: '标题2-1', 468 | description: 'Y-描述', 469 | children: [ 470 | { key: '2-1-1', name: '标题2-1-1', description: 'Z-描述' }, 471 | ], 472 | }, 473 | { 474 | key: '2-2', 475 | name: '标题2-2', 476 | description: 'YY-描述', 477 | }, 478 | ], 479 | }, 480 | { key: '3', name: '标题3', description: 'C-描述' }, 481 | ], 482 | properties: { 483 | name: { 484 | title: '标题', 485 | type: 'string', 486 | 'x-component': 'SelectTable.Column', 487 | 'x-component-props': { 488 | width: '40%', 489 | }, 490 | }, 491 | description: { 492 | title: '描述', 493 | type: 'string', 494 | 'x-component': 'SelectTable.Column', 495 | 'x-component-props': { 496 | width: '60%', 497 | }, 498 | }, 499 | }, 500 | }, 501 | }, 502 | } 503 | 504 | export default () => ( 505 | <FormProvider form={form}> 506 | <SchemaField schema={schema} /> 507 | <FormButtonGroup> 508 | <Submit onSubmit={console.log}>提交</Submit> 509 | </FormButtonGroup> 510 | </FormProvider> 511 | ) 512 | ``` 513 | 514 | ## JSON Schema 异步数据源案例 515 | 516 | ```tsx 517 | import React from 'react' 518 | import { FormItem, FormButtonGroup, Submit, SelectTable } from '@formily/next' 519 | import { createForm } from '@formily/core' 520 | import { FormProvider, createSchemaField } from '@formily/react' 521 | 522 | const SchemaField = createSchemaField({ 523 | components: { 524 | SelectTable, 525 | FormItem, 526 | }, 527 | }) 528 | 529 | const loadData = async (value) => { 530 | return new Promise((resolve) => { 531 | setTimeout(() => { 532 | resolve([ 533 | { key: '3', name: 'AAA' + value, description: 'aaa' }, 534 | { key: '4', name: 'BBB' + value, description: 'bbb' }, 535 | ]) 536 | }, 1500) 537 | }) 538 | } 539 | 540 | const useAsyncDataSource = (service, field) => (value) => { 541 | field.loading = true 542 | service(value).then((data) => { 543 | field.setState({ 544 | dataSource: data, 545 | loading: false, 546 | }) 547 | }) 548 | } 549 | 550 | const form = createForm() 551 | 552 | const schema = { 553 | type: 'object', 554 | properties: { 555 | selectTable: { 556 | type: 'array', 557 | 'x-decorator': 'FormItem', 558 | 'x-component': 'SelectTable', 559 | 'x-component-props': { 560 | hasBorder: false, 561 | showSearch: true, 562 | filterOption: false, 563 | onSearch: '{{useAsyncDataSource(loadData,$self)}}', 564 | }, 565 | enum: [ 566 | { key: '1', name: '标题1', description: '描述1' }, 567 | { key: '2', name: '标题2', description: '描述2' }, 568 | ], 569 | properties: { 570 | name: { 571 | title: '标题', 572 | type: 'string', 573 | 'x-component': 'SelectTable.Column', 574 | 'x-component-props': { 575 | width: '40%', 576 | }, 577 | }, 578 | description: { 579 | title: '描述', 580 | type: 'string', 581 | 'x-component': 'SelectTable.Column', 582 | 'x-component-props': { 583 | width: '60%', 584 | }, 585 | }, 586 | }, 587 | }, 588 | }, 589 | } 590 | 591 | export default () => ( 592 | <FormProvider form={form}> 593 | <SchemaField schema={schema} scope={{ useAsyncDataSource, loadData }} /> 594 | <FormButtonGroup> 595 | <Submit onSubmit={console.log}>提交</Submit> 596 | </FormButtonGroup> 597 | </FormProvider> 598 | ) 599 | ``` 600 | 601 | ## 纯 JSX 案例 602 | 603 | ```tsx 604 | import React from 'react' 605 | import { FormItem, FormButtonGroup, Submit, SelectTable } from '@formily/next' 606 | import { createForm } from '@formily/core' 607 | import { FormProvider, Field } from '@formily/react' 608 | 609 | const form = createForm() 610 | 611 | export default () => ( 612 | <FormProvider form={form}> 613 | <Field 614 | name="SelectTable" 615 | dataSource={[ 616 | { key: '1', name: '标题1', description: '描述1' }, 617 | { key: '2', name: '标题2', description: '描述2' }, 618 | ]} 619 | decorator={[FormItem]} 620 | component={[ 621 | SelectTable, 622 | { 623 | hasBorder: false, 624 | columns: [ 625 | { dataIndex: 'name', title: '标题' }, 626 | { dataIndex: 'description', title: '描述' }, 627 | ], 628 | }, 629 | ]} 630 | /> 631 | <FormButtonGroup> 632 | <Submit onSubmit={console.log}>提交</Submit> 633 | </FormButtonGroup> 634 | </FormProvider> 635 | ) 636 | ``` 637 | 638 | ## API 639 | 640 | ### SelectTable 641 | 642 | | 属性名 | 类型 | 描述 | 默认值 | 643 | | ------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | ------------ | 644 | | mode | `'multiple' \| 'single'` | 设置 SelectTable 模式为单选或多选 | `'multiple'` | 645 | | valueType | `'all' \| 'parent' \| 'child' \| 'path'` | 返回值类型,checkStrictly 设置为 `false` 时有效 | `'all'` | 646 | | optionAsValue | boolean | 使用表格行数据作为值,valueType 值为 `'path'` 时无效 | false | 647 | | showSearch | boolean | 是否显示搜索组件 | false | 648 | | searchProps | object | Search 组件属性 | - | 649 | | primaryKey | `string \| (record) => string` | 表格行 key 的取值 | `'key'` | 650 | | filterOption | `boolean \| (inputValue, option) => boolean` | 是否根据输入项进行筛选。当其为一个函数时,会接收 inputValue option 两个参数,当 option 符合筛选条件时,应返回 true,反之则返回 false | true | 651 | | filterSort | (optionA, optionB) => number | 搜索时对筛选结果项的排序函数, 类似 Array.sort 里的 compareFunction | - | 652 | | onSearch | 文本框值变化时回调 | (inputValue) => void | - | 653 | 654 | 参考 https://fusion.design/pc/component/basic/table 655 | 656 | ### rowSelection 657 | 658 | | 属性名 | 类型 | 描述 | 默认值 | 659 | | ------------- | ------- | ------------------------------------------------------------ | ------ | 660 | | checkStrictly | boolean | checkable 状态下节点选择完全受控(父子数据选中状态不再关联) | true | 661 | 662 | 参考 https://fusion.design/pc/component/basic/table rowSelection 663 | 664 | ### SelectTable.Column 665 | 666 | 参考 https://fusion.design/pc/component/basic/table Table.Column 属性 667 | ``` -------------------------------------------------------------------------------- /packages/next/docs/components/TreeSelect.md: -------------------------------------------------------------------------------- ```markdown 1 | # TreeSelect 2 | 3 | > Tree selector 4 | 5 | ## Markup Schema synchronization data source case 6 | 7 | ```tsx 8 | import React from 'react' 9 | import { TreeSelect, FormItem, FormButtonGroup, Submit } from '@formily/next' 10 | import { createForm } from '@formily/core' 11 | import { FormProvider, createSchemaField } from '@formily/react' 12 | 13 | const SchemaField = createSchemaField({ 14 | components: { 15 | TreeSelect, 16 | FormItem, 17 | }, 18 | }) 19 | 20 | const form = createForm() 21 | 22 | export default () => ( 23 | <FormProvider form={form}> 24 | <SchemaField> 25 | <SchemaField.Number 26 | name="select" 27 | label="select box" 28 | x-decorator="FormItem" 29 | x-component="TreeSelect" 30 | enum={[ 31 | { 32 | label: 'Option 1', 33 | value: 1, 34 | children: [ 35 | { 36 | label: 'Child Node1', 37 | value: '0-0-0', 38 | key: '0-0-0', 39 | }, 40 | { 41 | label: 'Child Node2', 42 | value: '0-0-1', 43 | key: '0-0-1', 44 | }, 45 | { 46 | label: 'Child Node3', 47 | value: '0-0-2', 48 | key: '0-0-2', 49 | }, 50 | ], 51 | }, 52 | { 53 | label: 'Option 2', 54 | value: 2, 55 | children: [ 56 | { 57 | label: 'Child Node3', 58 | value: '0-1-0', 59 | key: '0-1-0', 60 | }, 61 | { 62 | label: 'Child Node4', 63 | value: '0-1-1', 64 | key: '0-1-1', 65 | }, 66 | { 67 | label: 'Child Node5', 68 | value: '0-1-2', 69 | key: '0-1-2', 70 | }, 71 | ], 72 | }, 73 | ]} 74 | x-component-props={{ 75 | style: { 76 | width: 200, 77 | }, 78 | }} 79 | /> 80 | </SchemaField> 81 | <FormButtonGroup> 82 | <Submit onSubmit={console.log}>Submit</Submit> 83 | </FormButtonGroup> 84 | </FormProvider> 85 | ) 86 | ``` 87 | 88 | ## Markup Schema Asynchronous Linkage Data Source Case 89 | 90 | ```tsx 91 | import React from 'react' 92 | import { 93 | TreeSelect, 94 | Select, 95 | FormItem, 96 | FormButtonGroup, 97 | Submit, 98 | } from '@formily/next' 99 | import { createForm, onFieldReact, FormPathPattern, Field } from '@formily/core' 100 | import { FormProvider, createSchemaField } from '@formily/react' 101 | import { action } from '@formily/reactive' 102 | 103 | const SchemaField = createSchemaField({ 104 | components: { 105 | Select, 106 | TreeSelect, 107 | FormItem, 108 | }, 109 | }) 110 | 111 | const useAsyncDataSource = ( 112 | pattern: FormPathPattern, 113 | service: (field: Field) => Promise<{ label: string; value: any }[]> 114 | ) => { 115 | onFieldReact(pattern, (field) => { 116 | field.loading = true 117 | service(field).then( 118 | action.bound((data) => { 119 | field.dataSource = data 120 | field.loading = false 121 | }) 122 | ) 123 | }) 124 | } 125 | 126 | const form = createForm({ 127 | effects: () => { 128 | useAsyncDataSource('select', async (field) => { 129 | const linkage = field.query('linkage').get('value') 130 | if (!linkage) return [] 131 | return new Promise((resolve) => { 132 | setTimeout(() => { 133 | if (linkage === 1) { 134 | resolve([ 135 | { 136 | label: 'AAA', 137 | value: 'aaa', 138 | children: [ 139 | { 140 | label: 'Child Node1', 141 | value: '0-0-0', 142 | key: '0-0-0', 143 | }, 144 | { 145 | label: 'Child Node2', 146 | value: '0-0-1', 147 | key: '0-0-1', 148 | }, 149 | { 150 | label: 'Child Node3', 151 | value: '0-0-2', 152 | key: '0-0-2', 153 | }, 154 | ], 155 | }, 156 | { 157 | label: 'BBB', 158 | value: 'ccc', 159 | children: [ 160 | { 161 | label: 'Child Node1', 162 | value: '0-1-0', 163 | key: '0-1-0', 164 | }, 165 | { 166 | label: 'Child Node2', 167 | value: '0-1-1', 168 | key: '0-1-1', 169 | }, 170 | { 171 | label: 'Child Node3', 172 | value: '0-1-2', 173 | key: '0-1-2', 174 | }, 175 | ], 176 | }, 177 | ]) 178 | } else if (linkage === 2) { 179 | resolve([ 180 | { 181 | label: 'CCC', 182 | value: 'ccc', 183 | children: [ 184 | { 185 | label: 'Child Node1', 186 | value: '0-0-0', 187 | key: '0-0-0', 188 | }, 189 | { 190 | label: 'Child Node2', 191 | value: '0-0-1', 192 | key: '0-0-1', 193 | }, 194 | { 195 | label: 'Child Node3', 196 | value: '0-0-2', 197 | key: '0-0-2', 198 | }, 199 | ], 200 | }, 201 | { 202 | label: 'DDD', 203 | value: 'ddd', 204 | children: [ 205 | { 206 | label: 'Child Node1', 207 | value: '0-1-0', 208 | key: '0-1-0', 209 | }, 210 | { 211 | label: 'Child Node2', 212 | value: '0-1-1', 213 | key: '0-1-1', 214 | }, 215 | { 216 | label: 'Child Node3', 217 | value: '0-1-2', 218 | key: '0-1-2', 219 | }, 220 | ], 221 | }, 222 | ]) 223 | } 224 | }, 1500) 225 | }) 226 | }) 227 | }, 228 | }) 229 | 230 | export default () => ( 231 | <FormProvider form={form}> 232 | <SchemaField> 233 | <SchemaField.Number 234 | name="linkage" 235 | label="Linkage selection box" 236 | x-decorator="FormItem" 237 | x-component="Select" 238 | enum={[ 239 | { label: 'Request 1', value: 1 }, 240 | { label: 'Request 2', value: 2 }, 241 | ]} 242 | x-component-props={{ 243 | style: { 244 | width: 200, 245 | }, 246 | }} 247 | /> 248 | <SchemaField.String 249 | name="select" 250 | label="Asynchronous selection box" 251 | x-decorator="FormItem" 252 | x-component="TreeSelect" 253 | x-component-props={{ 254 | style: { 255 | width: 200, 256 | }, 257 | }} 258 | /> 259 | </SchemaField> 260 | <FormButtonGroup> 261 | <Submit onSubmit={console.log}>Submit</Submit> 262 | </FormButtonGroup> 263 | </FormProvider> 264 | ) 265 | ``` 266 | 267 | ## JSON Schema synchronization data source case 268 | 269 | ```tsx 270 | import React from 'react' 271 | import { TreeSelect, FormItem, FormButtonGroup, Submit } from '@formily/next' 272 | import { createForm } from '@formily/core' 273 | import { FormProvider, createSchemaField } from '@formily/react' 274 | 275 | const SchemaField = createSchemaField({ 276 | components: { 277 | TreeSelect, 278 | FormItem, 279 | }, 280 | }) 281 | 282 | const form = createForm() 283 | 284 | const schema = { 285 | type: 'object', 286 | properties: { 287 | select: { 288 | type: 'string', 289 | label: 'Select box', 290 | 'x-decorator': 'FormItem', 291 | 'x-component': 'TreeSelect', 292 | enum: [ 293 | { 294 | label: 'Option 1', 295 | value: 1, 296 | children: [ 297 | { 298 | label: 'Child Node1', 299 | value: '0-0-0', 300 | key: '0-0-0', 301 | }, 302 | { 303 | label: 'Child Node2', 304 | value: '0-0-1', 305 | key: '0-0-1', 306 | }, 307 | { 308 | label: 'Child Node3', 309 | value: '0-0-2', 310 | key: '0-0-2', 311 | }, 312 | ], 313 | }, 314 | { 315 | label: 'Option 2', 316 | value: 2, 317 | children: [ 318 | { 319 | label: 'Child Node1', 320 | value: '0-1-0', 321 | key: '0-1-0', 322 | }, 323 | { 324 | label: 'Child Node2', 325 | value: '0-1-1', 326 | key: '0-1-1', 327 | }, 328 | { 329 | label: 'Child Node3', 330 | value: '0-1-2', 331 | key: '0-1-2', 332 | }, 333 | ], 334 | }, 335 | ], 336 | 'x-component-props': { 337 | style: { 338 | width: 200, 339 | }, 340 | }, 341 | }, 342 | }, 343 | } 344 | 345 | export default () => ( 346 | <FormProvider form={form}> 347 | <SchemaField schema={schema} /> 348 | <FormButtonGroup> 349 | <Submit onSubmit={console.log}>Submit</Submit> 350 | </FormButtonGroup> 351 | </FormProvider> 352 | ) 353 | ``` 354 | 355 | ## JSON Schema asynchronous linkage data source case 356 | 357 | ```tsx 358 | import React from 'react' 359 | import { 360 | TreeSelect, 361 | Select, 362 | FormItem, 363 | FormButtonGroup, 364 | Submit, 365 | } from '@formily/next' 366 | import { createForm } from '@formily/core' 367 | import { FormProvider, createSchemaField } from '@formily/react' 368 | import { action } from '@formily/reactive' 369 | 370 | const SchemaField = createSchemaField({ 371 | components: { 372 | Select, 373 | TreeSelect, 374 | FormItem, 375 | }, 376 | }) 377 | 378 | const loadData = async (field) => { 379 | const linkage = field.query('linkage').get('value') 380 | if (!linkage) return [] 381 | return new Promise((resolve) => { 382 | setTimeout(() => { 383 | if (linkage === 1) { 384 | resolve([ 385 | { 386 | label: 'AAA', 387 | value: 'aaa', 388 | children: [ 389 | { 390 | label: 'Child Node1', 391 | value: '0-0-0', 392 | key: '0-0-0', 393 | }, 394 | { 395 | label: 'Child Node2', 396 | value: '0-0-1', 397 | key: '0-0-1', 398 | }, 399 | { 400 | label: 'Child Node3', 401 | value: '0-0-2', 402 | key: '0-0-2', 403 | }, 404 | ], 405 | }, 406 | { 407 | label: 'BBB', 408 | value: 'ccc', 409 | children: [ 410 | { 411 | label: 'Child Node1', 412 | value: '0-1-0', 413 | key: '0-1-0', 414 | }, 415 | { 416 | label: 'Child Node2', 417 | value: '0-1-1', 418 | key: '0-1-1', 419 | }, 420 | { 421 | label: 'Child Node3', 422 | value: '0-1-2', 423 | key: '0-1-2', 424 | }, 425 | ], 426 | }, 427 | ]) 428 | } else if (linkage === 2) { 429 | resolve([ 430 | { 431 | label: 'CCC', 432 | value: 'ccc', 433 | children: [ 434 | { 435 | label: 'Child Node1', 436 | value: '0-0-0', 437 | key: '0-0-0', 438 | }, 439 | { 440 | label: 'Child Node2', 441 | value: '0-0-1', 442 | key: '0-0-1', 443 | }, 444 | { 445 | label: 'Child Node3', 446 | value: '0-0-2', 447 | key: '0-0-2', 448 | }, 449 | ], 450 | }, 451 | { 452 | label: 'DDD', 453 | value: 'ddd', 454 | children: [ 455 | { 456 | label: 'Child Node1', 457 | value: '0-1-0', 458 | key: '0-1-0', 459 | }, 460 | { 461 | label: 'Child Node2', 462 | value: '0-1-1', 463 | key: '0-1-1', 464 | }, 465 | { 466 | label: 'Child Node3', 467 | value: '0-1-2', 468 | key: '0-1-2', 469 | }, 470 | ], 471 | }, 472 | ]) 473 | } 474 | }, 1500) 475 | }) 476 | } 477 | 478 | const useAsyncDataSource = (service) => (field) => { 479 | field.loading = true 480 | service(field).then( 481 | action.bound((data) => { 482 | field.dataSource = data 483 | field.loading = false 484 | }) 485 | ) 486 | } 487 | 488 | const form = createForm() 489 | 490 | const schema = { 491 | type: 'object', 492 | properties: { 493 | linkage: { 494 | type: 'string', 495 | label: 'Linkage selection box', 496 | enum: [ 497 | { label: 'Request 1', value: 1 }, 498 | { label: 'Request 2', value: 2 }, 499 | ], 500 | 'x-decorator': 'FormItem', 501 | 'x-component': 'Select', 502 | 'x-component-props': { 503 | style: { 504 | width: 200, 505 | }, 506 | }, 507 | }, 508 | select: { 509 | type: 'string', 510 | label: 'Asynchronous selection box', 511 | 'x-decorator': 'FormItem', 512 | 'x-component': 'TreeSelect', 513 | 'x-component-props': { 514 | style: { 515 | width: 200, 516 | }, 517 | }, 518 | 'x-reactions': ['{{useAsyncDataSource(loadData)}}'], 519 | }, 520 | }, 521 | } 522 | 523 | export default () => ( 524 | <FormProvider form={form}> 525 | <SchemaField schema={schema} scope={{ useAsyncDataSource, loadData }} /> 526 | <FormButtonGroup> 527 | <Submit onSubmit={console.log}>Submit</Submit> 528 | </FormButtonGroup> 529 | </FormProvider> 530 | ) 531 | ``` 532 | 533 | ## Pure JSX synchronization data source case 534 | 535 | ```tsx 536 | import React from 'react' 537 | import { TreeSelect, FormItem, FormButtonGroup, Submit } from '@formily/next' 538 | import { createForm } from '@formily/core' 539 | import { FormProvider, Field } from '@formily/react' 540 | 541 | const form = createForm() 542 | 543 | export default () => ( 544 | <FormProvider form={form}> 545 | <Field 546 | name="select" 547 | label="select box" 548 | dataSource={[ 549 | { 550 | label: 'Option 1', 551 | value: 1, 552 | children: [ 553 | { 554 | label: 'Child Node1', 555 | value: '0-0-0', 556 | key: '0-0-0', 557 | }, 558 | { 559 | label: 'Child Node2', 560 | value: '0-0-1', 561 | key: '0-0-1', 562 | }, 563 | { 564 | label: 'Child Node3', 565 | value: '0-0-2', 566 | key: '0-0-2', 567 | }, 568 | ], 569 | }, 570 | { 571 | label: 'Option 2', 572 | value: 2, 573 | children: [ 574 | { 575 | label: 'Child Node3', 576 | value: '0-1-0', 577 | key: '0-1-0', 578 | }, 579 | { 580 | label: 'Child Node4', 581 | value: '0-1-1', 582 | key: '0-1-1', 583 | }, 584 | { 585 | label: 'Child Node5', 586 | value: '0-1-2', 587 | key: '0-1-2', 588 | }, 589 | ], 590 | }, 591 | ]} 592 | decorator={[FormItem]} 593 | component={[ 594 | TreeSelect, 595 | { 596 | style: { 597 | width: 200, 598 | }, 599 | }, 600 | ]} 601 | /> 602 | <FormButtonGroup> 603 | <Submit onSubmit={console.log}>Submit</Submit> 604 | </FormButtonGroup> 605 | </FormProvider> 606 | ) 607 | ``` 608 | 609 | ## Pure JSX asynchronous linkage data source case 610 | 611 | ```tsx 612 | import React from 'react' 613 | import { 614 | TreeSelect, 615 | Select, 616 | FormItem, 617 | FormButtonGroup, 618 | Submit, 619 | } from '@formily/next' 620 | import { 621 | createForm, 622 | onFieldReact, 623 | FormPathPattern, 624 | FieldType, 625 | } from '@formily/core' 626 | import { FormProvider, Field } from '@formily/react' 627 | import { action } from '@formily/reactive' 628 | 629 | const useAsyncDataSource = ( 630 | pattern: FormPathPattern, 631 | service: (field: FieldType) => Promise<{ label: string; value: any }[]> 632 | ) => { 633 | onFieldReact(pattern, (field) => { 634 | field.loading = true 635 | service(field).then( 636 | action.bound((data) => { 637 | field.dataSource = data 638 | field.loading = false 639 | }) 640 | ) 641 | }) 642 | } 643 | 644 | const form = createForm({ 645 | effects: () => { 646 | useAsyncDataSource('select', async (field) => { 647 | const linkage = field.query('linkage').get('value') 648 | if (!linkage) return [] 649 | return new Promise((resolve) => { 650 | setTimeout(() => { 651 | if (linkage === 1) { 652 | resolve([ 653 | { 654 | label: 'AAA', 655 | value: 'aaa', 656 | children: [ 657 | { 658 | label: 'Child Node1', 659 | value: '0-0-0', 660 | key: '0-0-0', 661 | }, 662 | { 663 | label: 'Child Node2', 664 | value: '0-0-1', 665 | key: '0-0-1', 666 | }, 667 | { 668 | label: 'Child Node3', 669 | value: '0-0-2', 670 | key: '0-0-2', 671 | }, 672 | ], 673 | }, 674 | { 675 | label: 'BBB', 676 | value: 'ccc', 677 | children: [ 678 | { 679 | label: 'Child Node1', 680 | value: '0-1-0', 681 | key: '0-1-0', 682 | }, 683 | { 684 | label: 'Child Node2', 685 | value: '0-1-1', 686 | key: '0-1-1', 687 | }, 688 | { 689 | label: 'Child Node3', 690 | value: '0-1-2', 691 | key: '0-1-2', 692 | }, 693 | ], 694 | }, 695 | ]) 696 | } else if (linkage === 2) { 697 | resolve([ 698 | { 699 | label: 'CCC', 700 | value: 'ccc', 701 | children: [ 702 | { 703 | label: 'Child Node1', 704 | value: '0-0-0', 705 | key: '0-0-0', 706 | }, 707 | { 708 | label: 'Child Node2', 709 | value: '0-0-1', 710 | key: '0-0-1', 711 | }, 712 | { 713 | label: 'Child Node3', 714 | value: '0-0-2', 715 | key: '0-0-2', 716 | }, 717 | ], 718 | }, 719 | { 720 | label: 'DDD', 721 | value: 'ddd', 722 | children: [ 723 | { 724 | label: 'Child Node1', 725 | value: '0-1-0', 726 | key: '0-1-0', 727 | }, 728 | { 729 | label: 'Child Node2', 730 | value: '0-1-1', 731 | key: '0-1-1', 732 | }, 733 | { 734 | label: 'Child Node3', 735 | value: '0-1-2', 736 | key: '0-1-2', 737 | }, 738 | ], 739 | }, 740 | ]) 741 | } 742 | }, 1500) 743 | }) 744 | }) 745 | }, 746 | }) 747 | 748 | export default () => ( 749 | <FormProvider form={form}> 750 | <Field 751 | name="linkage" 752 | label="Linkage selection box" 753 | dataSource={[ 754 | { label: 'Request 1', value: 1 }, 755 | { label: 'Request 2', value: 2 }, 756 | ]} 757 | decorator={[FormItem]} 758 | component={[ 759 | Select, 760 | { 761 | style: { 762 | width: 200, 763 | }, 764 | }, 765 | ]} 766 | /> 767 | <Field 768 | name="select" 769 | label="Asynchronous selection box" 770 | decorator={[FormItem]} 771 | component={[ 772 | TreeSelect, 773 | { 774 | style: { 775 | width: 200, 776 | }, 777 | }, 778 | ]} 779 | /> 780 | <FormButtonGroup> 781 | <Submit onSubmit={console.log}>Submit</Submit> 782 | </FormButtonGroup> 783 | </FormProvider> 784 | ) 785 | ``` 786 | 787 | ## API 788 | 789 | Reference https://fusion.design/pc/component/basic/tree-select 790 | ``` -------------------------------------------------------------------------------- /packages/core/docs/api/entry/FormPath.md: -------------------------------------------------------------------------------- ```markdown 1 | --- 2 | order: 5 3 | --- 4 | 5 | # FormPath 6 | 7 | The core of FormPath in Formily is to solve 2 types of problems: 8 | 9 | - Path matching problem 10 | - Data manipulation issues 11 | 12 | Path matching requires that the given path must be a valid path matching syntax, such as `*(aa,bb,cc)`. 13 | 14 | Data operation requires that the given path must be a legal data operation path, that is, it must be in the form of `a.b.c` and cannot carry `*` 15 | 16 | ## Constructor 17 | 18 | ```ts 19 | class FormPath { 20 | constructor(pattern: FormPathPattern, base?: FormPathPattern) 21 | } 22 | ``` 23 | 24 | ## Attributes 25 | 26 | | Property | Description | Type | Default Value | 27 | | ------------------ | ------------------------------------------------------------------------------- | ------------------------- | ------------- | 28 | | length | If the path is a non-matching path, the length of the path can be read | Number | `0` | 29 | | entire | Path complete string, consistent with the input parameter data | String | | 30 | | segments | If the path is a non-matching path, you can read the complete path segmentation | `Array<String \| Number>` | `[]` | 31 | | isMatchPattern | Is the path a matching path | Boolean | | 32 | | isWildMatchPattern | Is the path a fully wildcarded path, such as `a.b.*` | Boolean | | 33 | | haveExcludePattern | Does the path have reverse matching, such as `*(!a.b.c)` | Boolean | | 34 | | tree | Parsed AST tree | Node | | 35 | 36 | ## FormPathPattern 37 | 38 | ### Signature 39 | 40 | ```ts 41 | type FormPathPattern = string | number | Array<string | number> | RegExp 42 | ``` 43 | 44 | ### Data path syntax 45 | 46 | #### Point path 47 | 48 | **description** 49 | 50 | It is our most commonly used `a.b.c` format, which uses dot notation to divide each path node, mainly used to read and write data 51 | 52 | **Example** 53 | 54 | ```ts 55 | import { FormPath } from '@formily/core' 56 | 57 | const target = {} 58 | 59 | FormPath.setIn(target, 'a.b.c', 'value') 60 | console.log(FormPath.getIn(target, 'a.b.c')) //'value' 61 | console.log(target) //{a:{b:{c:'value'}}} 62 | ``` 63 | 64 | #### Subscript path 65 | 66 | For array paths, there will be subscripts. Our subscripts can use dot syntax or square brackets. 67 | 68 | ```ts 69 | import { FormPath } from '@formily/core' 70 | 71 | const target = { 72 | array: [], 73 | } 74 | 75 | FormPath.setIn(target, 'array.0.aa', '000') 76 | console.log(FormPath.getIn(target, 'array.0.aa')) //000 77 | console.log(target) //{array:[{aa:'000'}]} 78 | FormPath.setIn(target, 'array[1].aa', '111') 79 | console.log(FormPath.getIn(target, 'array.1.aa')) //111 80 | console.log(target) //{array:[{aa:'000'},{aa:'111'}]} 81 | ``` 82 | 83 | #### Deconstruction expression 84 | 85 | The deconstruction expression is similar to the ES6 deconstruction grammar, except that it does not support `...` deconstruction. It is very suitable for scenarios where the front and back data is inconsistent. It has several characteristics: 86 | 87 | - The deconstruction expression will be regarded as a node of the point path, we can regard it as a normal string node, but it will take effect during data manipulation, so only the deconstruction expression needs to be matched as a normal node node in the matching grammar Can 88 | - Use the deconstruction path in setIn, the data will be deconstructed 89 | - Use the deconstruction path in getIn, the data will be reorganized 90 | 91 | ```ts 92 | import { FormPath } from '@formily/core' 93 | 94 | const target = {} 95 | 96 | FormPath.setIn(target, 'parent.[aa,bb]', [11, 22]) 97 | console.log(target) //{parent:{aa:11,bb:22}} 98 | console.log(FormPath.getIn(target, 'parent.[aa,bb]')) //[11,22] 99 | console.log(FormPath.parse('parent.[aa,bb]').toString()) //parent.[aa,bb] 100 | ``` 101 | 102 | #### relative path 103 | 104 | The relative path syntax is mainly expressed in dot syntax at the head of the data type path. It is very useful for calculating adjacent elements of the array. It has several characteristics: 105 | 106 | - A dot represents the current path 107 | - n dots represent n-1 steps forward 108 | - Subscripts can be used to calculate expressions in square brackets: `[+]` represents the current subscript +1, `[-]` represents the current subscript - 1, `[+n]` represents the current subscript +n, ` [-n]` represents the current subscript - n 109 | - When path matching, group matching and range matching cannot be used, such as `*(..[+1].aa,..[+2].bb)` 110 | 111 | ```ts 112 | import { FormPath } from '@formily/core' 113 | 114 | console.log(FormPath.parse('.dd', 'aa.bb.cc').toString()) //aa.bb.dd 115 | console.log(FormPath.parse('..[].dd', 'aa.1.cc').toString()) //aa.1.dd 116 | console.log(FormPath.parse('..[+].dd', 'aa.1.cc').toString()) //aa.2.dd 117 | console.log(FormPath.parse('..[+10].dd', 'aa.1.cc').toString()) //aa.11.dd 118 | ``` 119 | 120 | ### Match path syntax 121 | 122 | #### Full match 123 | 124 | Full match is equivalent to matching all paths, only a `*` identification is required 125 | 126 | ```ts 127 | import { FormPath } from '@formily/core' 128 | 129 | console.log(FormPath.parse('*').match('aa')) //true 130 | console.log(FormPath.parse('*').match('aa.bb')) //true 131 | console.log(FormPath.parse('*').match('cc')) //true 132 | ``` 133 | 134 | #### Partial match 135 | 136 | Local matching is equivalent to matching all paths of a node position, and also only needs to use a `*` mark 137 | 138 | ```ts 139 | import { FormPath } from '@formily/core' 140 | 141 | console.log(FormPath.parse('aa.*.cc').match('aa.bb.cc')) //true 142 | console.log(FormPath.parse('aa.*.cc').match('aa.kk.cc')) //true 143 | console.log(FormPath.parse('aa.*.cc').match('aa.dd.cc')) //true 144 | ``` 145 | 146 | #### Group Match 147 | 148 | Grouped matching can match multiple paths, and also supports nesting, syntax: `*(pattern1,pattern2,pattern3...)` 149 | 150 | ```ts 151 | import { FormPath } from '@formily/core' 152 | 153 | console.log( 154 | FormPath.parse('aa.*(bb,kk,dd,ee.*(oo,gg).gg).cc').match('aa.bb.cc') 155 | ) //true 156 | console.log( 157 | FormPath.parse('aa.*(bb,kk,dd,ee.*(oo,gg).gg).cc').match('aa.kk.cc') 158 | ) //true 159 | console.log( 160 | FormPath.parse('aa.*(bb,kk,dd,ee.*(oo,gg).gg).cc').match('aa.dd.cc') 161 | ) //true 162 | console.log( 163 | FormPath.parse('aa.*(bb,kk,dd,ee.*(oo,gg).gg).cc').match('aa.ee.oo.gg.cc') 164 | ) //true 165 | console.log( 166 | FormPath.parse('aa.*(bb,kk,dd,ee.*(oo,gg).gg).cc').match('aa.ee.gg.gg.cc') 167 | ) //true 168 | ``` 169 | 170 | #### Reverse match 171 | 172 | Reverse matching is mainly used to exclude the specified path, syntax: `*(!pattern1,pattern2,pattern3)` 173 | 174 | ```ts 175 | import { FormPath } from '@formily/core' 176 | 177 | console.log(FormPath.parse('*(!aa,bb,cc)').match('aa')) //false 178 | console.log(FormPath.parse('*(!aa,bb,cc)').match('kk')) //true 179 | ``` 180 | 181 | #### Extended matching 182 | 183 | Extended matching is mainly used to match the starting substring of the path, syntax: `pattern~` 184 | 185 | ```ts 186 | import { FormPath } from '@formily/core' 187 | 188 | console.log(FormPath.parse('test~').match('test_111')) //true 189 | console.log(FormPath.parse('test~').match('test_222')) //true 190 | ``` 191 | 192 | #### Range match 193 | 194 | Range matching is mainly used to match the array index range, syntax: `*[x:y]`, x and y can be empty, representing open range matching 195 | 196 | ```ts 197 | import { FormPath } from '@formily/core' 198 | 199 | console.log(FormPath.parse('aa.*[1:2].bb').match('aa.1.bb')) //true 200 | console.log(FormPath.parse('aa.*[1:2].bb').match('aa.2.bb')) //true 201 | console.log(FormPath.parse('aa.*[1:2].bb').match('aa.3.bb')) //false 202 | console.log(FormPath.parse('aa.*[1:].bb').match('aa.3.bb')) //true 203 | console.log(FormPath.parse('aa.*[:100].bb').match('aa.3.bb')) //true 204 | console.log(FormPath.parse('aa.*[:100].bb').match('aa.1000.bb')) //false 205 | ``` 206 | 207 | #### Escape match 208 | 209 | For path nodes that contain keywords, we can use escape syntax matching, the syntax is `\\` or `[[]]` 210 | 211 | ```ts 212 | import { FormPath } from '@formily/core' 213 | 214 | console.log( 215 | FormPath.parse('aa.\\,\\*\\{\\}\\.\\(\\).bb').match( 216 | 'aa.\\,\\*\\{\\}\\.\\(\\).bb' 217 | ) 218 | ) //true 219 | console.log(FormPath.parse('aa.[[,*{}.()]].bb').match('aa.[[,*{}.()]].bb')) // true 220 | ``` 221 | 222 | #### Destructuring matching 223 | 224 | For the path with deconstruction expression, if we match, we can directly match without escaping 225 | 226 | ```ts 227 | import { FormPath } from '@formily/core' 228 | 229 | console.log(FormPath.parse('target.[aa,bb]').match('target.[aa,bb]')) //true 230 | ``` 231 | 232 | ## Method 233 | 234 | ### toString 235 | 236 | #### Description 237 | 238 | The complete string of the output path, supporting matching paths and data manipulation paths 239 | 240 | #### Signature 241 | 242 | ```ts 243 | interface toString { 244 | (): string 245 | } 246 | ``` 247 | 248 | #### Example 249 | 250 | ```ts 251 | import { FormPath } from '@formily/core' 252 | 253 | console.log(FormPath.parse('aa.bb.cc').toString()) //aa.bb.cc 254 | console.log(FormPath.parse('aa.bb.*').toString()) //aa.bb.* 255 | console.log(FormPath.parse('*(aa,bb,cc)').toString()) //*(aa,bb,cc) 256 | ``` 257 | 258 | ### toArray 259 | 260 | #### Description 261 | 262 | Array fragment of output path, only supports data manipulation path 263 | 264 | #### Signature 265 | 266 | ```ts 267 | interface toArray { 268 | (): Array<string | number> 269 | } 270 | ``` 271 | 272 | #### Example 273 | 274 | ```ts 275 | import { FormPath } from '@formily/core' 276 | 277 | console.log(FormPath.parse('aa.bb.cc').toArray().join('--')) //aa-bb-cc 278 | console.log(FormPath.parse('aa.bb.*').toArray()) //[] 279 | console.log(FormPath.parse('*(aa,bb,cc)').toArray()) //[] 280 | ``` 281 | 282 | ### concat 283 | 284 | #### Description 285 | 286 | Connection data operation path 287 | 288 | #### Signature 289 | 290 | ```ts 291 | interface concat { 292 | (...args: FormPathPattern[]): FormPath 293 | } 294 | ``` 295 | 296 | #### Example 297 | 298 | ```ts 299 | import { FormPath } from '@formily/core' 300 | 301 | console.log(FormPath.parse('aa.bb.cc').concat('dd.ee.mm').toString()) //aa.bb.cc.dd.ee.mm 302 | console.log( 303 | FormPath.parse('aa.bb.cc').concat(['dd', 'ee', 'mm'], 'kk.oo').toString() 304 | ) //aa.bb.cc.dd.ee.mm.kk.oo 305 | ``` 306 | 307 | ### slice 308 | 309 | #### Description 310 | 311 | Select a segment of the data operation path 312 | 313 | #### Signature 314 | 315 | ```ts 316 | interface slice { 317 | (start?: number, end?: number): FormPath 318 | } 319 | ``` 320 | 321 | #### Example 322 | 323 | ```ts 324 | import { FormPath } from '@formily/core' 325 | 326 | console.log(FormPath.parse('aa.bb.cc').slice(1).toString()) //bb.cc 327 | ``` 328 | 329 | ### push 330 | 331 | #### Description 332 | 333 | Push a fragment path to the data operation path 334 | 335 | #### Signature 336 | 337 | ```ts 338 | interface push { 339 | (...args: FormPathPattern[]): FormPath 340 | } 341 | ``` 342 | 343 | #### Example 344 | 345 | ```ts 346 | import { FormPath } from '@formily/core' 347 | 348 | console.log(FormPath.parse('aa.bb.cc').push('dd.kk').toString()) //aa.bb.cc.dd.kk 349 | ``` 350 | 351 | ### pop 352 | 353 | #### Description 354 | 355 | Pop the last key from the data operation path 356 | 357 | #### Signature 358 | 359 | ```ts 360 | interface pop { 361 | (): FormPath 362 | } 363 | ``` 364 | 365 | #### Example 366 | 367 | ```ts 368 | import { FormPath } from '@formily/core' 369 | 370 | console.log(FormPath.parse('aa.bb.cc').pop().toString()) //aa.bb 371 | ``` 372 | 373 | ### splice 374 | 375 | #### Description 376 | 377 | Splice the data operation path 378 | 379 | #### Signature 380 | 381 | ```ts 382 | interface splice { 383 | ( 384 | startIndex: number, 385 | deleteCount?: number, 386 | ...inertItems: Array<string | number> 387 | ): FormPath 388 | } 389 | ``` 390 | 391 | #### Example 392 | 393 | ```ts 394 | import { FormPath } from '@formily/core' 395 | 396 | console.log(FormPath.parse('aa.bb.cc').splice(2, 1).toString()) //aa.bb 397 | console.log(FormPath.parse('aa.bb.cc').splice(2, 0, 'ee.gg').toString()) //aa.bb.ee.gg.cc 398 | console.log(FormPath.parse('aa.bb.cc').splice(2, 0, ['kk', 'mm']).toString()) //aa.bb.kk.mm.cc 399 | ``` 400 | 401 | ### forEach 402 | 403 | #### Description 404 | 405 | Traverse the data operation path 406 | 407 | #### Signature 408 | 409 | ```ts 410 | interface forEach { 411 | (eacher: (key: string | number, index: number) => void): void 412 | } 413 | ``` 414 | 415 | #### Example 416 | 417 | ```ts 418 | import { FormPath } from '@formily/core' 419 | 420 | const keys = [] 421 | 422 | FormPath.parse('aa.bb.cc').forEach((key) => { 423 | keys.push(key) 424 | }) 425 | 426 | console.log(keys) //['aa','bb','cc'] 427 | ``` 428 | 429 | ### map 430 | 431 | #### Description 432 | 433 | Loop mapping data operation path 434 | 435 | #### Signature 436 | 437 | ```ts 438 | interface map { 439 | (mapper: (key: string | number, index: number) => void): void 440 | } 441 | ``` 442 | 443 | #### Example 444 | 445 | ```ts 446 | import { FormPath } from '@formily/core' 447 | 448 | console.log( 449 | FormPath.parse('aa.bb.cc').map((key) => { 450 | return key + '~' 451 | }) //['aa~','bb~','cc~'] 452 | ) 453 | ``` 454 | 455 | ### reduce 456 | 457 | #### Description 458 | 459 | The reduce method executes a reducer function (executed in ascending order) provided by you on each element in the path, and aggregates the results into a single return value. 460 | 461 | #### Signature 462 | 463 | ```ts 464 | interface reduce<T> { 465 | (reducer: (value: T, key: string | number, index: number) => void): void 466 | accumulator: T 467 | } 468 | ``` 469 | 470 | #### Example 471 | 472 | ```ts 473 | import { FormPath } from '@formily/core' 474 | 475 | console.log( 476 | FormPath.parse('aa.bb.cc').reduce((count) => { 477 | return count + 1 478 | }, 0) 479 | ) //3 480 | ``` 481 | 482 | ### parent 483 | 484 | #### Description 485 | 486 | Get the parent path of the current data operation path 487 | 488 | #### Signature 489 | 490 | ```ts 491 | interface parent { 492 | (): FormPath 493 | } 494 | ``` 495 | 496 | #### Example 497 | 498 | ```ts 499 | import { FormPath } from '@formily/core' 500 | 501 | console.log(FormPath.parse('aa.bb.cc').parent().toString()) //aa.bb 502 | ``` 503 | 504 | ### includes 505 | 506 | #### Description 507 | 508 | Used to determine whether a given data operation path is a subpath of the current data operation path 509 | 510 | #### Signature 511 | 512 | ```ts 513 | interface includes { 514 | (pattern: FormPathPattern): boolean 515 | } 516 | ``` 517 | 518 | #### Example 519 | 520 | ```ts 521 | import { FormPath } from '@formily/core' 522 | 523 | console.log(FormPath.parse('aa.bb.cc').includes('aa.bb')) //true 524 | 525 | console.log(FormPath.parse('aa.bb.cc').includes('cc.bb')) //false 526 | ``` 527 | 528 | ### transform 529 | 530 | #### Description 531 | 532 | Based on regular extraction data to do path assembly 533 | 534 | #### Signature 535 | 536 | ```ts 537 | interface transform<T> { 538 | (regExp: RegExp, callback: (...matches: string[]) => T): T 539 | } 540 | ``` 541 | 542 | #### Example 543 | 544 | ```ts 545 | import { FormPath } from '@formily/core' 546 | 547 | console.log( 548 | FormPath.parse('aa.1.cc').transform( 549 | /\d+/, 550 | (index) => `aa.${parseInt(index) + 1}.cc` 551 | ) 552 | ) //aa.2.cc 553 | ``` 554 | 555 | ### match 556 | 557 | #### Description 558 | 559 | Use path matching syntax to match the current path 560 | 561 | #### Signature 562 | 563 | ```ts 564 | interface match { 565 | (pattern: FormPathPattern): boolean 566 | } 567 | ``` 568 | 569 | #### Example 570 | 571 | ```ts 572 | import { FormPath } from '@formily/core' 573 | 574 | console.log(FormPath.parse('aa.1.cc').match('aa.*.cc')) //true 575 | ``` 576 | 577 | ### matchAliasGroup 578 | 579 | #### Description 580 | 581 | Alias group matching, mainly used to match address and path in formily 582 | 583 | #### Signature 584 | 585 | ```ts 586 | interface matchAliasGroup { 587 | (pattern: FormPathPattern, alias: FormPathPattern): boolean 588 | } 589 | ``` 590 | 591 | #### Example 592 | 593 | ```ts 594 | import { FormPath } from '@formily/core' 595 | 596 | console.log(FormPath.parse('aa.bb.cc').matchAliasGroup('aa.bb.cc', 'aa.cc')) //true 597 | ``` 598 | 599 | ### existIn 600 | 601 | #### Description 602 | 603 | Determine whether the specified data exists based on the current path 604 | 605 | #### Signature 606 | 607 | ```ts 608 | interface existIn { 609 | (pattern: FormPathPattern): boolean 610 | } 611 | ``` 612 | 613 | #### Example 614 | 615 | ```ts 616 | import { FormPath } from '@formily/core' 617 | 618 | console.log(FormPath.parse('aa.bb.cc').existIn({})) //false 619 | ``` 620 | 621 | ### getIn 622 | 623 | #### Description 624 | 625 | Obtain the specified data based on the current path 626 | 627 | #### Signature 628 | 629 | ```ts 630 | interface getIn { 631 | (pattern: FormPathPattern): any 632 | } 633 | ``` 634 | 635 | #### Example 636 | 637 | ```ts 638 | import { FormPath } from '@formily/core' 639 | 640 | console.log(FormPath.parse('aa.bb.cc').getIn({ aa: { bb: { cc: 'value' } } })) //value 641 | ``` 642 | 643 | ### setIn 644 | 645 | #### Description 646 | 647 | Update the specified data based on the current path 648 | 649 | #### Signature 650 | 651 | ```ts 652 | interface setIn { 653 | (pattern: FormPathPattern, value: any): void 654 | } 655 | ``` 656 | 657 | #### Example 658 | 659 | ```ts 660 | import { FormPath } from '@formily/core' 661 | 662 | const target = {} 663 | 664 | FormPath.parse('aa.bb.cc').setIn(target, 'value') 665 | 666 | console.log(FormPath.parse('aa.bb.cc').getIn(target)) //value 667 | ``` 668 | 669 | ### deleteIn 670 | 671 | #### Description 672 | 673 | Delete the specified data based on the current path 674 | 675 | #### Signature 676 | 677 | ```ts 678 | interface deleteIn { 679 | (pattern: FormPathPattern): boolean 680 | } 681 | ``` 682 | 683 | #### Example 684 | 685 | ```ts 686 | import { FormPath } from '@formily/core' 687 | 688 | const target = { 689 | aa: { 690 | bb: { 691 | cc: 'value', 692 | }, 693 | }, 694 | } 695 | 696 | FormPath.parse('aa.bb.cc').deleteIn(target) 697 | console.log(FormPath.parse('aa.bb.cc').getIn(target)) //undefined 698 | ``` 699 | 700 | ### ensureIn 701 | 702 | #### Description 703 | 704 | Ensure that there must be data under a certain path, if not, create data 705 | 706 | #### Signature 707 | 708 | ```ts 709 | interface ensureIn { 710 | (pattern: FormPathPattern, value: any): any 711 | } 712 | ``` 713 | 714 | #### Example 715 | 716 | ```ts 717 | import { FormPath } from '@formily/core' 718 | 719 | const target = {} 720 | 721 | FormPath.parse('aa.bb.cc').ensureIn(target, 'value') 722 | 723 | console.log(FormPath.parse('aa.bb.cc').getIn(target)) //value 724 | ``` 725 | 726 | ## Static method 727 | 728 | ### match 729 | 730 | #### Description 731 | 732 | Generate a path matcher based on matching paths 733 | 734 | #### Signature 735 | 736 | ```ts 737 | interface match { 738 | (pattern: FormPathPattern): (pattern: FormPathPattern) => boolean 739 | } 740 | ``` 741 | 742 | #### Example 743 | 744 | ```ts 745 | import { FormPath } from '@formily/core' 746 | 747 | console.log(FormPath.match('aa.*.cc')('aa.bb.cc')) // true 748 | ``` 749 | 750 | ### transform 751 | 752 | #### Description 753 | 754 | Regular conversion path 755 | 756 | #### Signature 757 | 758 | ```ts 759 | interface transform<T> { 760 | ( 761 | pattern: FormPathPattern, 762 | regexp: RegExp, 763 | callback: (...matches: string[]) => T 764 | ): T 765 | } 766 | ``` 767 | 768 | #### Example 769 | 770 | ```ts 771 | import { FormPath } from '@formily/core' 772 | 773 | console.log( 774 | FormPath.transform( 775 | 'aa.0.bb', 776 | /\d+/, 777 | (index) => `aa.${parseInt(index) + 1}.bb` 778 | ) 779 | ) // `aa.1.bb` 780 | ``` 781 | 782 | ### parse 783 | 784 | #### Description 785 | 786 | Resolve path 787 | 788 | #### Signature 789 | 790 | ```ts 791 | interface parse { 792 | (pattern: FormPathPattern): FormPath 793 | } 794 | ``` 795 | 796 | #### Example 797 | 798 | ```ts 799 | import { FormPath } from '@formily/core' 800 | 801 | console.log(FormPath.parse('aa.0.bb')) 802 | ``` 803 | 804 | ### getIn 805 | 806 | Get data based on path 807 | 808 | #### Signature 809 | 810 | ```ts 811 | interface getIn { 812 | (target: any, pattern: FormPathPattern): any 813 | } 814 | ``` 815 | 816 | #### Example 817 | 818 | ```ts 819 | import { FormPath } from '@formily/core' 820 | 821 | console.log(FormPath.getIn({ aa: [{ bb: 'value' }] }, 'aa.0.bb')) 822 | ``` 823 | 824 | ### setIn 825 | 826 | Update data based on path 827 | 828 | #### Signature 829 | 830 | ```ts 831 | interface setIn { 832 | (target: any, pattern: FormPathPattern, value: any): void 833 | } 834 | ``` 835 | 836 | #### Example 837 | 838 | ```ts 839 | import { FormPath } from '@formily/core' 840 | 841 | const target = {} 842 | 843 | FormPath.setIn(target, 'aa.bb.cc', 'value') 844 | 845 | console.log(target) //{aa:{bb:{cc:'value'}}} 846 | ``` 847 | 848 | ### deleteIn 849 | 850 | Delete data based on path 851 | 852 | #### Signature 853 | 854 | ```ts 855 | interface deleteIn { 856 | (target: any, pattern: FormPathPattern): void 857 | } 858 | ``` 859 | 860 | #### Example 861 | 862 | ```ts 863 | import { FormPath } from '@formily/core' 864 | 865 | const target = { 866 | aa: { 867 | bb: { 868 | cc: 'value', 869 | }, 870 | }, 871 | } 872 | 873 | FormPath.deleteIn(target, 'aa.bb.cc') 874 | 875 | console.log(target) //{aa:{bb:{}}} 876 | ``` 877 | 878 | ### existIn 879 | 880 | #### Description 881 | 882 | Determine whether there is data in the specified path 883 | 884 | #### Signature 885 | 886 | ```ts 887 | interface existIn { 888 | (target: any, pattern: FormPathPattern): void 889 | } 890 | ``` 891 | 892 | #### Example 893 | 894 | ```ts 895 | import { FormPath } from '@formily/core' 896 | 897 | const target = { 898 | aa: { 899 | bb: { 900 | cc: 'value', 901 | }, 902 | }, 903 | } 904 | 905 | console.log(FormPath.existIn(target, 'aa.bb.cc')) //true 906 | console.log(FormPath.existIn(target, 'aa.bb.kk')) //false 907 | ``` 908 | 909 | ### ensureIn 910 | 911 | #### Description 912 | 913 | Ensure that there must be data under a certain path, if not, create data 914 | 915 | #### Signature 916 | 917 | ```ts 918 | interface ensureIn { 919 | (target: any, pattern: FormPathPattern, defaultValue: any): any 920 | } 921 | ``` 922 | 923 | #### Example 924 | 925 | ```ts 926 | import { FormPath } from '@formily/core' 927 | 928 | const target = {} 929 | 930 | FormPath.ensureIn(target, 'aa.bb.cc', 'value') 931 | 932 | console.log(FormPath.getIn(target, 'aa.bb.cc')) //value 933 | ``` 934 | ``` -------------------------------------------------------------------------------- /packages/antd/src/form-item/style.less: -------------------------------------------------------------------------------- ``` 1 | @root-entry-name: 'default'; 2 | @import (reference) '~antd/es/style/themes/index.less'; 3 | @import (reference) '~antd/lib/input/style/mixin.less'; 4 | @import './grid.less'; 5 | @import './animation.less'; 6 | 7 | @form-item-cls: ~'@{ant-prefix}-formily-item'; 8 | 9 | .@{form-item-cls} { 10 | display: flex; 11 | margin-bottom: @form-item-margin-bottom - 2; 12 | position: relative; 13 | font-size: @font-size-base; 14 | 15 | &-label { 16 | line-height: @height-base; 17 | min-height: @height-base - 2; 18 | label { 19 | cursor: text; 20 | } 21 | } 22 | 23 | textarea.@{ant-prefix}-input { 24 | height: auto; 25 | } 26 | 27 | // input[type=file] 28 | .@{ant-prefix}-upload { 29 | background: transparent; 30 | } 31 | 32 | .@{ant-prefix}-upload.@{ant-prefix}-upload-drag { 33 | background: @background-color-light; 34 | } 35 | 36 | input[type='radio'], 37 | input[type='checkbox'] { 38 | width: @font-size-base; 39 | height: @font-size-base; 40 | } 41 | 42 | // Radios and checkboxes on same line 43 | .@{ant-prefix}-radio-inline, 44 | .@{ant-prefix}-checkbox-inline { 45 | display: inline-block; 46 | margin-left: 8px; 47 | font-weight: normal; 48 | vertical-align: middle; 49 | cursor: pointer; 50 | 51 | &:first-child { 52 | margin-left: 0; 53 | } 54 | } 55 | 56 | .@{ant-prefix}-checkbox-vertical, 57 | .@{ant-prefix}-radio-vertical { 58 | display: block; 59 | } 60 | 61 | .@{ant-prefix}-checkbox-vertical + .@{ant-prefix}-checkbox-vertical, 62 | .@{ant-prefix}-radio-vertical + .@{ant-prefix}-radio-vertical { 63 | margin-left: 0; 64 | } 65 | 66 | .@{ant-prefix}-input-number { 67 | width: 100%; 68 | 69 | + .@{ant-prefix}-form-text { 70 | margin-left: 8px; 71 | } 72 | 73 | &-handler-wrap { 74 | z-index: 2; // https://github.com/ant-design/ant-design/issues/6289 75 | } 76 | } 77 | 78 | .@{ant-prefix}-select, 79 | .@{ant-prefix}-cascader-picker, 80 | .@{ant-prefix}-picker { 81 | width: 100%; 82 | } 83 | 84 | // Don't impact select inside input group 85 | .@{ant-prefix}-input-group .@{ant-prefix}-select, 86 | .@{ant-prefix}-input-group .@{ant-prefix}-cascader-picker { 87 | width: auto; 88 | } 89 | } 90 | 91 | .@{form-item-cls}-label { 92 | position: relative; 93 | display: flex; 94 | 95 | &-content { 96 | overflow: hidden; 97 | text-overflow: ellipsis; 98 | white-space: nowrap; 99 | } 100 | 101 | &-tooltip { 102 | cursor: help; 103 | 104 | * { 105 | cursor: help; 106 | } 107 | 108 | label { 109 | border-bottom: 1px dashed currentColor; 110 | } 111 | } 112 | } 113 | 114 | .@{form-item-cls}-label { 115 | color: @heading-color; 116 | } 117 | 118 | .@{form-item-cls}-label-align-left { 119 | > .@{form-item-cls}-label { 120 | justify-content: flex-start; 121 | } 122 | } 123 | 124 | .@{form-item-cls}-label-align-right { 125 | > .@{form-item-cls}-label { 126 | justify-content: flex-end; 127 | } 128 | } 129 | 130 | .@{form-item-cls}-label-wrap { 131 | .@{form-item-cls}-label { 132 | label { 133 | white-space: pre-line; 134 | word-break: break-all; 135 | } 136 | } 137 | } 138 | 139 | .@{form-item-cls}-feedback-layout-terse { 140 | margin-bottom: 8px; 141 | 142 | &.@{form-item-cls}-feedback-has-text:not(.@{form-item-cls}-inset) { 143 | margin-bottom: 0; 144 | } 145 | } 146 | 147 | .@{form-item-cls}-feedback-layout-loose { 148 | margin-bottom: 22px; 149 | 150 | &.@{form-item-cls}-feedback-has-text:not(.@{form-item-cls}-inset) { 151 | margin-bottom: 0; 152 | } 153 | } 154 | 155 | .@{form-item-cls}-feedback-layout-none { 156 | margin-bottom: 0px; 157 | 158 | &.@{form-item-cls}-feedback-has-text:not(.@{form-item-cls}-inset) { 159 | margin-bottom: 0; 160 | } 161 | } 162 | 163 | .@{form-item-cls}-control { 164 | flex: 1; 165 | max-width: 100%; 166 | 167 | .@{form-item-cls}-control-content { 168 | display: flex; 169 | 170 | .@{form-item-cls}-control-content-component { 171 | width: 100%; 172 | min-height: @height-base - 2; 173 | line-height: @height-base + 2; 174 | 175 | &-has-feedback-icon { 176 | flex: 1; 177 | position: relative; 178 | display: flex; 179 | align-items: center; 180 | } 181 | } 182 | 183 | .@{form-item-cls}-addon-before { 184 | margin-right: 8px; 185 | display: inline-flex; 186 | align-items: center; 187 | min-height: @height-base; 188 | flex-shrink: 0; 189 | } 190 | 191 | .@{form-item-cls}-addon-after { 192 | margin-left: 8px; 193 | display: inline-flex; 194 | align-items: center; 195 | min-height: @height-base; 196 | flex-shrink: 0; 197 | } 198 | } 199 | 200 | .@{form-item-cls}-help, 201 | .@{form-item-cls}-extra { 202 | min-height: 22px; 203 | line-height: 22px; 204 | color: @text-color-secondary; 205 | } 206 | } 207 | 208 | .@{form-item-cls}-size-small { 209 | font-size: @font-size-sm; 210 | 211 | line-height: @height-sm; 212 | 213 | .@{form-item-cls}-label { 214 | line-height: @height-sm; 215 | min-height: @height-sm - 2; 216 | } 217 | 218 | .@{form-item-cls}-control-content { 219 | .@{form-item-cls}-control-content-component { 220 | min-height: @height-sm - 2; 221 | line-height: @height-sm + 2; 222 | } 223 | } 224 | 225 | .@{form-item-cls}-help, 226 | .@{form-item-cls}-extra { 227 | min-height: @height-sm - 4; 228 | line-height: @height-sm - 4; 229 | } 230 | 231 | .@{form-item-cls}-control-content { 232 | min-height: @height-sm - 2; 233 | } 234 | 235 | .@{form-item-cls}-label > label { 236 | height: @height-sm - 2; 237 | } 238 | 239 | .@{ant-prefix}-input-affix-wrapper, 240 | .@{ant-prefix}-input-number, 241 | .@{ant-prefix}-picker { 242 | padding: 0px 11px; 243 | 244 | input { 245 | height: @height-sm - 2; 246 | font-size: @font-size-sm; 247 | } 248 | } 249 | 250 | .@{ant-prefix}-cascader-picker { 251 | height: @height-sm - 2; 252 | 253 | input { 254 | padding: 0 7px; 255 | height: @height-sm - 2; 256 | font-size: @font-size-sm; 257 | } 258 | } 259 | 260 | .@{ant-prefix}-select-single:not(.@{ant-prefix}-select-customize-input) 261 | .@{ant-prefix}-select-selector { 262 | padding: 0px 11px; 263 | height: @height-sm - 2; 264 | font-size: @font-size-sm; 265 | line-height: @height-sm; 266 | 267 | .@{ant-prefix}-select-selection-search { 268 | height: @height-sm; 269 | line-height: @height-sm - 2; 270 | 271 | &-input { 272 | height: @height-sm; 273 | line-height: @height-sm - 2; 274 | } 275 | } 276 | 277 | .@{ant-prefix}-select-selection-placeholder { 278 | line-height: @height-sm - 2; 279 | height: @height-sm; 280 | } 281 | 282 | .@{ant-prefix}-select-selection-item { 283 | line-height: @height-sm - 2; 284 | height: @height-sm; 285 | } 286 | } 287 | 288 | .@{ant-prefix}-select-multiple:not(.@{ant-prefix}-select-customize-input) 289 | .@{ant-prefix}-select-selector { 290 | padding: 0px 2px; 291 | height: @height-sm - 2; 292 | font-size: @font-size-sm; 293 | line-height: @height-sm; 294 | 295 | &::after { 296 | height: @height-sm - 8; 297 | line-height: @height-sm - 8; 298 | } 299 | 300 | .@{ant-prefix}-select-selection-search { 301 | height: @height-sm - 8; 302 | line-height: @height-sm - 8; 303 | margin-inline-start: 0; 304 | 305 | &-input { 306 | height: @height-sm - 12; 307 | line-height: @height-sm - 12; 308 | } 309 | } 310 | 311 | .@{ant-prefix}-select-selection-placeholder { 312 | line-height: @height-sm - 8; 313 | height: @height-sm - 8; 314 | left: 4px; 315 | } 316 | 317 | .@{ant-prefix}-select-selection-overflow-item { 318 | align-self: flex-start; 319 | } 320 | 321 | .@{ant-prefix}-select-selection-item { 322 | line-height: @height-sm - 10; 323 | height: @height-sm - 8; 324 | } 325 | } 326 | 327 | &.@{form-item-cls}-feedback-layout-terse { 328 | margin-bottom: 8px; 329 | 330 | &.@{form-item-cls}-feedback-has-text:not(.@{form-item-cls}-inset) { 331 | margin-bottom: 0; 332 | } 333 | } 334 | 335 | &.@{form-item-cls}-feedback-layout-loose { 336 | margin-bottom: @height-sm - 4; 337 | 338 | &.@{form-item-cls}-feedback-has-text:not(.@{form-item-cls}-inset) { 339 | margin-bottom: 0; 340 | } 341 | } 342 | } 343 | 344 | .@{form-item-cls}-size-large { 345 | font-size: @font-size-lg; 346 | line-height: @height-lg; 347 | 348 | .@{form-item-cls}-label { 349 | line-height: @height-lg; 350 | min-height: @height-lg - 2; 351 | } 352 | 353 | .@{form-item-cls}-control-content { 354 | .@{form-item-cls}-control-content-component { 355 | min-height: @height-lg - 2; 356 | line-height: @height-lg; 357 | } 358 | } 359 | 360 | .@{form-item-cls}-help, 361 | .@{form-item-cls}-extra { 362 | min-height: @form-item-margin-bottom; 363 | line-height: @form-item-margin-bottom; 364 | } 365 | 366 | .@{form-item-cls}-control-content { 367 | min-height: @height-lg - 2; 368 | } 369 | 370 | .@{ant-prefix}-input { 371 | font-size: @font-size-lg; 372 | } 373 | 374 | .@{ant-prefix}-input-number { 375 | font-size: @font-size-lg; 376 | 377 | input { 378 | height: @height-lg - 2; 379 | } 380 | } 381 | 382 | .@{ant-prefix}-input-affix-wrapper, 383 | .@{ant-prefix}-picker { 384 | padding: 0px 11px; 385 | line-height: @height-lg - 2; 386 | 387 | input { 388 | height: @height-lg - 2; 389 | font-size: @font-size-lg; 390 | } 391 | } 392 | 393 | .@{ant-prefix}-btn { 394 | height: @height-lg; 395 | padding: 0px 8px; 396 | } 397 | 398 | .@{ant-prefix}-radio-button-wrapper { 399 | height: @height-lg; 400 | line-height: @height-lg; 401 | } 402 | 403 | .@{ant-prefix}-cascader-picker { 404 | height: @height-lg - 2; 405 | 406 | input { 407 | padding: 0px 11px; 408 | height: @height-lg - 2; 409 | font-size: @font-size-lg; 410 | } 411 | } 412 | 413 | .@{ant-prefix}-select-single:not(.@{ant-prefix}-select-customize-input) 414 | .@{ant-prefix}-select-selector { 415 | padding: 0px 11px; 416 | height: @height-lg; 417 | font-size: @font-size-lg; 418 | line-height: @height-lg; 419 | 420 | .@{ant-prefix}-select-selection-search { 421 | height: @height-lg; 422 | line-height: @height-lg - 2; 423 | 424 | &-input { 425 | height: @height-lg; 426 | line-height: @height-lg - 2; 427 | } 428 | } 429 | 430 | .@{ant-prefix}-select-selection-placeholder { 431 | line-height: @height-lg - 2; 432 | height: @height-lg; 433 | } 434 | 435 | .@{ant-prefix}-select-selection-item { 436 | line-height: @height-lg - 2; 437 | height: @height-lg; 438 | } 439 | } 440 | 441 | .@{ant-prefix}-select-multiple:not(.@{ant-prefix}-select-customize-input) 442 | .@{ant-prefix}-select-selector { 443 | padding: 0px 2px; 444 | height: @height-lg - 2; 445 | font-size: @font-size-lg; 446 | line-height: @height-lg; 447 | 448 | &::after { 449 | height: @height-lg - 8; 450 | line-height: @height-lg - 8; 451 | } 452 | 453 | .@{ant-prefix}-select-selection-search { 454 | height: @height-lg - 8; 455 | line-height: @height-lg - 8; 456 | 457 | &-input { 458 | height: @height-lg - 12; 459 | line-height: @height-lg - 12; 460 | } 461 | } 462 | 463 | .@{ant-prefix}-select-selection-placeholder { 464 | line-height: @height-lg - 8; 465 | height: @height-lg - 8; 466 | } 467 | 468 | .@{ant-prefix}-select-selection-overflow-item { 469 | align-self: flex-start; 470 | } 471 | 472 | .@{ant-prefix}-select-selection-item { 473 | line-height: @height-lg - 10; 474 | height: @height-lg - 8; 475 | } 476 | } 477 | 478 | &.@{form-item-cls}-feedback-layout-terse { 479 | margin-bottom: 8px; 480 | 481 | &.@{form-item-cls}-feedback-has-text:not(.@{form-item-cls}-inset) { 482 | margin-bottom: 0; 483 | } 484 | } 485 | 486 | &.@{form-item-cls}-feedback-layout-loose { 487 | margin-bottom: @form-item-margin-bottom; 488 | 489 | &.@{form-item-cls}-feedback-has-text:not(.@{form-item-cls}-inset) { 490 | margin-bottom: 0; 491 | } 492 | } 493 | } 494 | 495 | .@{form-item-cls} { 496 | &-layout-vertical { 497 | display: block; 498 | 499 | .@{form-item-cls}-label { 500 | min-height: @height-base - 10; 501 | line-height: 1.5715; 502 | } 503 | } 504 | } 505 | 506 | .@{form-item-cls}-feedback-layout-popover { 507 | margin-bottom: 8px; 508 | } 509 | 510 | .@{form-item-cls}-label-tooltip-icon { 511 | margin-left: 4px; 512 | color: #00000073; 513 | display: flex; 514 | align-items: center; 515 | max-height: @height-base; 516 | 517 | span { 518 | display: inline-flex; 519 | } 520 | } 521 | 522 | .@{form-item-cls}-control-align-left { 523 | .@{form-item-cls}-control-content { 524 | justify-content: flex-start; 525 | } 526 | } 527 | 528 | .@{form-item-cls}-control-align-right { 529 | .@{form-item-cls}-control-content { 530 | justify-content: flex-end; 531 | } 532 | } 533 | 534 | .@{form-item-cls}-control-wrap { 535 | .@{form-item-cls}-control { 536 | white-space: pre-line; 537 | word-break: break-all; 538 | } 539 | } 540 | 541 | .@{form-item-cls}-asterisk { 542 | color: @error-color; 543 | margin-right: 4px; 544 | display: inline-block; 545 | font-family: SimSun, sans-serif; 546 | } 547 | 548 | .@{form-item-cls}-optional { 549 | color: rgba(0, 0, 0, 0.45); 550 | } 551 | 552 | .@{form-item-cls}-colon { 553 | margin-left: 2px; 554 | margin-right: 8px; 555 | } 556 | 557 | .@{form-item-cls}-help, 558 | .@{form-item-cls}-extra { 559 | clear: both; 560 | min-height: @form-item-margin-bottom - 2; 561 | color: rgba(0, 0, 0, 0.45); 562 | transition: color 0.3s cubic-bezier(0.215, 0.61, 0.355, 1); 563 | padding-top: 0px; 564 | } 565 | 566 | .@{form-item-cls}-fullness { 567 | > .@{form-item-cls}-control { 568 | > .@{form-item-cls}-control-content { 569 | > .@{form-item-cls}-control-content-component { 570 | > *:first-child { 571 | width: 100%; 572 | } 573 | } 574 | } 575 | } 576 | } 577 | 578 | .@{form-item-cls}-control-content-component-has-feedback-icon { 579 | border-radius: 2px; 580 | border: 1px solid @border-color-base; 581 | padding-right: 8px; 582 | transition: all 0.3s; 583 | touch-action: manipulation; 584 | outline: none; 585 | 586 | .@{ant-prefix}-input-number, 587 | .@{ant-prefix}-picker, 588 | .@{ant-prefix}-cascader-picker:focus .@{ant-prefix}-cascader-input, 589 | .@{ant-prefix}-select:not(.@{ant-prefix}-select-customize-input) 590 | .@{ant-prefix}-select-selector, 591 | .@{ant-prefix}-input-affix-wrapper, 592 | .@{ant-prefix}-input { 593 | border: none !important; 594 | box-shadow: none !important; 595 | } 596 | } 597 | 598 | .@{form-item-cls}-bordered-none { 599 | .@{ant-prefix}-input-number, 600 | .@{ant-prefix}-input-affix-wrapper, 601 | .@{ant-prefix}-picker, 602 | .@{ant-prefix}-cascader-picker:focus .@{ant-prefix}-cascader-input, 603 | .@{ant-prefix}-select:not(.@{ant-prefix}-select-customize-input) 604 | .@{ant-prefix}-select-selector, 605 | .@{ant-prefix}-input { 606 | border: none !important; 607 | box-shadow: none !important; 608 | } 609 | 610 | .@{ant-prefix}-input-number-handler-wrap { 611 | border: none !important; 612 | 613 | .@{ant-prefix}-input-number-handler { 614 | border: none !important; 615 | } 616 | } 617 | } 618 | 619 | .@{form-item-cls}-inset { 620 | border-radius: 2px; 621 | border: 1px solid @border-color-base; 622 | padding-left: 12px; 623 | transition: 0.3s all; 624 | 625 | .@{ant-prefix}-input-number, 626 | .@{ant-prefix}-picker, 627 | .@{ant-prefix}-cascader-picker:focus .@{ant-prefix}-cascader-input, 628 | .@{ant-prefix}-select:not(.@{ant-prefix}-select-customize-input) 629 | .@{ant-prefix}-select-selector, 630 | .@{ant-prefix}-input-affix-wrapper, 631 | .@{ant-prefix}-input { 632 | border: none !important; 633 | box-shadow: none !important; 634 | } 635 | 636 | .@{ant-prefix}-input-number-handler-wrap { 637 | border: none !important; 638 | 639 | .@{ant-prefix}-input-number-handler { 640 | border: none !important; 641 | } 642 | } 643 | 644 | &:hover { 645 | .hover(); 646 | } 647 | } 648 | 649 | .@{form-item-cls}-inset-active { 650 | .active(); 651 | } 652 | 653 | .@{form-item-cls}-active { 654 | .@{form-item-cls}-control-content-component-has-feedback-icon { 655 | .active(); 656 | } 657 | 658 | .@{ant-prefix}-input-number, 659 | .@{ant-prefix}-picker, 660 | .@{ant-prefix}-cascader-picker:focus .@{ant-prefix}-cascader-input, 661 | .@{ant-prefix}-select:not(.@{ant-prefix}-select-customize-input) 662 | .@{ant-prefix}-select-selector, 663 | .@{ant-prefix}-input { 664 | .active(); 665 | } 666 | } 667 | 668 | .@{form-item-cls} { 669 | &:hover { 670 | .@{form-item-cls}-control-content-component-has-feedback-icon { 671 | .hover(); 672 | } 673 | } 674 | } 675 | 676 | .@{form-item-cls}-error { 677 | .@{ant-prefix}-select-selector, 678 | .@{ant-prefix}-cascader-picker, 679 | .@{ant-prefix}-picker, 680 | .@{ant-prefix}-input, 681 | .@{ant-prefix}-input-number, 682 | .@{ant-prefix}-input-affix-wrapper, 683 | .@{ant-prefix}-input-affix-wrapper, 684 | .@{ant-prefix}-input { 685 | border-color: @error-color !important; 686 | } 687 | 688 | .@{ant-prefix}-select-selector, 689 | .@{ant-prefix}-cascader-picker, 690 | .@{ant-prefix}-picker, 691 | .@{ant-prefix}-input, 692 | .@{ant-prefix}-input-number, 693 | .@{ant-prefix}-input-affix-wrapper, 694 | .@{ant-prefix}-input-affix-wrapper:hover, 695 | .@{ant-prefix}-input:hover { 696 | border-color: @error-color !important; 697 | } 698 | 699 | .@{ant-prefix}-select:not(.@{ant-prefix}-select-disabled):not(.@{ant-prefix}-select-customize-input) { 700 | .@{ant-prefix}-select-selector { 701 | background-color: @form-error-input-bg; 702 | border-color: @error-color !important; 703 | } 704 | 705 | &.@{ant-prefix}-select-open .@{ant-prefix}-select-selector, 706 | &.@{ant-prefix}-select-focused .@{ant-prefix}-select-selector { 707 | .active(@error-color); 708 | } 709 | } 710 | 711 | .@{ant-prefix}-input-number, 712 | .@{ant-prefix}-picker { 713 | background-color: @form-error-input-bg; 714 | border-color: @error-color; 715 | 716 | &-focused, 717 | &:focus { 718 | .active(@error-color); 719 | } 720 | 721 | &:not([disabled]):hover { 722 | background-color: @form-error-input-bg; 723 | border-color: @error-color; 724 | } 725 | } 726 | 727 | .@{ant-prefix}-cascader-picker:focus .@{ant-prefix}-cascader-input { 728 | background-color: @form-error-input-bg; 729 | .active(@error-color); 730 | } 731 | 732 | .@{ant-prefix}-input-affix-wrapper-focused, 733 | .@{ant-prefix}-input-affix-wrapper:focus, 734 | .@{ant-prefix}-input-focused, 735 | .@{ant-prefix}-input:focus { 736 | .active(@error-color); 737 | } 738 | } 739 | 740 | .@{form-item-cls}-error-help { 741 | color: @error-color !important; 742 | } 743 | 744 | .@{form-item-cls}-warning-help { 745 | color: @warning-color !important; 746 | } 747 | 748 | .@{form-item-cls}-success-help { 749 | color: @success-color !important; 750 | } 751 | 752 | .@{form-item-cls}-warning { 753 | .@{ant-prefix}-select-selector, 754 | .@{ant-prefix}-cascader-picker, 755 | .@{ant-prefix}-picker, 756 | .@{ant-prefix}-input, 757 | .@{ant-prefix}-input-number, 758 | .@{ant-prefix}-input-affix-wrapper, 759 | .@{ant-prefix}-input-affix-wrapper, 760 | .@{ant-prefix}-input { 761 | border-color: @warning-color !important; 762 | } 763 | 764 | .@{ant-prefix}-select-selector, 765 | .@{ant-prefix}-cascader-picker, 766 | .@{ant-prefix}-picker, 767 | .@{ant-prefix}-input, 768 | .@{ant-prefix}-input-number, 769 | .@{ant-prefix}-input-affix-wrapper, 770 | .@{ant-prefix}-input-affix-wrapper:hover, 771 | .@{ant-prefix}-input:hover { 772 | border-color: @warning-color !important; 773 | } 774 | 775 | .@{ant-prefix}-select:not(.@{ant-prefix}-select-disabled):not(.@{ant-prefix}-select-customize-input) { 776 | .@{ant-prefix}-select-selector { 777 | background-color: @form-warning-input-bg; 778 | border-color: @warning-color !important; 779 | } 780 | 781 | &.@{ant-prefix}-select-open .@{ant-prefix}-select-selector, 782 | &.@{ant-prefix}-select-focused .@{ant-prefix}-select-selector { 783 | .active(@warning-color); 784 | } 785 | } 786 | 787 | .@{ant-prefix}-input-number, 788 | .@{ant-prefix}-picker { 789 | background-color: @form-warning-input-bg; 790 | border-color: @warning-color; 791 | 792 | &-focused, 793 | &:focus { 794 | .active(@warning-color); 795 | } 796 | 797 | &:not([disabled]):hover { 798 | background-color: @form-warning-input-bg; 799 | border-color: @warning-color; 800 | } 801 | } 802 | 803 | .@{ant-prefix}-cascader-picker:focus .@{ant-prefix}-cascader-input { 804 | background-color: @form-warning-input-bg; 805 | .active(@warning-color); 806 | } 807 | 808 | .@{ant-prefix}-input-affix-wrapper-focused, 809 | .@{ant-prefix}-input-affix-wrapper:focus, 810 | .@{ant-prefix}-input-focused, 811 | .@{ant-prefix}-input:focus { 812 | .active(@warning-color); 813 | } 814 | } 815 | 816 | .@{form-item-cls}-success { 817 | .@{ant-prefix}-select-selector, 818 | .@{ant-prefix}-cascader-picker, 819 | .@{ant-prefix}-picker, 820 | .@{ant-prefix}-input, 821 | .@{ant-prefix}-input-number, 822 | .@{ant-prefix}-input-affix-wrapper, 823 | .@{ant-prefix}-input-affix-wrapper, 824 | .@{ant-prefix}-input { 825 | border-color: @success-color !important; 826 | } 827 | 828 | .@{ant-prefix}-select-selector, 829 | .@{ant-prefix}-cascader-picker, 830 | .@{ant-prefix}-picker, 831 | .@{ant-prefix}-input, 832 | .@{ant-prefix}-input-number, 833 | .@{ant-prefix}-input-affix-wrapper, 834 | .@{ant-prefix}-input-affix-wrapper:hover, 835 | .@{ant-prefix}-input:hover { 836 | border-color: @success-color !important; 837 | } 838 | 839 | .@{ant-prefix}-input-affix-wrapper-focused, 840 | .@{ant-prefix}-input-affix-wrapper:focus, 841 | .@{ant-prefix}-input-focused, 842 | .@{ant-prefix}-input:focus { 843 | border-color: @success-color !important; 844 | border-right-width: 1px !important; 845 | outline: 0; 846 | } 847 | } 848 | ```