This is page 11 of 52. Use http://codebase.md/alibaba/formily?lines=true&page={x} to view the full context. # Directory Structure ``` ├── .all-contributorsrc ├── .codecov.yml ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .github │ ├── CONTRIBUTING.md │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE │ │ └── config.yml │ ├── PULL_REQUEST_TEMPLATE.md │ └── workflows │ ├── check-pr-title.yml │ ├── ci.yml │ ├── commitlint.yml │ ├── issue-open-check.yml │ ├── package-size.yml │ └── pr-welcome.yml ├── .gitignore ├── .prettierrc.js ├── .umirc.js ├── .vscode │ └── cspell.json ├── .yarnrc ├── CHANGELOG.md ├── commitlint.config.js ├── devtools │ ├── .eslintrc │ └── chrome-extension │ ├── .npmignore │ ├── assets │ │ └── img │ │ ├── loading.svg │ │ └── logo │ │ ├── 128x128.png │ │ ├── 16x16.png │ │ ├── 38x38.png │ │ ├── 48x48.png │ │ ├── error.png │ │ ├── gray.png │ │ └── scalable.png │ ├── config │ │ ├── webpack.base.ts │ │ ├── webpack.dev.ts │ │ └── webpack.prod.ts │ ├── LICENSE.md │ ├── package.json │ ├── src │ │ ├── app │ │ │ ├── components │ │ │ │ ├── FieldTree.tsx │ │ │ │ ├── filter.ts │ │ │ │ ├── LeftPanel.tsx │ │ │ │ ├── RightPanel.tsx │ │ │ │ ├── SearchBox.tsx │ │ │ │ └── Tabs.tsx │ │ │ ├── demo.tsx │ │ │ └── index.tsx │ │ └── extension │ │ ├── backend.ts │ │ ├── background.ts │ │ ├── content.ts │ │ ├── devpanel.tsx │ │ ├── devtools.tsx │ │ ├── inject.ts │ │ ├── manifest.json │ │ ├── popup.tsx │ │ └── views │ │ ├── devpanel.ejs │ │ ├── devtools.ejs │ │ └── popup.ejs │ ├── tsconfig.build.json │ └── tsconfig.json ├── docs │ ├── functions │ │ ├── contributors.ts │ │ └── npm-search.ts │ ├── guide │ │ ├── advanced │ │ │ ├── async.md │ │ │ ├── async.zh-CN.md │ │ │ ├── build.md │ │ │ ├── build.zh-CN.md │ │ │ ├── business-logic.md │ │ │ ├── business-logic.zh-CN.md │ │ │ ├── calculator.md │ │ │ ├── calculator.zh-CN.md │ │ │ ├── controlled.md │ │ │ ├── controlled.zh-CN.md │ │ │ ├── custom.md │ │ │ ├── custom.zh-CN.md │ │ │ ├── destructor.md │ │ │ ├── destructor.zh-CN.md │ │ │ ├── input.less │ │ │ ├── layout.md │ │ │ ├── layout.zh-CN.md │ │ │ ├── linkages.md │ │ │ ├── linkages.zh-CN.md │ │ │ ├── validate.md │ │ │ └── validate.zh-CN.md │ │ ├── contribution.md │ │ ├── contribution.zh-CN.md │ │ ├── form-builder.md │ │ ├── form-builder.zh-CN.md │ │ ├── index.md │ │ ├── index.zh-CN.md │ │ ├── issue-helper.md │ │ ├── issue-helper.zh-CN.md │ │ ├── learn-formily.md │ │ ├── learn-formily.zh-CN.md │ │ ├── quick-start.md │ │ ├── quick-start.zh-CN.md │ │ ├── scenes │ │ │ ├── dialog-drawer.md │ │ │ ├── dialog-drawer.zh-CN.md │ │ │ ├── edit-detail.md │ │ │ ├── edit-detail.zh-CN.md │ │ │ ├── index.less │ │ │ ├── login-register.md │ │ │ ├── login-register.zh-CN.md │ │ │ ├── more.md │ │ │ ├── more.zh-CN.md │ │ │ ├── query-list.md │ │ │ ├── query-list.zh-CN.md │ │ │ ├── step-form.md │ │ │ ├── step-form.zh-CN.md │ │ │ ├── tab-form.md │ │ │ ├── tab-form.zh-CN.md │ │ │ └── VerifyCode.tsx │ │ ├── upgrade.md │ │ └── upgrade.zh-CN.md │ ├── index.md │ ├── index.zh-CN.md │ └── site │ ├── Contributors.less │ ├── Contributors.tsx │ ├── QrCode.less │ ├── QrCode.tsx │ ├── Section.less │ ├── Section.tsx │ └── styles.less ├── global.config.ts ├── jest.config.js ├── lerna.json ├── LICENSE.md ├── package.json ├── packages │ ├── .eslintrc │ ├── antd │ │ ├── __tests__ │ │ │ ├── moment.spec.ts │ │ │ └── sideEffects.spec.ts │ │ ├── .npmignore │ │ ├── .umirc.js │ │ ├── build-style.ts │ │ ├── create-style.ts │ │ ├── docs │ │ │ ├── components │ │ │ │ ├── ArrayCards.md │ │ │ │ ├── ArrayCards.zh-CN.md │ │ │ │ ├── ArrayCollapse.md │ │ │ │ ├── ArrayCollapse.zh-CN.md │ │ │ │ ├── ArrayItems.md │ │ │ │ ├── ArrayItems.zh-CN.md │ │ │ │ ├── ArrayTable.md │ │ │ │ ├── ArrayTable.zh-CN.md │ │ │ │ ├── ArrayTabs.md │ │ │ │ ├── ArrayTabs.zh-CN.md │ │ │ │ ├── Cascader.md │ │ │ │ ├── Cascader.zh-CN.md │ │ │ │ ├── Checkbox.md │ │ │ │ ├── Checkbox.zh-CN.md │ │ │ │ ├── DatePicker.md │ │ │ │ ├── DatePicker.zh-CN.md │ │ │ │ ├── Editable.md │ │ │ │ ├── Editable.zh-CN.md │ │ │ │ ├── Form.md │ │ │ │ ├── Form.zh-CN.md │ │ │ │ ├── FormButtonGroup.md │ │ │ │ ├── FormButtonGroup.zh-CN.md │ │ │ │ ├── FormCollapse.md │ │ │ │ ├── FormCollapse.zh-CN.md │ │ │ │ ├── FormDialog.md │ │ │ │ ├── FormDialog.zh-CN.md │ │ │ │ ├── FormDrawer.md │ │ │ │ ├── FormDrawer.zh-CN.md │ │ │ │ ├── FormGrid.md │ │ │ │ ├── FormGrid.zh-CN.md │ │ │ │ ├── FormItem.md │ │ │ │ ├── FormItem.zh-CN.md │ │ │ │ ├── FormLayout.md │ │ │ │ ├── FormLayout.zh-CN.md │ │ │ │ ├── FormStep.md │ │ │ │ ├── FormStep.zh-CN.md │ │ │ │ ├── FormTab.md │ │ │ │ ├── FormTab.zh-CN.md │ │ │ │ ├── index.md │ │ │ │ ├── index.zh-CN.md │ │ │ │ ├── Input.md │ │ │ │ ├── Input.zh-CN.md │ │ │ │ ├── NumberPicker.md │ │ │ │ ├── NumberPicker.zh-CN.md │ │ │ │ ├── Password.md │ │ │ │ ├── Password.zh-CN.md │ │ │ │ ├── PreviewText.md │ │ │ │ ├── PreviewText.zh-CN.md │ │ │ │ ├── Radio.md │ │ │ │ ├── Radio.zh-CN.md │ │ │ │ ├── Reset.md │ │ │ │ ├── Reset.zh-CN.md │ │ │ │ ├── Select.md │ │ │ │ ├── Select.zh-CN.md │ │ │ │ ├── SelectTable.md │ │ │ │ ├── SelectTable.zh-CN.md │ │ │ │ ├── Space.md │ │ │ │ ├── Space.zh-CN.md │ │ │ │ ├── Submit.md │ │ │ │ ├── Submit.zh-CN.md │ │ │ │ ├── Switch.md │ │ │ │ ├── Switch.zh-CN.md │ │ │ │ ├── TimePicker.md │ │ │ │ ├── TimePicker.zh-CN.md │ │ │ │ ├── Transfer.md │ │ │ │ ├── Transfer.zh-CN.md │ │ │ │ ├── TreeSelect.md │ │ │ │ ├── TreeSelect.zh-CN.md │ │ │ │ ├── Upload.md │ │ │ │ └── Upload.zh-CN.md │ │ │ ├── index.md │ │ │ └── index.zh-CN.md │ │ ├── LICENSE.md │ │ ├── package.json │ │ ├── README.md │ │ ├── rollup.config.js │ │ ├── src │ │ │ ├── __builtins__ │ │ │ │ ├── hooks │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── useClickAway.ts │ │ │ │ │ └── usePrefixCls.ts │ │ │ │ ├── index.ts │ │ │ │ ├── loading.ts │ │ │ │ ├── moment.ts │ │ │ │ ├── pickDataProps.ts │ │ │ │ ├── portal.tsx │ │ │ │ ├── render.ts │ │ │ │ └── sort.tsx │ │ │ ├── array-base │ │ │ │ ├── index.tsx │ │ │ │ ├── style.less │ │ │ │ └── style.ts │ │ │ ├── array-cards │ │ │ │ ├── index.tsx │ │ │ │ ├── style.less │ │ │ │ └── style.ts │ │ │ ├── array-collapse │ │ │ │ ├── index.tsx │ │ │ │ ├── style.less │ │ │ │ └── style.ts │ │ │ ├── array-items │ │ │ │ ├── index.tsx │ │ │ │ ├── style.less │ │ │ │ └── style.ts │ │ │ ├── array-table │ │ │ │ ├── index.tsx │ │ │ │ ├── style.less │ │ │ │ └── style.ts │ │ │ ├── array-tabs │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── cascader │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── checkbox │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── date-picker │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── editable │ │ │ │ ├── index.tsx │ │ │ │ ├── style.less │ │ │ │ └── style.ts │ │ │ ├── form │ │ │ │ ├── index.tsx │ │ │ │ ├── style.less │ │ │ │ └── style.ts │ │ │ ├── form-button-group │ │ │ │ ├── index.tsx │ │ │ │ ├── style.less │ │ │ │ └── style.ts │ │ │ ├── form-collapse │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── form-dialog │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── form-drawer │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── form-grid │ │ │ │ ├── index.tsx │ │ │ │ ├── style.less │ │ │ │ └── style.ts │ │ │ ├── form-item │ │ │ │ ├── animation.less │ │ │ │ ├── grid.less │ │ │ │ ├── index.tsx │ │ │ │ ├── style.less │ │ │ │ └── style.ts │ │ │ ├── form-layout │ │ │ │ ├── index.tsx │ │ │ │ ├── style.less │ │ │ │ ├── style.ts │ │ │ │ └── useResponsiveFormLayout.ts │ │ │ ├── form-step │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── form-tab │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── index.ts │ │ │ ├── input │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── number-picker │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── password │ │ │ │ ├── index.tsx │ │ │ │ ├── PasswordStrength.tsx │ │ │ │ └── style.ts │ │ │ ├── preview-text │ │ │ │ ├── index.tsx │ │ │ │ ├── style.less │ │ │ │ └── style.ts │ │ │ ├── radio │ │ │ │ ├── index.tsx │ │ │ │ ├── style.less │ │ │ │ └── style.ts │ │ │ ├── reset │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── select │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── select-table │ │ │ │ ├── index.tsx │ │ │ │ ├── style.less │ │ │ │ ├── style.ts │ │ │ │ ├── useCheckSlackly.tsx │ │ │ │ ├── useFilterOptions.tsx │ │ │ │ ├── useFlatOptions.tsx │ │ │ │ ├── useSize.tsx │ │ │ │ ├── useTitleAddon.tsx │ │ │ │ └── utils.ts │ │ │ ├── space │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── style.less │ │ │ ├── style.ts │ │ │ ├── submit │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── switch │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── time-picker │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── transfer │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── tree-select │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ └── upload │ │ │ ├── index.tsx │ │ │ ├── placeholder.ts │ │ │ └── style.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── benchmark │ │ ├── .npmignore │ │ ├── .umirc.js │ │ ├── LICENSE.md │ │ ├── package.json │ │ ├── README.md │ │ ├── src │ │ │ └── index.tsx │ │ ├── template.ejs │ │ ├── tsconfig.build.json │ │ ├── tsconfig.json │ │ ├── webpack.base.ts │ │ ├── webpack.dev.ts │ │ └── webpack.prod.ts │ ├── core │ │ ├── .npmignore │ │ ├── .umirc.js │ │ ├── docs │ │ │ ├── api │ │ │ │ ├── entry │ │ │ │ │ ├── ActionResponse.less │ │ │ │ │ ├── ActionResponse.tsx │ │ │ │ │ ├── createForm.md │ │ │ │ │ ├── createForm.zh-CN.md │ │ │ │ │ ├── FieldEffectHooks.md │ │ │ │ │ ├── FieldEffectHooks.zh-CN.md │ │ │ │ │ ├── FormChecker.md │ │ │ │ │ ├── FormChecker.zh-CN.md │ │ │ │ │ ├── FormEffectHooks.md │ │ │ │ │ ├── FormEffectHooks.zh-CN.md │ │ │ │ │ ├── FormHooksAPI.md │ │ │ │ │ ├── FormHooksAPI.zh-CN.md │ │ │ │ │ ├── FormPath.md │ │ │ │ │ ├── FormPath.zh-CN.md │ │ │ │ │ ├── FormValidatorRegistry.md │ │ │ │ │ └── FormValidatorRegistry.zh-CN.md │ │ │ │ └── models │ │ │ │ ├── ArrayField.md │ │ │ │ ├── ArrayField.zh-CN.md │ │ │ │ ├── Field.md │ │ │ │ ├── Field.zh-CN.md │ │ │ │ ├── Form.md │ │ │ │ ├── Form.zh-CN.md │ │ │ │ ├── ObjectField.md │ │ │ │ ├── ObjectField.zh-CN.md │ │ │ │ ├── Query.md │ │ │ │ ├── Query.zh-CN.md │ │ │ │ ├── VoidField.md │ │ │ │ └── VoidField.zh-CN.md │ │ │ ├── guide │ │ │ │ ├── architecture.md │ │ │ │ ├── architecture.zh-CN.md │ │ │ │ ├── field.md │ │ │ │ ├── field.zh-CN.md │ │ │ │ ├── form.md │ │ │ │ ├── form.zh-CN.md │ │ │ │ ├── index.md │ │ │ │ ├── index.zh-CN.md │ │ │ │ ├── mvvm.md │ │ │ │ ├── mvvm.zh-CN.md │ │ │ │ ├── values.md │ │ │ │ └── values.zh-CN.md │ │ │ ├── index.md │ │ │ └── index.zh-CN.md │ │ ├── LICENSE.md │ │ ├── package.json │ │ ├── README.md │ │ ├── rollup.config.js │ │ ├── src │ │ │ ├── __tests__ │ │ │ │ ├── array.spec.ts │ │ │ │ ├── effects.spec.ts │ │ │ │ ├── externals.spec.ts │ │ │ │ ├── field.spec.ts │ │ │ │ ├── form.spec.ts │ │ │ │ ├── graph.spec.ts │ │ │ │ ├── heart.spec.ts │ │ │ │ ├── internals.spec.ts │ │ │ │ ├── lifecycle.spec.ts │ │ │ │ ├── object.spec.ts │ │ │ │ ├── shared.ts │ │ │ │ └── void.spec.ts │ │ │ ├── effects │ │ │ │ ├── index.ts │ │ │ │ ├── onFieldEffects.ts │ │ │ │ └── onFormEffects.ts │ │ │ ├── global.d.ts │ │ │ ├── index.ts │ │ │ ├── models │ │ │ │ ├── ArrayField.ts │ │ │ │ ├── BaseField.ts │ │ │ │ ├── Field.ts │ │ │ │ ├── Form.ts │ │ │ │ ├── Graph.ts │ │ │ │ ├── Heart.ts │ │ │ │ ├── index.ts │ │ │ │ ├── LifeCycle.ts │ │ │ │ ├── ObjectField.ts │ │ │ │ ├── Query.ts │ │ │ │ ├── types.ts │ │ │ │ └── VoidField.ts │ │ │ ├── shared │ │ │ │ ├── checkers.ts │ │ │ │ ├── constants.ts │ │ │ │ ├── effective.ts │ │ │ │ ├── externals.ts │ │ │ │ └── internals.ts │ │ │ └── types.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── element │ │ ├── .npmignore │ │ ├── build-style.ts │ │ ├── create-style.ts │ │ ├── docs │ │ │ ├── .vuepress │ │ │ │ ├── components │ │ │ │ │ ├── createCodeSandBox.js │ │ │ │ │ ├── dumi-previewer.vue │ │ │ │ │ └── highlight.js │ │ │ │ ├── config.js │ │ │ │ ├── enhanceApp.js │ │ │ │ ├── styles │ │ │ │ │ └── index.styl │ │ │ │ └── util.js │ │ │ ├── demos │ │ │ │ ├── guide │ │ │ │ │ ├── array-cards │ │ │ │ │ │ ├── effects-json-schema.vue │ │ │ │ │ │ ├── effects-markup-schema.vue │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ └── markup-schema.vue │ │ │ │ │ ├── array-collapse │ │ │ │ │ │ ├── effects-json-schema.vue │ │ │ │ │ │ ├── effects-markup-schema.vue │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ └── markup-schema.vue │ │ │ │ │ ├── array-items │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ └── markup-schema.vue │ │ │ │ │ ├── array-table │ │ │ │ │ │ ├── effects-json-schema.vue │ │ │ │ │ │ ├── effects-markup-schema.vue │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ └── markup-schema.vue │ │ │ │ │ ├── array-tabs │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ └── markup-schema.vue │ │ │ │ │ ├── cascader │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── checkbox │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── date-picker │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── editable │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── form-button-group.vue │ │ │ │ │ ├── form-collapse │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ └── markup-schema.vue │ │ │ │ │ ├── form-dialog │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── form-drawer │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── form-grid │ │ │ │ │ │ ├── form.vue │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── native.vue │ │ │ │ │ ├── form-item │ │ │ │ │ │ ├── bordered-none.vue │ │ │ │ │ │ ├── common.vue │ │ │ │ │ │ ├── feedback.vue │ │ │ │ │ │ ├── inset.vue │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ ├── size.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── form-layout │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── form-step │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ └── markup-schema.vue │ │ │ │ │ ├── form-tab │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ └── markup-schema.vue │ │ │ │ │ ├── form.vue │ │ │ │ │ ├── input │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── input-number │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── password │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── preview-text │ │ │ │ │ │ ├── base.vue │ │ │ │ │ │ └── extend.vue │ │ │ │ │ ├── radio │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── reset │ │ │ │ │ │ ├── base.vue │ │ │ │ │ │ ├── force.vue │ │ │ │ │ │ └── validate.vue │ │ │ │ │ ├── select │ │ │ │ │ │ ├── json-schema-async.vue │ │ │ │ │ │ ├── json-schema-sync.vue │ │ │ │ │ │ ├── markup-schema-async-search.vue │ │ │ │ │ │ ├── markup-schema-async.vue │ │ │ │ │ │ ├── markup-schema-sync.vue │ │ │ │ │ │ ├── template-async.vue │ │ │ │ │ │ └── template-sync.vue │ │ │ │ │ ├── space │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── submit │ │ │ │ │ │ ├── base.vue │ │ │ │ │ │ └── loading.vue │ │ │ │ │ ├── switch │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── time-picker │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ ├── transfer │ │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ │ └── template.vue │ │ │ │ │ └── upload │ │ │ │ │ ├── json-schema.vue │ │ │ │ │ ├── markup-schema.vue │ │ │ │ │ └── template.vue │ │ │ │ └── index.vue │ │ │ ├── guide │ │ │ │ ├── array-cards.md │ │ │ │ ├── array-collapse.md │ │ │ │ ├── array-items.md │ │ │ │ ├── array-table.md │ │ │ │ ├── array-tabs.md │ │ │ │ ├── cascader.md │ │ │ │ ├── checkbox.md │ │ │ │ ├── date-picker.md │ │ │ │ ├── editable.md │ │ │ │ ├── form-button-group.md │ │ │ │ ├── form-collapse.md │ │ │ │ ├── form-dialog.md │ │ │ │ ├── form-drawer.md │ │ │ │ ├── form-grid.md │ │ │ │ ├── form-item.md │ │ │ │ ├── form-layout.md │ │ │ │ ├── form-step.md │ │ │ │ ├── form-tab.md │ │ │ │ ├── form.md │ │ │ │ ├── index.md │ │ │ │ ├── input-number.md │ │ │ │ ├── input.md │ │ │ │ ├── password.md │ │ │ │ ├── preview-text.md │ │ │ │ ├── radio.md │ │ │ │ ├── reset.md │ │ │ │ ├── select.md │ │ │ │ ├── space.md │ │ │ │ ├── submit.md │ │ │ │ ├── switch.md │ │ │ │ ├── time-picker.md │ │ │ │ ├── transfer.md │ │ │ │ └── upload.md │ │ │ └── README.md │ │ ├── package.json │ │ ├── README.md │ │ ├── rollup.config.js │ │ ├── src │ │ │ ├── __builtins__ │ │ │ │ ├── configs │ │ │ │ │ └── index.ts │ │ │ │ ├── index.ts │ │ │ │ ├── shared │ │ │ │ │ ├── create-context.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── loading.ts │ │ │ │ │ ├── portal.ts │ │ │ │ │ ├── resolve-component.ts │ │ │ │ │ ├── transform-component.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ └── utils.ts │ │ │ │ └── styles │ │ │ │ └── common.scss │ │ │ ├── array-base │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ └── style.ts │ │ │ ├── array-cards │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ └── style.ts │ │ │ ├── array-collapse │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ └── style.ts │ │ │ ├── array-items │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ └── style.ts │ │ │ ├── array-table │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ └── style.ts │ │ │ ├── array-tabs │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ └── style.ts │ │ │ ├── cascader │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── checkbox │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── date-picker │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── editable │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ └── style.ts │ │ │ ├── el-form │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── el-form-item │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── form │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ └── style.ts │ │ │ ├── form-button-group │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ └── style.ts │ │ │ ├── form-collapse │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ └── style.ts │ │ │ ├── form-dialog │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── form-drawer │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ └── style.ts │ │ │ ├── form-grid │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ └── style.ts │ │ │ ├── form-item │ │ │ │ ├── animation.scss │ │ │ │ ├── grid.scss │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ ├── style.ts │ │ │ │ └── var.scss │ │ │ ├── form-layout │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ ├── style.ts │ │ │ │ └── useResponsiveFormLayout.ts │ │ │ ├── form-step │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── form-tab │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ └── style.ts │ │ │ ├── index.ts │ │ │ ├── input │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── input-number │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── password │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── preview-text │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── radio │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── reset │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── select │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── space │ │ │ │ ├── index.ts │ │ │ │ ├── style.scss │ │ │ │ └── style.ts │ │ │ ├── style.ts │ │ │ ├── submit │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── switch │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── time-picker │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ ├── transfer │ │ │ │ ├── index.ts │ │ │ │ └── style.ts │ │ │ └── upload │ │ │ ├── index.ts │ │ │ └── style.ts │ │ ├── transformer.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── grid │ │ ├── .npmignore │ │ ├── LICENSE.md │ │ ├── package.json │ │ ├── README.md │ │ ├── rollup.config.js │ │ ├── src │ │ │ ├── index.ts │ │ │ └── observer.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── json-schema │ │ ├── .npmignore │ │ ├── LICENSE.md │ │ ├── package.json │ │ ├── README.md │ │ ├── rollup.config.js │ │ ├── src │ │ │ ├── __tests__ │ │ │ │ ├── __snapshots__ │ │ │ │ │ └── schema.spec.ts.snap │ │ │ │ ├── compiler.spec.ts │ │ │ │ ├── patches.spec.ts │ │ │ │ ├── schema.spec.ts │ │ │ │ ├── server-validate.spec.ts │ │ │ │ ├── shared.spec.ts │ │ │ │ ├── transformer.spec.ts │ │ │ │ └── traverse.spec.ts │ │ │ ├── compiler.ts │ │ │ ├── global.d.ts │ │ │ ├── index.ts │ │ │ ├── patches.ts │ │ │ ├── polyfills │ │ │ │ ├── index.ts │ │ │ │ └── SPECIFICATION_1_0.ts │ │ │ ├── schema.ts │ │ │ ├── shared.ts │ │ │ ├── transformer.ts │ │ │ └── types.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── next │ │ ├── __tests__ │ │ │ ├── moment.spec.ts │ │ │ └── sideEffects.spec.ts │ │ ├── .npmignore │ │ ├── .umirc.js │ │ ├── build-style.ts │ │ ├── create-style.ts │ │ ├── docs │ │ │ ├── components │ │ │ │ ├── ArrayCards.md │ │ │ │ ├── ArrayCards.zh-CN.md │ │ │ │ ├── ArrayCollapse.md │ │ │ │ ├── ArrayCollapse.zh-CN.md │ │ │ │ ├── ArrayItems.md │ │ │ │ ├── ArrayItems.zh-CN.md │ │ │ │ ├── ArrayTable.md │ │ │ │ ├── ArrayTable.zh-CN.md │ │ │ │ ├── Cascader.md │ │ │ │ ├── Cascader.zh-CN.md │ │ │ │ ├── Checkbox.md │ │ │ │ ├── Checkbox.zh-CN.md │ │ │ │ ├── DatePicker.md │ │ │ │ ├── DatePicker.zh-CN.md │ │ │ │ ├── DatePicker2.md │ │ │ │ ├── DatePicker2.zh-CN.md │ │ │ │ ├── Editable.md │ │ │ │ ├── Editable.zh-CN.md │ │ │ │ ├── Form.md │ │ │ │ ├── Form.zh-CN.md │ │ │ │ ├── FormButtonGroup.md │ │ │ │ ├── FormButtonGroup.zh-CN.md │ │ │ │ ├── FormCollapse.md │ │ │ │ ├── FormCollapse.zh-CN.md │ │ │ │ ├── FormDialog.md │ │ │ │ ├── FormDialog.zh-CN.md │ │ │ │ ├── FormDrawer.md │ │ │ │ ├── FormDrawer.zh-CN.md │ │ │ │ ├── FormGrid.md │ │ │ │ ├── FormGrid.zh-CN.md │ │ │ │ ├── FormItem.md │ │ │ │ ├── FormItem.zh-CN.md │ │ │ │ ├── FormLayout.md │ │ │ │ ├── FormLayout.zh-CN.md │ │ │ │ ├── FormStep.md │ │ │ │ ├── FormStep.zh-CN.md │ │ │ │ ├── FormTab.md │ │ │ │ ├── FormTab.zh-CN.md │ │ │ │ ├── index.md │ │ │ │ ├── index.zh-CN.md │ │ │ │ ├── Input.md │ │ │ │ ├── Input.zh-CN.md │ │ │ │ ├── NumberPicker.md │ │ │ │ ├── NumberPicker.zh-CN.md │ │ │ │ ├── Password.md │ │ │ │ ├── Password.zh-CN.md │ │ │ │ ├── PreviewText.md │ │ │ │ ├── PreviewText.zh-CN.md │ │ │ │ ├── Radio.md │ │ │ │ ├── Radio.zh-CN.md │ │ │ │ ├── Reset.md │ │ │ │ ├── Reset.zh-CN.md │ │ │ │ ├── Select.md │ │ │ │ ├── Select.zh-CN.md │ │ │ │ ├── SelectTable.md │ │ │ │ ├── SelectTable.zh-CN.md │ │ │ │ ├── Space.md │ │ │ │ ├── Space.zh-CN.md │ │ │ │ ├── Submit.md │ │ │ │ ├── Submit.zh-CN.md │ │ │ │ ├── Switch.md │ │ │ │ ├── Switch.zh-CN.md │ │ │ │ ├── TimePicker.md │ │ │ │ ├── TimePicker.zh-CN.md │ │ │ │ ├── TimePicker2.md │ │ │ │ ├── TimePicker2.zh-CN.md │ │ │ │ ├── Transfer.md │ │ │ │ ├── Transfer.zh-CN.md │ │ │ │ ├── TreeSelect.md │ │ │ │ ├── TreeSelect.zh-CN.md │ │ │ │ ├── Upload.md │ │ │ │ └── Upload.zh-CN.md │ │ │ ├── index.md │ │ │ └── index.zh-CN.md │ │ ├── LESENCE.md │ │ ├── package.json │ │ ├── README.md │ │ ├── rollup.config.js │ │ ├── src │ │ │ ├── __builtins__ │ │ │ │ ├── empty.tsx │ │ │ │ ├── hooks │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── useClickAway.ts │ │ │ │ │ └── usePrefixCls.ts │ │ │ │ ├── icons.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── loading.ts │ │ │ │ ├── mapSize.ts │ │ │ │ ├── mapStatus.ts │ │ │ │ ├── moment.ts │ │ │ │ ├── pickDataProps.ts │ │ │ │ ├── portal.tsx │ │ │ │ ├── render.ts │ │ │ │ └── toArray.ts │ │ │ ├── array-base │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ └── style.ts │ │ │ ├── array-cards │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ └── style.ts │ │ │ ├── array-collapse │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ └── style.ts │ │ │ ├── array-items │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ └── style.ts │ │ │ ├── array-table │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ └── style.ts │ │ │ ├── cascader │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── checkbox │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── date-picker │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── date-picker2 │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ └── style.ts │ │ │ ├── editable │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ └── style.ts │ │ │ ├── form │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ └── style.ts │ │ │ ├── form-button-group │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ └── style.ts │ │ │ ├── form-collapse │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── form-dialog │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── form-drawer │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── form-grid │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ └── style.ts │ │ │ ├── form-item │ │ │ │ ├── animation.scss │ │ │ │ ├── grid.scss │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ ├── scss │ │ │ │ │ └── variable.scss │ │ │ │ └── style.ts │ │ │ ├── form-layout │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ ├── style.ts │ │ │ │ └── useResponsiveFormLayout.ts │ │ │ ├── form-step │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── form-tab │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── index.ts │ │ │ ├── input │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── main.scss │ │ │ ├── number-picker │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── password │ │ │ │ ├── index.tsx │ │ │ │ ├── PasswordStrength.tsx │ │ │ │ └── style.ts │ │ │ ├── preview-text │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ └── style.ts │ │ │ ├── radio │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── reset │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── select │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── select-table │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ ├── style.ts │ │ │ │ ├── useCheckSlackly.tsx │ │ │ │ ├── useFilterOptions.tsx │ │ │ │ ├── useFlatOptions.tsx │ │ │ │ ├── useSize.tsx │ │ │ │ ├── useTitleAddon.tsx │ │ │ │ └── utils.ts │ │ │ ├── space │ │ │ │ ├── index.tsx │ │ │ │ ├── main.scss │ │ │ │ └── style.ts │ │ │ ├── style.ts │ │ │ ├── submit │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── switch │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── time-picker │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── time-picker2 │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── transfer │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── tree-select │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ └── upload │ │ │ ├── index.tsx │ │ │ ├── main.scss │ │ │ ├── placeholder.ts │ │ │ └── style.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── path │ │ ├── .npmignore │ │ ├── benchmark.ts │ │ ├── LICENSE.md │ │ ├── package.json │ │ ├── README.md │ │ ├── rollup.config.js │ │ ├── src │ │ │ ├── __tests__ │ │ │ │ ├── accessor.spec.ts │ │ │ │ ├── basic.spec.ts │ │ │ │ ├── match.spec.ts │ │ │ │ ├── parser.spec.ts │ │ │ │ └── share.spec.ts │ │ │ ├── contexts.ts │ │ │ ├── destructor.ts │ │ │ ├── index.ts │ │ │ ├── matcher.ts │ │ │ ├── parser.ts │ │ │ ├── shared.ts │ │ │ ├── tokenizer.ts │ │ │ ├── tokens.ts │ │ │ └── types.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── react │ │ ├── .npmignore │ │ ├── .umirc.js │ │ ├── docs │ │ │ ├── api │ │ │ │ ├── components │ │ │ │ │ ├── ArrayField.md │ │ │ │ │ ├── ArrayField.zh-CN.md │ │ │ │ │ ├── ExpressionScope.md │ │ │ │ │ ├── ExpressionScope.zh-CN.md │ │ │ │ │ ├── Field.md │ │ │ │ │ ├── Field.zh-CN.md │ │ │ │ │ ├── FormConsumer.md │ │ │ │ │ ├── FormConsumer.zh-CN.md │ │ │ │ │ ├── FormProvider.md │ │ │ │ │ ├── FormProvider.zh-CN.md │ │ │ │ │ ├── ObjectField.md │ │ │ │ │ ├── ObjectField.zh-CN.md │ │ │ │ │ ├── RecordScope.md │ │ │ │ │ ├── RecordScope.zh-CN.md │ │ │ │ │ ├── RecordsScope.md │ │ │ │ │ ├── RecordsScope.zh-CN.md │ │ │ │ │ ├── RecursionField.md │ │ │ │ │ ├── RecursionField.zh-CN.md │ │ │ │ │ ├── SchemaField.md │ │ │ │ │ ├── SchemaField.zh-CN.md │ │ │ │ │ ├── VoidField.md │ │ │ │ │ └── VoidField.zh-CN.md │ │ │ │ ├── hooks │ │ │ │ │ ├── useExpressionScope.md │ │ │ │ │ ├── useExpressionScope.zh-CN.md │ │ │ │ │ ├── useField.md │ │ │ │ │ ├── useField.zh-CN.md │ │ │ │ │ ├── useFieldSchema.md │ │ │ │ │ ├── useFieldSchema.zh-CN.md │ │ │ │ │ ├── useForm.md │ │ │ │ │ ├── useForm.zh-CN.md │ │ │ │ │ ├── useFormEffects.md │ │ │ │ │ ├── useFormEffects.zh-CN.md │ │ │ │ │ ├── useParentForm.md │ │ │ │ │ └── useParentForm.zh-CN.md │ │ │ │ └── shared │ │ │ │ ├── connect.md │ │ │ │ ├── connect.zh-CN.md │ │ │ │ ├── context.md │ │ │ │ ├── context.zh-CN.md │ │ │ │ ├── mapProps.md │ │ │ │ ├── mapProps.zh-CN.md │ │ │ │ ├── mapReadPretty.md │ │ │ │ ├── mapReadPretty.zh-CN.md │ │ │ │ ├── observer.md │ │ │ │ ├── observer.zh-CN.md │ │ │ │ ├── Schema.md │ │ │ │ └── Schema.zh-CN.md │ │ │ ├── guide │ │ │ │ ├── architecture.md │ │ │ │ ├── architecture.zh-CN.md │ │ │ │ ├── concept.md │ │ │ │ ├── concept.zh-CN.md │ │ │ │ ├── index.md │ │ │ │ └── index.zh-CN.md │ │ │ ├── index.md │ │ │ └── index.zh-CN.md │ │ ├── LICENSE.md │ │ ├── package.json │ │ ├── README.md │ │ ├── rollup.config.js │ │ ├── src │ │ │ ├── __tests__ │ │ │ │ ├── expression.spec.tsx │ │ │ │ ├── field.spec.tsx │ │ │ │ ├── form.spec.tsx │ │ │ │ ├── schema.json.spec.tsx │ │ │ │ ├── schema.markup.spec.tsx │ │ │ │ └── shared.tsx │ │ │ ├── components │ │ │ │ ├── ArrayField.tsx │ │ │ │ ├── ExpressionScope.tsx │ │ │ │ ├── Field.tsx │ │ │ │ ├── FormConsumer.tsx │ │ │ │ ├── FormProvider.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── ObjectField.tsx │ │ │ │ ├── ReactiveField.tsx │ │ │ │ ├── RecordScope.tsx │ │ │ │ ├── RecordsScope.tsx │ │ │ │ ├── RecursionField.tsx │ │ │ │ ├── SchemaField.tsx │ │ │ │ └── VoidField.tsx │ │ │ ├── global.d.ts │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ ├── useAttach.ts │ │ │ │ ├── useExpressionScope.ts │ │ │ │ ├── useField.ts │ │ │ │ ├── useFieldSchema.ts │ │ │ │ ├── useForm.ts │ │ │ │ ├── useFormEffects.ts │ │ │ │ └── useParentForm.ts │ │ │ ├── index.ts │ │ │ ├── shared │ │ │ │ ├── connect.ts │ │ │ │ ├── context.ts │ │ │ │ ├── index.ts │ │ │ │ └── render.ts │ │ │ └── types.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── reactive │ │ ├── .npmignore │ │ ├── .umirc.js │ │ ├── benchmark.ts │ │ ├── docs │ │ │ ├── api │ │ │ │ ├── action.md │ │ │ │ ├── action.zh-CN.md │ │ │ │ ├── autorun.md │ │ │ │ ├── autorun.zh-CN.md │ │ │ │ ├── batch.md │ │ │ │ ├── batch.zh-CN.md │ │ │ │ ├── define.md │ │ │ │ ├── define.zh-CN.md │ │ │ │ ├── hasCollected.md │ │ │ │ ├── hasCollected.zh-CN.md │ │ │ │ ├── markObservable.md │ │ │ │ ├── markObservable.zh-CN.md │ │ │ │ ├── markRaw.md │ │ │ │ ├── markRaw.zh-CN.md │ │ │ │ ├── model.md │ │ │ │ ├── model.zh-CN.md │ │ │ │ ├── observable.md │ │ │ │ ├── observable.zh-CN.md │ │ │ │ ├── observe.md │ │ │ │ ├── observe.zh-CN.md │ │ │ │ ├── raw.md │ │ │ │ ├── raw.zh-CN.md │ │ │ │ ├── react │ │ │ │ │ ├── observer.md │ │ │ │ │ └── observer.zh-CN.md │ │ │ │ ├── reaction.md │ │ │ │ ├── reaction.zh-CN.md │ │ │ │ ├── toJS.md │ │ │ │ ├── toJS.zh-CN.md │ │ │ │ ├── tracker.md │ │ │ │ ├── tracker.zh-CN.md │ │ │ │ ├── typeChecker.md │ │ │ │ ├── typeChecker.zh-CN.md │ │ │ │ ├── untracked.md │ │ │ │ ├── untracked.zh-CN.md │ │ │ │ └── vue │ │ │ │ ├── observer.md │ │ │ │ └── observer.zh-CN.md │ │ │ ├── guide │ │ │ │ ├── best-practice.md │ │ │ │ ├── best-practice.zh-CN.md │ │ │ │ ├── concept.md │ │ │ │ ├── concept.zh-CN.md │ │ │ │ ├── index.md │ │ │ │ └── index.zh-CN.md │ │ │ ├── index.md │ │ │ └── index.zh-CN.md │ │ ├── LICENSE.md │ │ ├── package.json │ │ ├── README.md │ │ ├── rollup.config.js │ │ ├── src │ │ │ ├── __tests__ │ │ │ │ ├── action.spec.ts │ │ │ │ ├── annotations.spec.ts │ │ │ │ ├── array.spec.ts │ │ │ │ ├── autorun.spec.ts │ │ │ │ ├── batch.spec.ts │ │ │ │ ├── collections-map.spec.ts │ │ │ │ ├── collections-set.spec.ts │ │ │ │ ├── collections-weakmap.spec.ts │ │ │ │ ├── collections-weakset.spec.ts │ │ │ │ ├── define.spec.ts │ │ │ │ ├── externals.spec.ts │ │ │ │ ├── hasCollected.spec.ts │ │ │ │ ├── observable.spec.ts │ │ │ │ ├── observe.spec.ts │ │ │ │ ├── tracker.spec.ts │ │ │ │ └── untracked.spec.ts │ │ │ ├── action.ts │ │ │ ├── annotations │ │ │ │ ├── box.ts │ │ │ │ ├── computed.ts │ │ │ │ ├── index.ts │ │ │ │ ├── observable.ts │ │ │ │ ├── ref.ts │ │ │ │ └── shallow.ts │ │ │ ├── array.ts │ │ │ ├── autorun.ts │ │ │ ├── batch.ts │ │ │ ├── checkers.ts │ │ │ ├── environment.ts │ │ │ ├── externals.ts │ │ │ ├── global.d.ts │ │ │ ├── handlers.ts │ │ │ ├── index.ts │ │ │ ├── internals.ts │ │ │ ├── model.ts │ │ │ ├── observable.ts │ │ │ ├── observe.ts │ │ │ ├── reaction.ts │ │ │ ├── tracker.ts │ │ │ ├── tree.ts │ │ │ ├── types.ts │ │ │ └── untracked.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── reactive-react │ │ ├── .npmignore │ │ ├── .umirc.js │ │ ├── LICENSE.md │ │ ├── package.json │ │ ├── README.md │ │ ├── rollup.config.js │ │ ├── src │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ ├── useCompatEffect.ts │ │ │ │ ├── useCompatFactory.ts │ │ │ │ ├── useDidUpdate.ts │ │ │ │ ├── useForceUpdate.ts │ │ │ │ ├── useLayoutEffect.ts │ │ │ │ └── useObserver.ts │ │ │ ├── index.ts │ │ │ ├── observer.ts │ │ │ ├── shared │ │ │ │ ├── gc.ts │ │ │ │ ├── global.ts │ │ │ │ ├── immediate.ts │ │ │ │ └── index.ts │ │ │ └── types.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── reactive-test-cases-for-react18 │ │ ├── .npmignore │ │ ├── .umirc.js │ │ ├── LICENSE.md │ │ ├── package.json │ │ ├── README.md │ │ ├── src │ │ │ ├── index.js │ │ │ └── MySlowList.js │ │ ├── template.ejs │ │ ├── tsconfig.build.json │ │ ├── tsconfig.json │ │ ├── webpack.base.ts │ │ ├── webpack.dev.ts │ │ └── webpack.prod.ts │ ├── reactive-vue │ │ ├── .npmignore │ │ ├── LICENSE.md │ │ ├── package.json │ │ ├── README.md │ │ ├── rollup.config.js │ │ ├── src │ │ │ ├── __tests__ │ │ │ │ └── observer.spec.ts │ │ │ ├── hooks │ │ │ │ ├── index.ts │ │ │ │ └── useObserver.ts │ │ │ ├── index.ts │ │ │ ├── observer │ │ │ │ ├── collectData.ts │ │ │ │ ├── index.ts │ │ │ │ ├── observerInVue2.ts │ │ │ │ └── observerInVue3.ts │ │ │ └── types.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── shared │ │ ├── .npmignore │ │ ├── LICENSE.md │ │ ├── package.json │ │ ├── README.md │ │ ├── rollup.config.js │ │ ├── src │ │ │ ├── __tests__ │ │ │ │ └── index.spec.ts │ │ │ ├── array.ts │ │ │ ├── case.ts │ │ │ ├── checkers.ts │ │ │ ├── clone.ts │ │ │ ├── compare.ts │ │ │ ├── defaults.ts │ │ │ ├── deprecate.ts │ │ │ ├── global.ts │ │ │ ├── index.ts │ │ │ ├── instanceof.ts │ │ │ ├── isEmpty.ts │ │ │ ├── merge.ts │ │ │ ├── middleware.ts │ │ │ ├── path.ts │ │ │ ├── string.ts │ │ │ ├── subscribable.ts │ │ │ └── uid.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ ├── validator │ │ ├── .npmignore │ │ ├── LICENSE.md │ │ ├── package.json │ │ ├── README.md │ │ ├── rollup.config.js │ │ ├── src │ │ │ ├── __tests__ │ │ │ │ ├── parser.spec.ts │ │ │ │ ├── registry.spec.ts │ │ │ │ └── validator.spec.ts │ │ │ ├── formats.ts │ │ │ ├── index.ts │ │ │ ├── locale.ts │ │ │ ├── parser.ts │ │ │ ├── registry.ts │ │ │ ├── rules.ts │ │ │ ├── template.ts │ │ │ ├── types.ts │ │ │ └── validator.ts │ │ ├── tsconfig.build.json │ │ └── tsconfig.json │ └── vue │ ├── .npmignore │ ├── bin │ │ ├── formily-vue-fix.js │ │ └── formily-vue-switch.js │ ├── docs │ │ ├── .vuepress │ │ │ ├── components │ │ │ │ ├── createCodeSandBox.js │ │ │ │ ├── dumi-previewer.vue │ │ │ │ └── highlight.js │ │ │ ├── config.js │ │ │ ├── enhanceApp.js │ │ │ └── styles │ │ │ └── index.styl │ │ ├── api │ │ │ ├── components │ │ │ │ ├── array-field.md │ │ │ │ ├── expression-scope.md │ │ │ │ ├── field.md │ │ │ │ ├── form-consumer.md │ │ │ │ ├── form-provider.md │ │ │ │ ├── object-field.md │ │ │ │ ├── recursion-field-with-component.md │ │ │ │ ├── recursion-field.md │ │ │ │ ├── schema-field-with-schema.md │ │ │ │ ├── schema-field.md │ │ │ │ └── void-field.md │ │ │ ├── hooks │ │ │ │ ├── use-field-schema.md │ │ │ │ ├── use-field.md │ │ │ │ ├── use-form-effects.md │ │ │ │ ├── use-form.md │ │ │ │ └── use-parent-form.md │ │ │ └── shared │ │ │ ├── connect.md │ │ │ ├── injections.md │ │ │ ├── map-props.md │ │ │ ├── map-read-pretty.md │ │ │ ├── observer.md │ │ │ └── schema.md │ │ ├── demos │ │ │ ├── api │ │ │ │ ├── components │ │ │ │ │ ├── array-field.vue │ │ │ │ │ ├── expression-scope.vue │ │ │ │ │ ├── field.vue │ │ │ │ │ ├── form-consumer.vue │ │ │ │ │ ├── form-provider.vue │ │ │ │ │ ├── object-field.vue │ │ │ │ │ ├── recursion-field-with-component.vue │ │ │ │ │ ├── recursion-field.vue │ │ │ │ │ ├── schema-field-with-schema.vue │ │ │ │ │ ├── schema-field.vue │ │ │ │ │ └── void-field.vue │ │ │ │ ├── hooks │ │ │ │ │ ├── use-field-schema.vue │ │ │ │ │ ├── use-field.vue │ │ │ │ │ ├── use-form-effects.vue │ │ │ │ │ ├── use-form.vue │ │ │ │ │ └── use-parent-form.vue │ │ │ │ └── shared │ │ │ │ ├── connect.vue │ │ │ │ ├── map-props.vue │ │ │ │ ├── map-read-pretty.vue │ │ │ │ └── observer.vue │ │ │ ├── index.vue │ │ │ └── questions │ │ │ ├── default-slot.vue │ │ │ ├── events.vue │ │ │ ├── named-slot.vue │ │ │ └── scoped-slot.vue │ │ ├── guide │ │ │ ├── architecture.md │ │ │ ├── concept.md │ │ │ └── README.md │ │ ├── questions │ │ │ └── README.md │ │ └── README.md │ ├── package.json │ ├── README.md │ ├── rollup.config.js │ ├── scripts │ │ ├── postinstall.js │ │ ├── switch-cli.js │ │ └── utils.js │ ├── src │ │ ├── __tests__ │ │ │ ├── expression.scope.spec.ts │ │ │ ├── field.spec.ts │ │ │ ├── form.spec.ts │ │ │ ├── schema.json.spec.ts │ │ │ ├── schema.markup.spec.ts │ │ │ ├── shared.spec.ts │ │ │ └── utils.spec.ts │ │ ├── components │ │ │ ├── ArrayField.ts │ │ │ ├── ExpressionScope.ts │ │ │ ├── Field.ts │ │ │ ├── FormConsumer.ts │ │ │ ├── FormProvider.ts │ │ │ ├── index.ts │ │ │ ├── ObjectField.ts │ │ │ ├── ReactiveField.ts │ │ │ ├── RecursionField.ts │ │ │ ├── SchemaField.ts │ │ │ └── VoidField.ts │ │ ├── global.d.ts │ │ ├── hooks │ │ │ ├── index.ts │ │ │ ├── useAttach.ts │ │ │ ├── useField.ts │ │ │ ├── useFieldSchema.ts │ │ │ ├── useForm.ts │ │ │ ├── useFormEffects.ts │ │ │ ├── useInjectionCleaner.ts │ │ │ └── useParentForm.ts │ │ ├── index.ts │ │ ├── shared │ │ │ ├── connect.ts │ │ │ ├── context.ts │ │ │ ├── createForm.ts │ │ │ ├── fragment.ts │ │ │ ├── h.ts │ │ │ └── index.ts │ │ ├── types │ │ │ └── index.ts │ │ ├── utils │ │ │ ├── formatVNodeData.ts │ │ │ ├── getFieldProps.ts │ │ │ ├── getRawComponent.ts │ │ │ └── resolveSchemaProps.ts │ │ └── vue2-components.ts │ ├── tsconfig.build.json │ ├── tsconfig.json │ └── tsconfig.types.json ├── README.md ├── README.zh-cn.md ├── scripts │ ├── build-style │ │ ├── buildAllStyles.ts │ │ ├── copy.ts │ │ ├── helper.ts │ │ └── index.ts │ └── rollup.base.js ├── tsconfig.build.json ├── tsconfig.jest.json ├── tsconfig.json └── yarn.lock ``` # Files -------------------------------------------------------------------------------- /packages/core/src/models/Query.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { FormPath, isFn, each, FormPathPattern } from '@formily/shared' 2 | import { buildDataPath } from '../shared/internals' 3 | import { GeneralField, IGeneralFieldState, IQueryProps } from '../types' 4 | import { Form } from './Form' 5 | 6 | const output = ( 7 | field: GeneralField, 8 | taker: (field: GeneralField, address: FormPath) => any 9 | ) => { 10 | if (!field) return 11 | if (isFn(taker)) { 12 | return taker(field, field.address) 13 | } 14 | return field 15 | } 16 | 17 | const takeMatchPattern = (form: Form, pattern: FormPath) => { 18 | const identifier = pattern.toString() 19 | const indexIdentifier = form.indexes[identifier] 20 | const absoluteField = form.fields[identifier] 21 | const indexField = form.fields[indexIdentifier] 22 | if (absoluteField) { 23 | return identifier 24 | } else if (indexField) { 25 | return indexIdentifier 26 | } 27 | } 28 | 29 | export class Query { 30 | private pattern: FormPath 31 | private addresses: string[] = [] 32 | private form: Form 33 | constructor(props: IQueryProps) { 34 | this.pattern = FormPath.parse(props.pattern, props.base) 35 | this.form = props.form 36 | if (!this.pattern.isMatchPattern) { 37 | const matched = takeMatchPattern( 38 | this.form, 39 | this.pattern.haveRelativePattern 40 | ? buildDataPath(props.form.fields, this.pattern) 41 | : this.pattern 42 | ) 43 | if (matched) { 44 | this.addresses = [matched] 45 | } 46 | } else { 47 | each(this.form.fields, (field, address) => { 48 | if (!field) { 49 | delete this.form.fields[address] 50 | return 51 | } 52 | if (field.match(this.pattern)) { 53 | this.addresses.push(address) 54 | } 55 | }) 56 | } 57 | } 58 | 59 | take(): GeneralField | undefined 60 | take<Result>( 61 | getter: (field: GeneralField, address: FormPath) => Result 62 | ): Result 63 | take(taker?: any): any { 64 | return output(this.form.fields[this.addresses[0]], taker) 65 | } 66 | 67 | map(): GeneralField[] 68 | map<Result>( 69 | iterator?: (field: GeneralField, address: FormPath) => Result 70 | ): Result[] 71 | map(iterator?: any): any { 72 | return this.addresses.map((address) => 73 | output(this.form.fields[address], iterator) 74 | ) 75 | } 76 | 77 | forEach<Result>( 78 | iterator: (field: GeneralField, address: FormPath) => Result 79 | ) { 80 | return this.addresses.forEach((address) => 81 | output(this.form.fields[address], iterator) 82 | ) 83 | } 84 | 85 | reduce<Result>( 86 | reducer: (value: Result, field: GeneralField, address: FormPath) => Result, 87 | initial?: Result 88 | ): Result { 89 | return this.addresses.reduce( 90 | (value, address) => 91 | output(this.form.fields[address], (field, address) => 92 | reducer(value, field, address) 93 | ), 94 | initial 95 | ) 96 | } 97 | 98 | get<K extends keyof IGeneralFieldState>(key: K): IGeneralFieldState[K] { 99 | const results: any = this.take() 100 | if (results) { 101 | return results[key] 102 | } 103 | } 104 | 105 | getIn(pattern?: FormPathPattern) { 106 | return FormPath.getIn(this.take(), pattern) 107 | } 108 | 109 | value() { 110 | return this.get('value') 111 | } 112 | 113 | initialValue() { 114 | return this.get('initialValue') 115 | } 116 | } 117 | ``` -------------------------------------------------------------------------------- /packages/antd/docs/components/Checkbox.zh-CN.md: -------------------------------------------------------------------------------- ```markdown 1 | # Checkbox 2 | 3 | > 复选框 4 | 5 | ## Markup Schema 案例 6 | 7 | ```tsx 8 | import React from 'react' 9 | import { Checkbox, FormItem, FormButtonGroup, Submit } from '@formily/antd' 10 | import { createForm } from '@formily/core' 11 | import { FormProvider, createSchemaField } from '@formily/react' 12 | 13 | const SchemaField = createSchemaField({ 14 | components: { 15 | Checkbox, 16 | FormItem, 17 | }, 18 | }) 19 | 20 | const form = createForm() 21 | 22 | export default () => ( 23 | <FormProvider form={form}> 24 | <SchemaField> 25 | <SchemaField.Boolean 26 | name="single" 27 | title="是否确认" 28 | x-decorator="FormItem" 29 | x-component="Checkbox" 30 | /> 31 | <SchemaField.String 32 | name="multiple" 33 | title="复选" 34 | enum={[ 35 | { 36 | label: '选项1', 37 | value: 1, 38 | }, 39 | { 40 | label: '选项2', 41 | value: 2, 42 | }, 43 | ]} 44 | x-decorator="FormItem" 45 | x-component="Checkbox.Group" 46 | /> 47 | </SchemaField> 48 | <FormButtonGroup> 49 | <Submit onSubmit={console.log}>提交</Submit> 50 | </FormButtonGroup> 51 | </FormProvider> 52 | ) 53 | ``` 54 | 55 | ## JSON Schema 案例 56 | 57 | ```tsx 58 | import React from 'react' 59 | import { Checkbox, FormItem, FormButtonGroup, Submit } from '@formily/antd' 60 | import { createForm } from '@formily/core' 61 | import { FormProvider, createSchemaField } from '@formily/react' 62 | 63 | const SchemaField = createSchemaField({ 64 | components: { 65 | Checkbox, 66 | FormItem, 67 | }, 68 | }) 69 | 70 | const form = createForm() 71 | 72 | const schema = { 73 | type: 'object', 74 | properties: { 75 | single: { 76 | type: 'boolean', 77 | title: '是否确认', 78 | 'x-decorator': 'FormItem', 79 | 'x-component': 'Checkbox', 80 | }, 81 | multiple: { 82 | type: 'array', 83 | title: '复选', 84 | enum: [ 85 | { 86 | label: '选项1', 87 | value: 1, 88 | }, 89 | { 90 | label: '选项2', 91 | value: 2, 92 | }, 93 | ], 94 | 'x-decorator': 'FormItem', 95 | 'x-component': 'Checkbox.Group', 96 | }, 97 | }, 98 | } 99 | 100 | export default () => ( 101 | <FormProvider form={form}> 102 | <SchemaField schema={schema} /> 103 | <FormButtonGroup> 104 | <Submit onSubmit={console.log}>提交</Submit> 105 | </FormButtonGroup> 106 | </FormProvider> 107 | ) 108 | ``` 109 | 110 | ## 纯 JSX 案例 111 | 112 | ```tsx 113 | import React from 'react' 114 | import { Checkbox, FormItem, FormButtonGroup, Submit } from '@formily/antd' 115 | import { createForm } from '@formily/core' 116 | import { FormProvider, Field } from '@formily/react' 117 | 118 | const form = createForm() 119 | 120 | export default () => ( 121 | <FormProvider form={form}> 122 | <Field 123 | name="single" 124 | title="是否确认" 125 | decorator={[FormItem]} 126 | component={[Checkbox]} 127 | /> 128 | <Field 129 | name="multiple" 130 | title="复选" 131 | dataSource={[ 132 | { 133 | label: '选项1', 134 | value: 1, 135 | }, 136 | { 137 | label: '选项2', 138 | value: 2, 139 | }, 140 | ]} 141 | decorator={[FormItem]} 142 | component={[Checkbox.Group]} 143 | /> 144 | <FormButtonGroup> 145 | <Submit onSubmit={console.log}>提交</Submit> 146 | </FormButtonGroup> 147 | </FormProvider> 148 | ) 149 | ``` 150 | 151 | ## API 152 | 153 | 参考 https://ant.design/components/checkbox-cn/ 154 | ``` -------------------------------------------------------------------------------- /packages/next/docs/components/Checkbox.zh-CN.md: -------------------------------------------------------------------------------- ```markdown 1 | # Checkbox 2 | 3 | > 复选框 4 | 5 | ## Markup Schema 案例 6 | 7 | ```tsx 8 | import React from 'react' 9 | import { Checkbox, 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 | Checkbox, 16 | FormItem, 17 | }, 18 | }) 19 | 20 | const form = createForm() 21 | 22 | export default () => ( 23 | <FormProvider form={form}> 24 | <SchemaField> 25 | <SchemaField.Boolean 26 | name="single" 27 | title="是否确认" 28 | x-decorator="FormItem" 29 | x-component="Checkbox" 30 | /> 31 | <SchemaField.String 32 | name="multiple" 33 | title="复选" 34 | enum={[ 35 | { 36 | label: '选项1', 37 | value: 1, 38 | }, 39 | { 40 | label: '选项2', 41 | value: 2, 42 | }, 43 | ]} 44 | x-decorator="FormItem" 45 | x-component="Checkbox.Group" 46 | /> 47 | </SchemaField> 48 | <FormButtonGroup> 49 | <Submit onSubmit={console.log}>提交</Submit> 50 | </FormButtonGroup> 51 | </FormProvider> 52 | ) 53 | ``` 54 | 55 | ## JSON Schema 案例 56 | 57 | ```tsx 58 | import React from 'react' 59 | import { Checkbox, FormItem, FormButtonGroup, Submit } from '@formily/next' 60 | import { createForm } from '@formily/core' 61 | import { FormProvider, createSchemaField } from '@formily/react' 62 | 63 | const SchemaField = createSchemaField({ 64 | components: { 65 | Checkbox, 66 | FormItem, 67 | }, 68 | }) 69 | 70 | const form = createForm() 71 | 72 | const schema = { 73 | type: 'object', 74 | properties: { 75 | single: { 76 | type: 'boolean', 77 | title: '是否确认', 78 | 'x-decorator': 'FormItem', 79 | 'x-component': 'Checkbox', 80 | }, 81 | multiple: { 82 | type: 'array', 83 | title: '复选', 84 | enum: [ 85 | { 86 | label: '选项1', 87 | value: 1, 88 | }, 89 | { 90 | label: '选项2', 91 | value: 2, 92 | }, 93 | ], 94 | 'x-decorator': 'FormItem', 95 | 'x-component': 'Checkbox.Group', 96 | }, 97 | }, 98 | } 99 | 100 | export default () => ( 101 | <FormProvider form={form}> 102 | <SchemaField schema={schema} /> 103 | <FormButtonGroup> 104 | <Submit onSubmit={console.log}>提交</Submit> 105 | </FormButtonGroup> 106 | </FormProvider> 107 | ) 108 | ``` 109 | 110 | ## 纯 JSX 案例 111 | 112 | ```tsx 113 | import React from 'react' 114 | import { Checkbox, FormItem, FormButtonGroup, Submit } from '@formily/next' 115 | import { createForm } from '@formily/core' 116 | import { FormProvider, Field } from '@formily/react' 117 | 118 | const form = createForm() 119 | 120 | export default () => ( 121 | <FormProvider form={form}> 122 | <Field 123 | name="single" 124 | title="是否确认" 125 | decorator={[FormItem]} 126 | component={[Checkbox]} 127 | /> 128 | <Field 129 | name="multiple" 130 | title="复选" 131 | dataSource={[ 132 | { 133 | label: '选项1', 134 | value: 1, 135 | }, 136 | { 137 | label: '选项2', 138 | value: 2, 139 | }, 140 | ]} 141 | decorator={[FormItem]} 142 | component={[Checkbox.Group]} 143 | /> 144 | <FormButtonGroup> 145 | <Submit onSubmit={console.log}>提交</Submit> 146 | </FormButtonGroup> 147 | </FormProvider> 148 | ) 149 | ``` 150 | 151 | ## API 152 | 153 | 参考 https://fusion.design/pc/component/basic/checkbox 154 | ``` -------------------------------------------------------------------------------- /packages/element/docs/.vuepress/components/createCodeSandBox.js: -------------------------------------------------------------------------------- ```javascript 1 | import { getParameters } from 'codesandbox/lib/api/define' 2 | 3 | const CodeSandBoxHTML = '<div id="app"></div>' 4 | const CodeSandBoxJS = ` 5 | import Vue from 'vue' 6 | import App from './App.vue' 7 | import Element from 'element-ui'; 8 | import 'element-ui/lib/theme-chalk/index.css'; 9 | 10 | Vue.config.productionTip = false 11 | Vue.use(Element, { size: 'small' }); 12 | 13 | new Vue({ 14 | render: h => h(App), 15 | }).$mount('#app')` 16 | 17 | const createForm = ({ method, action, data }) => { 18 | const form = document.createElement('form') // 构造 form 19 | form.style.display = 'none' // 设置为不显示 20 | form.target = '_blank' // 指向 iframe 21 | 22 | // 构造 formdata 23 | Object.keys(data).forEach((key) => { 24 | const input = document.createElement('input') // 创建 input 25 | 26 | input.name = key // 设置 name 27 | input.value = data[key] // 设置 value 28 | 29 | form.appendChild(input) 30 | }) 31 | 32 | form.method = method // 设置方法 33 | form.action = action // 设置地址 34 | 35 | document.body.appendChild(form) 36 | 37 | // 对该 form 执行提交 38 | form.submit() 39 | 40 | document.body.removeChild(form) 41 | } 42 | 43 | export function createCodeSandBox(codeStr) { 44 | const parameters = getParameters({ 45 | files: { 46 | 'sandbox.config.json': { 47 | content: { 48 | template: 'node', 49 | infiniteLoopProtection: true, 50 | hardReloadOnChange: false, 51 | view: 'browser', 52 | container: { 53 | port: 8080, 54 | node: '14', 55 | }, 56 | }, 57 | }, 58 | 'package.json': { 59 | content: { 60 | scripts: { 61 | serve: 'vue-cli-service serve', 62 | build: 'vue-cli-service build', 63 | lint: 'vue-cli-service lint', 64 | }, 65 | dependencies: { 66 | '@formily/core': 'latest', 67 | '@formily/vue': 'latest', 68 | '@formily/element': 'latest', 69 | axios: '^0.21.1', 70 | 'core-js': '^3.6.5', 71 | 'element-ui': 'latest', 72 | 'vue-demi': 'latest', 73 | vue: '^2.6.11', 74 | }, 75 | devDependencies: { 76 | '@vue/cli-plugin-babel': '~4.5.0', 77 | '@vue/cli-service': '~4.5.0', 78 | '@vue/composition-api': 'latest', 79 | 'vue-template-compiler': '^2.6.11', 80 | sass: '^1.34.1', 81 | 'sass-loader': '^8.0.2', 82 | }, 83 | babel: { 84 | presets: [ 85 | [ 86 | '@vue/babel-preset-jsx', 87 | { 88 | vModel: false, 89 | compositionAPI: true, 90 | }, 91 | ], 92 | ], 93 | }, 94 | vue: { 95 | devServer: { 96 | host: '0.0.0.0', 97 | disableHostCheck: true, // 必须 98 | }, 99 | }, 100 | }, 101 | }, 102 | 'src/App.vue': { 103 | content: codeStr, 104 | }, 105 | 'src/main.js': { 106 | content: CodeSandBoxJS, 107 | }, 108 | 'public/index.html': { 109 | content: CodeSandBoxHTML, 110 | }, 111 | }, 112 | }) 113 | 114 | createForm({ 115 | method: 'post', 116 | action: 'https://codesandbox.io/api/v1/sandboxes/define', 117 | data: { 118 | parameters, 119 | query: 'file=/src/App.vue', 120 | }, 121 | }) 122 | } 123 | ``` -------------------------------------------------------------------------------- /packages/next/src/form-grid/index.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import React, { useLayoutEffect, useRef, useMemo, useContext } from 'react' 2 | import { markRaw } from '@formily/reactive' 3 | import { observer } from '@formily/react' 4 | import { Grid, IGridOptions } from '@formily/grid' 5 | import { usePrefixCls, pickDataProps } from '../__builtins__' 6 | import { useFormLayout } from '../form-layout' 7 | import cls from 'classnames' 8 | 9 | const FormGridContext = React.createContext<Grid<HTMLElement>>(null) 10 | 11 | export interface IFormGridProps extends IGridOptions { 12 | grid?: Grid<HTMLElement> 13 | prefix?: string 14 | className?: string 15 | style?: React.CSSProperties 16 | } 17 | 18 | export interface IGridColumnProps { 19 | gridSpan?: number 20 | style?: React.CSSProperties 21 | className?: string 22 | } 23 | 24 | type ComposedFormGrid = React.FC<React.PropsWithChildren<IFormGridProps>> & { 25 | GridColumn: React.FC<React.PropsWithChildren<IGridColumnProps>> 26 | useFormGrid: () => Grid<HTMLElement> 27 | createFormGrid: (props: IFormGridProps) => Grid<HTMLElement> 28 | /** 29 | * @deprecated 30 | */ 31 | useGridSpan: (gridSpan: number) => number 32 | /** 33 | * @deprecated 34 | */ 35 | useGridColumn: (gridSpan: number) => number 36 | } 37 | 38 | export const createFormGrid = (props: IFormGridProps) => { 39 | return markRaw(new Grid(props)) 40 | } 41 | 42 | export const useFormGrid = () => useContext(FormGridContext) 43 | 44 | /** 45 | * @deprecated 46 | */ 47 | export const useGridSpan = (gridSpan = 1) => { 48 | return gridSpan 49 | } 50 | /** 51 | * @deprecated 52 | */ 53 | export const useGridColumn = (gridSpan = 1) => { 54 | return gridSpan 55 | } 56 | 57 | export const FormGrid: ComposedFormGrid = observer( 58 | ({ 59 | children, 60 | className, 61 | style, 62 | ...props 63 | }: React.PropsWithChildren<IFormGridProps>) => { 64 | const layout = useFormLayout() 65 | const options = { 66 | columnGap: layout?.gridColumnGap ?? 8, 67 | rowGap: layout?.gridRowGap ?? 4, 68 | ...props, 69 | } 70 | const grid = useMemo( 71 | () => markRaw(options?.grid ? options.grid : new Grid(options)), 72 | [Grid.id(options)] 73 | ) 74 | const ref = useRef<HTMLDivElement>() 75 | const prefixCls = usePrefixCls('formily-grid', props) 76 | const dataProps = pickDataProps(props) 77 | useLayoutEffect(() => { 78 | return grid.connect(ref.current) 79 | }, [grid]) 80 | return ( 81 | <FormGridContext.Provider value={grid}> 82 | <div 83 | {...dataProps} 84 | className={cls(`${prefixCls}-layout`, className)} 85 | style={{ 86 | ...style, 87 | gridTemplateColumns: grid.templateColumns, 88 | gap: grid.gap, 89 | }} 90 | ref={ref} 91 | > 92 | {children} 93 | </div> 94 | </FormGridContext.Provider> 95 | ) 96 | }, 97 | { 98 | forwardRef: true, 99 | } 100 | ) as any 101 | 102 | export const GridColumn: React.FC<React.PropsWithChildren<IGridColumnProps>> = 103 | observer(({ gridSpan = 1, children, ...props }) => { 104 | return ( 105 | <div {...props} data-grid-span={gridSpan}> 106 | {children} 107 | </div> 108 | ) 109 | }) 110 | 111 | FormGrid.createFormGrid = createFormGrid 112 | FormGrid.useFormGrid = useFormGrid 113 | FormGrid.useGridSpan = useGridSpan 114 | FormGrid.useGridColumn = useGridColumn 115 | FormGrid.GridColumn = GridColumn 116 | 117 | export default FormGrid 118 | ``` -------------------------------------------------------------------------------- /devtools/chrome-extension/src/extension/backend.ts: -------------------------------------------------------------------------------- ```typescript 1 | //inject content script 2 | 3 | const serializeObject = (obj: any) => { 4 | const seens = new WeakMap() 5 | const serialize = (obj: any) => { 6 | if (Array.isArray(obj)) { 7 | return obj.map(serialize) 8 | } else if (typeof obj === 'function') { 9 | return `f ${obj.displayName || obj.name}(){ }` 10 | } else if (typeof obj === 'object') { 11 | if (seens.get(obj)) return '#CircularReference' 12 | if (!obj) return obj 13 | if ('$$typeof' in obj && '_owner' in obj) { 14 | seens.set(obj, true) 15 | return '#ReactNode' 16 | } else if (obj.toJS) { 17 | seens.set(obj, true) 18 | return obj.toJS() 19 | } else if (obj.toJSON) { 20 | seens.set(obj, true) 21 | return obj.toJSON() 22 | } else { 23 | seens.set(obj, true) 24 | const result = {} 25 | for (let key in obj) { 26 | result[key] = serialize(obj[key]) 27 | } 28 | seens.set(obj, false) 29 | return result 30 | } 31 | } 32 | return obj 33 | } 34 | return serialize(obj) 35 | } 36 | 37 | const send = ({ 38 | type, 39 | id, 40 | form, 41 | }: { 42 | type: string 43 | id?: string | number 44 | form?: any 45 | }) => { 46 | const graph = serializeObject(form?.getFormGraph()) 47 | window.postMessage( 48 | { 49 | source: '@formily-devtools-inject-script', 50 | type, 51 | id, 52 | graph: 53 | form && 54 | JSON.stringify(graph, (key, value) => { 55 | if (typeof value === 'symbol') { 56 | return value.toString() 57 | } 58 | return value 59 | }), 60 | }, 61 | '*' 62 | ) 63 | } 64 | 65 | send({ 66 | type: 'init', 67 | }) 68 | 69 | interface IIdleDeadline { 70 | didTimeout: boolean 71 | timeRemaining: () => DOMHighResTimeStamp 72 | } 73 | 74 | const HOOK = { 75 | hasFormilyInstance: false, 76 | hasOpenDevtools: false, 77 | store: {}, 78 | openDevtools() { 79 | this.hasOpenDevtools = true 80 | }, 81 | closeDevtools() { 82 | this.hasOpenDevtools = false 83 | }, 84 | setVm(fieldId: string, formId: string) { 85 | if (fieldId) { 86 | globalThis.$vm = this.store[formId].fields[fieldId] 87 | } else { 88 | globalThis.$vm = this.store[formId] 89 | } 90 | }, 91 | inject(id: number, form: any) { 92 | this.hasFormilyInstance = true 93 | this.store[id] = form 94 | send({ 95 | type: 'install', 96 | id, 97 | form, 98 | }) 99 | let timer = null 100 | const task = () => { 101 | globalThis.requestIdleCallback((deadline: IIdleDeadline) => { 102 | if (this.store[id]) { 103 | if (deadline.timeRemaining() < 16) { 104 | task() 105 | } else { 106 | send({ 107 | type: 'update', 108 | id, 109 | form, 110 | }) 111 | } 112 | } 113 | }) 114 | } 115 | form.subscribe(() => { 116 | if (!this.hasOpenDevtools) return 117 | clearTimeout(timer) 118 | timer = setTimeout(task, 300) 119 | }) 120 | }, 121 | update() { 122 | const keys = Object.keys(this.store || {}) 123 | keys.forEach((id) => { 124 | send({ 125 | type: 'update', 126 | id, 127 | form: this.store[id], 128 | }) 129 | }) 130 | }, 131 | unmount(id: number) { 132 | delete this.store[id] 133 | send({ 134 | type: 'uninstall', 135 | id, 136 | }) 137 | }, 138 | } 139 | 140 | globalThis.__FORMILY_DEV_TOOLS_HOOK__ = HOOK 141 | globalThis.__UFORM_DEV_TOOLS_HOOK__ = HOOK 142 | ``` -------------------------------------------------------------------------------- /packages/element/src/radio/index.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { connect, h, mapProps, mapReadPretty } from '@formily/vue' 2 | import type { 3 | Radio as ElRadioProps, 4 | RadioGroup as ElRadioGroupProps, 5 | } from 'element-ui' 6 | import { 7 | Radio as ElRadio, 8 | RadioButton, 9 | RadioGroup as ElRadioGroup, 10 | } from 'element-ui' 11 | import { defineComponent, PropType } from 'vue-demi' 12 | import { PreviewText } from '../preview-text' 13 | import { 14 | composeExport, 15 | resolveComponent, 16 | SlotTypes, 17 | transformComponent, 18 | } from '../__builtins__/shared' 19 | 20 | export type RadioGroupProps = ElRadioGroupProps & { 21 | value: any 22 | options?: ( 23 | | (Omit<ElRadioProps, 'value'> & { 24 | value: ElRadioProps['label'] 25 | label: SlotTypes 26 | }) 27 | | string 28 | )[] 29 | optionType: 'default' | 'button' 30 | } 31 | 32 | export type RadioProps = ElRadioProps 33 | 34 | const TransformElRadioGroup = transformComponent(ElRadioGroup, { 35 | change: 'input', 36 | uselessChange:'change' 37 | }) 38 | 39 | const RadioGroupOption = defineComponent<RadioGroupProps>({ 40 | name: 'FRadioGroup', 41 | props: { 42 | options: { 43 | type: Array as PropType<RadioGroupProps['options']>, 44 | default: () => [], 45 | }, 46 | optionType: { 47 | type: String as PropType<RadioGroupProps['optionType']>, 48 | default: 'default', 49 | }, 50 | }, 51 | setup(customProps, { attrs, slots, listeners }) { 52 | return () => { 53 | const options = customProps.options || [] 54 | const OptionType = 55 | customProps.optionType === 'button' ? RadioButton : ElRadio 56 | const children = 57 | options.length !== 0 58 | ? { 59 | default: () => 60 | options.map((option) => { 61 | if (typeof option === 'string') { 62 | return h( 63 | OptionType, 64 | { props: { label: option } }, 65 | { 66 | default: () => [ 67 | resolveComponent(slots?.option ?? option, { option }), 68 | ], 69 | } 70 | ) 71 | } else { 72 | return h( 73 | OptionType, 74 | { 75 | props: { 76 | ...option, 77 | value: undefined, 78 | label: option.value, 79 | }, 80 | }, 81 | { 82 | default: () => [ 83 | resolveComponent(slots?.option ?? option.label, { 84 | option, 85 | }), 86 | ], 87 | } 88 | ) 89 | } 90 | }), 91 | } 92 | : slots 93 | return h( 94 | TransformElRadioGroup, 95 | { 96 | attrs: { 97 | ...attrs, 98 | }, 99 | on: listeners, 100 | }, 101 | children 102 | ) 103 | } 104 | }, 105 | }) 106 | 107 | const RadioGroup = connect( 108 | RadioGroupOption, 109 | mapProps({ dataSource: 'options' }), 110 | mapReadPretty(PreviewText.Select) 111 | ) 112 | export const Radio = composeExport(ElRadio, { 113 | Group: RadioGroup, 114 | }) 115 | 116 | export default Radio 117 | ``` -------------------------------------------------------------------------------- /packages/antd/src/form-grid/index.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import React, { useLayoutEffect, useRef, useMemo, useContext } from 'react' 2 | import { markRaw } from '@formily/reactive' 3 | import { observer } from '@formily/react' 4 | import { Grid, IGridOptions } from '@formily/grid' 5 | import { usePrefixCls, pickDataProps } from '../__builtins__' 6 | import { useFormLayout } from '../form-layout' 7 | import cls from 'classnames' 8 | 9 | const FormGridContext = React.createContext<Grid<HTMLElement>>(null) 10 | 11 | export interface IFormGridProps extends IGridOptions { 12 | grid?: Grid<HTMLElement> 13 | prefixCls?: string 14 | className?: string 15 | style?: React.CSSProperties 16 | } 17 | 18 | export interface IGridColumnProps { 19 | gridSpan?: number 20 | style?: React.CSSProperties 21 | className?: string 22 | } 23 | 24 | type ComposedFormGrid = React.FC<React.PropsWithChildren<IFormGridProps>> & { 25 | GridColumn: React.FC<React.PropsWithChildren<IGridColumnProps>> 26 | useFormGrid: () => Grid<HTMLElement> 27 | createFormGrid: (props: IFormGridProps) => Grid<HTMLElement> 28 | /** 29 | * @deprecated 30 | */ 31 | useGridSpan: (gridSpan: number) => number 32 | /** 33 | * @deprecated 34 | */ 35 | useGridColumn: (gridSpan: number) => number 36 | } 37 | 38 | export const createFormGrid = (props: IFormGridProps) => { 39 | return markRaw(new Grid(props)) 40 | } 41 | 42 | export const useFormGrid = () => useContext(FormGridContext) 43 | 44 | /** 45 | * @deprecated 46 | */ 47 | export const useGridSpan = (gridSpan = 1) => { 48 | return gridSpan 49 | } 50 | 51 | /** 52 | * @deprecated 53 | */ 54 | export const useGridColumn = (gridSpan = 1) => { 55 | return gridSpan 56 | } 57 | 58 | export const FormGrid: ComposedFormGrid = observer( 59 | ({ 60 | children, 61 | className, 62 | style, 63 | ...props 64 | }: React.PropsWithChildren<IFormGridProps>) => { 65 | const layout = useFormLayout() 66 | const options = { 67 | columnGap: layout?.gridColumnGap ?? 8, 68 | rowGap: layout?.gridRowGap ?? 4, 69 | ...props, 70 | } 71 | const grid = useMemo( 72 | () => markRaw(options?.grid ? options.grid : new Grid(options)), 73 | [Grid.id(options)] 74 | ) 75 | const ref = useRef<HTMLDivElement>() 76 | const prefixCls = usePrefixCls('formily-grid', props) 77 | const dataProps = pickDataProps(props) 78 | useLayoutEffect(() => { 79 | return grid.connect(ref.current) 80 | }, [grid]) 81 | return ( 82 | <FormGridContext.Provider value={grid}> 83 | <div 84 | {...dataProps} 85 | className={cls(`${prefixCls}-layout`, className)} 86 | style={{ 87 | ...style, 88 | gridTemplateColumns: grid.templateColumns, 89 | gap: grid.gap, 90 | }} 91 | ref={ref} 92 | > 93 | {children} 94 | </div> 95 | </FormGridContext.Provider> 96 | ) 97 | }, 98 | { 99 | forwardRef: true, 100 | } 101 | ) as any 102 | 103 | export const GridColumn: React.FC<React.PropsWithChildren<IGridColumnProps>> = 104 | observer(({ gridSpan = 1, children, ...props }) => { 105 | return ( 106 | <div {...props} style={props.style} data-grid-span={gridSpan}> 107 | {children} 108 | </div> 109 | ) 110 | }) 111 | 112 | FormGrid.createFormGrid = createFormGrid 113 | FormGrid.useGridSpan = useGridSpan 114 | FormGrid.useGridColumn = useGridColumn 115 | FormGrid.useFormGrid = useFormGrid 116 | FormGrid.GridColumn = GridColumn 117 | 118 | export default FormGrid 119 | ``` -------------------------------------------------------------------------------- /packages/element/docs/demos/guide/form-step/json-schema.vue: -------------------------------------------------------------------------------- ```vue 1 | <template> 2 | <FormProvider :form="form"> 3 | <SchemaField :schema="schema" :scope="{ formStep }" /> 4 | <FormConsumer> 5 | <template #default> 6 | <FormButtonGroup> 7 | <Button 8 | :disabled="!formStep.allowBack" 9 | @click=" 10 | () => { 11 | formStep.back() 12 | } 13 | " 14 | > 15 | 上一步 16 | </Button> 17 | <Button 18 | :disabled="!formStep.allowNext" 19 | @click=" 20 | () => { 21 | formStep.next() 22 | } 23 | " 24 | > 25 | 下一步 26 | </Button> 27 | <Submit :disabled="formStep.allowNext" @submit="log">提交</Submit> 28 | </FormButtonGroup> 29 | </template> 30 | </FormConsumer> 31 | </FormProvider> 32 | </template> 33 | 34 | <script> 35 | import { createForm } from '@formily/core' 36 | import { FormProvider, createSchemaField, FormConsumer } from '@formily/vue' 37 | import { 38 | FormItem, 39 | FormStep, 40 | FormButtonGroup, 41 | Submit, 42 | Input, 43 | } from '@formily/element' 44 | import { Button } from 'element-ui' 45 | 46 | const { SchemaField } = createSchemaField({ 47 | components: { 48 | FormItem, 49 | FormStep, 50 | Input, 51 | }, 52 | }) 53 | 54 | const schema = { 55 | type: 'object', 56 | properties: { 57 | collapse: { 58 | type: 'void', 59 | 'x-component': 'FormStep', 60 | 'x-component-props': { 61 | formStep: '{{formStep}}', 62 | }, 63 | properties: { 64 | step1: { 65 | type: 'void', 66 | 'x-component': 'FormStep.StepPane', 67 | 'x-component-props': { 68 | title: '第一步', 69 | }, 70 | properties: { 71 | aaa: { 72 | type: 'string', 73 | title: 'AAA', 74 | required: true, 75 | 'x-decorator': 'FormItem', 76 | 'x-component': 'Input', 77 | }, 78 | }, 79 | }, 80 | step2: { 81 | type: 'void', 82 | 'x-component': 'FormStep.StepPane', 83 | 'x-component-props': { 84 | title: '第二步', 85 | }, 86 | properties: { 87 | bbb: { 88 | type: 'string', 89 | title: 'AAA', 90 | required: true, 91 | 'x-decorator': 'FormItem', 92 | 'x-component': 'Input', 93 | }, 94 | }, 95 | }, 96 | step3: { 97 | type: 'void', 98 | 'x-component': 'FormStep.StepPane', 99 | 'x-component-props': { 100 | title: '第三步', 101 | }, 102 | properties: { 103 | ccc: { 104 | type: 'string', 105 | title: 'AAA', 106 | required: true, 107 | 'x-decorator': 'FormItem', 108 | 'x-component': 'Input', 109 | }, 110 | }, 111 | }, 112 | }, 113 | }, 114 | }, 115 | } 116 | 117 | export default { 118 | components: { 119 | FormProvider, 120 | FormConsumer, 121 | FormButtonGroup, 122 | Button, 123 | Submit, 124 | SchemaField, 125 | }, 126 | 127 | data() { 128 | const form = createForm() 129 | const formStep = FormStep.createFormStep() 130 | return { 131 | schema, 132 | form, 133 | formStep, 134 | } 135 | }, 136 | methods: { 137 | log() { 138 | this.formStep.submit(console.log) 139 | }, 140 | }, 141 | } 142 | </script> 143 | 144 | <style lang="scss" scoped></style> 145 | ``` -------------------------------------------------------------------------------- /packages/element/docs/demos/guide/space/json-schema.vue: -------------------------------------------------------------------------------- ```vue 1 | <template> 2 | <FormProvider :form="form"> 3 | <FormLayout :labelCol="6" :wrapperCol="16"> 4 | <SchemaField :schema="schema" /> 5 | <FormButtonGroup alignFormItem> 6 | <Submit onSubmit="log">提交</Submit> 7 | </FormButtonGroup> 8 | </FormLayout> 9 | </FormProvider> 10 | </template> 11 | 12 | <script> 13 | import { createForm } from '@formily/core' 14 | import { createSchemaField, FormProvider } from '@formily/vue' 15 | import { 16 | FormButtonGroup, 17 | FormLayout, 18 | FormItem, 19 | Input, 20 | Submit, 21 | Space, 22 | } from '@formily/element' 23 | 24 | const { SchemaField } = createSchemaField({ 25 | components: { 26 | FormLayout, 27 | FormItem, 28 | Input, 29 | Space, 30 | }, 31 | }) 32 | 33 | export default { 34 | components: { 35 | FormProvider, 36 | FormButtonGroup, 37 | FormLayout, 38 | SchemaField, 39 | Submit, 40 | }, 41 | data() { 42 | const schema = { 43 | type: 'object', 44 | properties: { 45 | name: { 46 | type: 'void', 47 | title: '姓名', 48 | 'x-decorator': 'FormItem', 49 | 'x-decorator-props': { 50 | asterisk: true, 51 | feedbackLayout: 'none', 52 | }, 53 | 'x-component': 'Space', 54 | properties: { 55 | firstName: { 56 | type: 'string', 57 | 'x-decorator': 'FormItem', 58 | 'x-component': 'Input', 59 | required: true, 60 | }, 61 | lastName: { 62 | type: 'string', 63 | 'x-decorator': 'FormItem', 64 | 'x-component': 'Input', 65 | required: true, 66 | }, 67 | }, 68 | }, 69 | texts: { 70 | type: 'void', 71 | title: '文本串联', 72 | 'x-decorator': 'FormItem', 73 | 'x-decorator-props': { 74 | asterisk: true, 75 | feedbackLayout: 'none', 76 | }, 77 | 'x-component': 'Space', 78 | properties: { 79 | aa: { 80 | type: 'string', 81 | 'x-decorator': 'FormItem', 82 | 'x-decorator-props': { 83 | addonAfter: '单位', 84 | }, 85 | 'x-component': 'Input', 86 | required: true, 87 | }, 88 | bb: { 89 | type: 'string', 90 | 'x-decorator': 'FormItem', 91 | 'x-decorator-props': { 92 | addonAfter: '单位', 93 | }, 94 | 'x-component': 'Input', 95 | required: true, 96 | }, 97 | cc: { 98 | type: 'string', 99 | 'x-decorator': 'FormItem', 100 | 'x-decorator-props': { 101 | addonAfter: '单位', 102 | }, 103 | 'x-component': 'Input', 104 | required: true, 105 | }, 106 | }, 107 | }, 108 | 109 | textarea: { 110 | type: 'string', 111 | title: '文本框', 112 | 'x-decorator': 'FormItem', 113 | 'x-component': 'Input.TextArea', 114 | 'x-component-props': { 115 | style: { 116 | width: 400, 117 | }, 118 | }, 119 | required: true, 120 | }, 121 | }, 122 | } 123 | 124 | const form = createForm() 125 | 126 | return { 127 | form, 128 | schema, 129 | } 130 | }, 131 | methods: { 132 | logs(value) { 133 | console.log(value) 134 | }, 135 | }, 136 | } 137 | </script> 138 | ``` -------------------------------------------------------------------------------- /packages/element/docs/demos/guide/array-collapse/effects-json-schema.vue: -------------------------------------------------------------------------------- ```vue 1 | <template> 2 | <FormProvider :form="form"> 3 | <SchemaField :schema="schema" /> 4 | <Submit @submit="log">提交</Submit> 5 | </FormProvider> 6 | </template> 7 | 8 | <script> 9 | import { createForm } from '@formily/core' 10 | import { FormProvider, createSchemaField } from '@formily/vue' 11 | import { 12 | FormItem, 13 | FormButtonGroup, 14 | Submit, 15 | Input, 16 | ArrayCollapse, 17 | } from '@formily/element' 18 | import { Button } from 'element-ui' 19 | 20 | const SchemaField = createSchemaField({ 21 | components: { 22 | FormItem, 23 | Input, 24 | ArrayCollapse, 25 | }, 26 | }) 27 | 28 | export default { 29 | components: { 30 | FormProvider, 31 | FormButtonGroup, 32 | Button, 33 | Submit, 34 | ...SchemaField, 35 | }, 36 | 37 | data() { 38 | const form = createForm() 39 | const schema = { 40 | type: 'object', 41 | properties: { 42 | array: { 43 | type: 'array', 44 | 'x-component': 'ArrayCollapse', 45 | maxItems: 3, 46 | title: '对象数组', 47 | items: { 48 | type: 'object', 49 | 'x-component': 'ArrayCollapse.Item', 50 | 'x-component-props': { 51 | header: '对象数组', 52 | }, 53 | properties: { 54 | index: { 55 | type: 'void', 56 | 'x-component': 'ArrayCollapse.Index', 57 | }, 58 | aa: { 59 | type: 'string', 60 | 'x-decorator': 'FormItem', 61 | title: 'AA', 62 | required: true, 63 | 'x-component': 'Input', 64 | description: '输入123', 65 | }, 66 | bb: { 67 | type: 'string', 68 | title: 'BB', 69 | required: true, 70 | 'x-decorator': 'FormItem', 71 | 'x-component': 'Input', 72 | 'x-reactions': [ 73 | { 74 | dependencies: ['.aa'], 75 | when: "{{$deps[0] != '123'}}", 76 | fulfill: { 77 | schema: { 78 | title: 'BB', 79 | 'x-disabled': true, 80 | }, 81 | }, 82 | otherwise: { 83 | schema: { 84 | title: 'Changed', 85 | 'x-disabled': false, 86 | }, 87 | }, 88 | }, 89 | ], 90 | }, 91 | remove: { 92 | type: 'void', 93 | 'x-component': 'ArrayCollapse.Remove', 94 | }, 95 | moveUp: { 96 | type: 'void', 97 | 'x-component': 'ArrayCollapse.MoveUp', 98 | }, 99 | moveDown: { 100 | type: 'void', 101 | 'x-component': 'ArrayCollapse.MoveDown', 102 | }, 103 | }, 104 | }, 105 | properties: { 106 | addition: { 107 | type: 'void', 108 | title: '添加条目', 109 | 'x-component': 'ArrayCollapse.Addition', 110 | }, 111 | }, 112 | }, 113 | }, 114 | } 115 | 116 | return { 117 | form, 118 | schema, 119 | } 120 | }, 121 | methods: { 122 | log(values) { 123 | console.log(values) 124 | }, 125 | }, 126 | } 127 | </script> 128 | 129 | <style lang="scss" scoped></style> 130 | ``` -------------------------------------------------------------------------------- /packages/core/src/__tests__/externals.spec.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { createForm } from '..' 2 | import { 3 | isArrayField, 4 | isArrayFieldState, 5 | isDataField, 6 | isDataFieldState, 7 | isField, 8 | isFieldState, 9 | isForm, 10 | isFormState, 11 | isGeneralField, 12 | isGeneralFieldState, 13 | isObjectField, 14 | isObjectFieldState, 15 | isQuery, 16 | isVoidField, 17 | isVoidFieldState, 18 | createEffectHook, 19 | } from '../shared/externals' 20 | import { attach } from './shared' 21 | 22 | test('type checkers', () => { 23 | const form = attach(createForm()) 24 | const normal = attach( 25 | form.createField({ 26 | name: 'normal', 27 | }) 28 | ) 29 | const array = attach( 30 | form.createArrayField({ 31 | name: 'array', 32 | }) 33 | ) 34 | const object = attach( 35 | form.createObjectField({ 36 | name: 'object', 37 | }) 38 | ) 39 | const void_ = attach( 40 | form.createVoidField({ 41 | name: 'void', 42 | }) 43 | ) 44 | expect(isField(normal)).toBeTruthy() 45 | expect(isFieldState(normal.getState())).toBeTruthy() 46 | expect(isFieldState(null)).toBeFalsy() 47 | expect(isFieldState({})).toBeFalsy() 48 | expect(isFieldState(normal)).toBeFalsy() 49 | 50 | expect(isArrayField(array)).toBeTruthy() 51 | expect(isArrayFieldState(array.getState())).toBeTruthy() 52 | expect(isArrayFieldState(null)).toBeFalsy() 53 | expect(isArrayFieldState({})).toBeFalsy() 54 | expect(isArrayFieldState(array)).toBeFalsy() 55 | 56 | expect(isObjectField(object)).toBeTruthy() 57 | expect(isObjectFieldState(object.getState())).toBeTruthy() 58 | expect(isObjectFieldState(null)).toBeFalsy() 59 | expect(isObjectFieldState({})).toBeFalsy() 60 | expect(isObjectFieldState(object)).toBeFalsy() 61 | 62 | expect(isVoidField(void_)).toBeTruthy() 63 | expect(isVoidFieldState(void_.getState())).toBeTruthy() 64 | expect(isVoidFieldState(null)).toBeFalsy() 65 | expect(isVoidFieldState({})).toBeFalsy() 66 | expect(isVoidFieldState(void_)).toBeFalsy() 67 | 68 | expect(isDataField(void_)).toBeFalsy() 69 | expect(isDataFieldState(void_.getState())).toBeFalsy() 70 | 71 | expect(isDataField(normal)).toBeTruthy() 72 | expect(isDataFieldState(normal.getState())).toBeTruthy() 73 | expect(isGeneralField(normal)).toBeTruthy() 74 | expect(isGeneralField(array)).toBeTruthy() 75 | expect(isGeneralField(object)).toBeTruthy() 76 | expect(isGeneralField(void_)).toBeTruthy() 77 | 78 | expect(isGeneralFieldState(normal.getState())).toBeTruthy() 79 | expect(isGeneralFieldState(array.getState())).toBeTruthy() 80 | expect(isGeneralFieldState(object.getState())).toBeTruthy() 81 | expect(isGeneralFieldState(void_.getState())).toBeTruthy() 82 | expect(isGeneralFieldState(null)).toBeFalsy() 83 | expect(isGeneralFieldState({})).toBeFalsy() 84 | expect(isGeneralFieldState(void_)).toBeFalsy() 85 | 86 | expect(isForm(form)).toBeTruthy() 87 | expect(isFormState(form.getState())).toBeTruthy() 88 | expect(isFormState({})).toBeFalsy() 89 | expect(isFormState(form)).toBeFalsy() 90 | expect(isFormState(null)).toBeFalsy() 91 | expect(isQuery(form.query('*'))).toBeTruthy() 92 | }) 93 | 94 | test('createEffectHook', () => { 95 | try { 96 | createEffectHook('xxx')() 97 | } catch {} 98 | const form = attach( 99 | createForm({ 100 | effects() { 101 | createEffectHook('xxx')() 102 | createEffectHook('yyy', () => () => {})() 103 | }, 104 | }) 105 | ) 106 | form.notify('xxx') 107 | form.notify('yyy') 108 | }) 109 | ``` -------------------------------------------------------------------------------- /packages/antd/docs/components/Checkbox.md: -------------------------------------------------------------------------------- ```markdown 1 | # Checkbox 2 | 3 | > Checkbox 4 | 5 | ## Markup Schema example 6 | 7 | ```tsx 8 | import React from 'react' 9 | import { Checkbox, FormItem, FormButtonGroup, Submit } from '@formily/antd' 10 | import { createForm } from '@formily/core' 11 | import { FormProvider, createSchemaField } from '@formily/react' 12 | 13 | const SchemaField = createSchemaField({ 14 | components: { 15 | Checkbox, 16 | FormItem, 17 | }, 18 | }) 19 | 20 | const form = createForm() 21 | 22 | export default () => ( 23 | <FormProvider form={form}> 24 | <SchemaField> 25 | <SchemaField.Boolean 26 | name="single" 27 | title="Are you sure" 28 | x-decorator="FormItem" 29 | x-component="Checkbox" 30 | /> 31 | <SchemaField.String 32 | name="multiple" 33 | title="Check" 34 | enum={[ 35 | { 36 | label: 'Option 1', 37 | value: 1, 38 | }, 39 | { 40 | label: 'Option 2', 41 | value: 2, 42 | }, 43 | ]} 44 | x-decorator="FormItem" 45 | x-component="Checkbox.Group" 46 | /> 47 | </SchemaField> 48 | <FormButtonGroup> 49 | <Submit onSubmit={console.log}>Submit</Submit> 50 | </FormButtonGroup> 51 | </FormProvider> 52 | ) 53 | ``` 54 | 55 | ## JSON Schema case 56 | 57 | ```tsx 58 | import React from 'react' 59 | import { Checkbox, FormItem, FormButtonGroup, Submit } from '@formily/antd' 60 | import { createForm } from '@formily/core' 61 | import { FormProvider, createSchemaField } from '@formily/react' 62 | 63 | const SchemaField = createSchemaField({ 64 | components: { 65 | Checkbox, 66 | FormItem, 67 | }, 68 | }) 69 | 70 | const form = createForm() 71 | 72 | const schema = { 73 | type: 'object', 74 | properties: { 75 | single: { 76 | type: 'boolean', 77 | title: 'Are you sure?', 78 | 'x-decorator': 'FormItem', 79 | 'x-component': 'Checkbox', 80 | }, 81 | multiple: { 82 | type: 'array', 83 | title: 'Check', 84 | enum: [ 85 | { 86 | label: 'Option 1', 87 | value: 1, 88 | }, 89 | { 90 | label: 'Option 2', 91 | value: 2, 92 | }, 93 | ], 94 | 'x-decorator': 'FormItem', 95 | 'x-component': 'Checkbox.Group', 96 | }, 97 | }, 98 | } 99 | 100 | export default () => ( 101 | <FormProvider form={form}> 102 | <SchemaField schema={schema} /> 103 | <FormButtonGroup> 104 | <Submit onSubmit={console.log}>Submit</Submit> 105 | </FormButtonGroup> 106 | </FormProvider> 107 | ) 108 | ``` 109 | 110 | ## Pure JSX case 111 | 112 | ```tsx 113 | import React from 'react' 114 | import { Checkbox, FormItem, FormButtonGroup, Submit } from '@formily/antd' 115 | import { createForm } from '@formily/core' 116 | import { FormProvider, Field } from '@formily/react' 117 | 118 | const form = createForm() 119 | 120 | export default () => ( 121 | <FormProvider form={form}> 122 | <Field 123 | name="single" 124 | title="Are you sure" 125 | decorator={[FormItem]} 126 | component={[Checkbox]} 127 | /> 128 | <Field 129 | name="multiple" 130 | title="Check" 131 | dataSource={[ 132 | { 133 | label: 'Option 1', 134 | value: 1, 135 | }, 136 | { 137 | label: 'Option 2', 138 | value: 2, 139 | }, 140 | ]} 141 | decorator={[FormItem]} 142 | component={[Checkbox.Group]} 143 | /> 144 | <FormButtonGroup> 145 | <Submit onSubmit={console.log}>Submit</Submit> 146 | </FormButtonGroup> 147 | </FormProvider> 148 | ) 149 | ``` 150 | 151 | ## API 152 | 153 | Reference https://ant.design/components/checkbox-cn/ 154 | ``` -------------------------------------------------------------------------------- /packages/antd/docs/components/Input.zh-CN.md: -------------------------------------------------------------------------------- ```markdown 1 | # Input 2 | 3 | > 文本输入框 4 | 5 | ## Markup Schema 案例 6 | 7 | ```tsx 8 | import React from 'react' 9 | import { Input, FormItem, FormButtonGroup, Submit } from '@formily/antd' 10 | import { createForm } from '@formily/core' 11 | import { FormProvider, createSchemaField } from '@formily/react' 12 | 13 | const SchemaField = createSchemaField({ 14 | components: { 15 | Input, 16 | FormItem, 17 | }, 18 | }) 19 | 20 | const form = createForm() 21 | 22 | export default () => ( 23 | <FormProvider form={form}> 24 | <SchemaField> 25 | <SchemaField.String 26 | name="input" 27 | title="输入框" 28 | x-decorator="FormItem" 29 | x-component="Input" 30 | required 31 | x-component-props={{ 32 | style: { 33 | width: 240, 34 | }, 35 | }} 36 | /> 37 | <SchemaField.String 38 | name="textarea" 39 | title="文本框" 40 | x-decorator="FormItem" 41 | required 42 | x-component="Input.TextArea" 43 | x-component-props={{ 44 | style: { 45 | width: 400, 46 | }, 47 | }} 48 | /> 49 | </SchemaField> 50 | <FormButtonGroup> 51 | <Submit onSubmit={console.log}>提交</Submit> 52 | </FormButtonGroup> 53 | </FormProvider> 54 | ) 55 | ``` 56 | 57 | ## JSON Schema 案例 58 | 59 | ```tsx 60 | import React from 'react' 61 | import { Input, FormItem, FormButtonGroup, Submit } from '@formily/antd' 62 | import { createForm } from '@formily/core' 63 | import { FormProvider, createSchemaField } from '@formily/react' 64 | 65 | const SchemaField = createSchemaField({ 66 | components: { 67 | Input, 68 | FormItem, 69 | }, 70 | }) 71 | 72 | const form = createForm() 73 | 74 | const schema = { 75 | type: 'object', 76 | properties: { 77 | input: { 78 | type: 'string', 79 | title: '输入框', 80 | 'x-decorator': 'FormItem', 81 | 'x-component': 'Input', 82 | 'x-component-props': { 83 | style: { 84 | width: 240, 85 | }, 86 | }, 87 | }, 88 | textarea: { 89 | type: 'string', 90 | title: '输入框', 91 | 'x-decorator': 'FormItem', 92 | 'x-component': 'Input.TextArea', 93 | 'x-component-props': { 94 | style: { 95 | width: 240, 96 | }, 97 | }, 98 | }, 99 | }, 100 | } 101 | 102 | export default () => ( 103 | <FormProvider form={form}> 104 | <SchemaField schema={schema} /> 105 | <FormButtonGroup> 106 | <Submit onSubmit={console.log}>提交</Submit> 107 | </FormButtonGroup> 108 | </FormProvider> 109 | ) 110 | ``` 111 | 112 | ## 纯 JSX 案例 113 | 114 | ```tsx 115 | import React from 'react' 116 | import { Input, FormItem, FormButtonGroup, Submit } from '@formily/antd' 117 | import { createForm } from '@formily/core' 118 | import { FormProvider, Field } from '@formily/react' 119 | 120 | const form = createForm() 121 | 122 | export default () => ( 123 | <FormProvider form={form}> 124 | <Field 125 | name="input" 126 | title="输入框" 127 | required 128 | decorator={[FormItem]} 129 | component={[ 130 | Input, 131 | { 132 | style: { 133 | width: 240, 134 | }, 135 | }, 136 | ]} 137 | /> 138 | <Field 139 | name="textarea" 140 | title="文本框" 141 | required 142 | decorator={[FormItem]} 143 | component={[ 144 | Input.TextArea, 145 | { 146 | style: { 147 | width: 400, 148 | }, 149 | }, 150 | ]} 151 | /> 152 | <FormButtonGroup> 153 | <Submit onSubmit={console.log}>提交</Submit> 154 | </FormButtonGroup> 155 | </FormProvider> 156 | ) 157 | ``` 158 | 159 | ## API 160 | 161 | 参考 https://ant.design/components/input-cn/ 162 | ``` -------------------------------------------------------------------------------- /packages/next/docs/components/Checkbox.md: -------------------------------------------------------------------------------- ```markdown 1 | # Checkbox 2 | 3 | > Checkbox 4 | 5 | ## Markup Schema example 6 | 7 | ```tsx 8 | import React from 'react' 9 | import { Checkbox, 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 | Checkbox, 16 | FormItem, 17 | }, 18 | }) 19 | 20 | const form = createForm() 21 | 22 | export default () => ( 23 | <FormProvider form={form}> 24 | <SchemaField> 25 | <SchemaField.Boolean 26 | name="single" 27 | title="Are you sure" 28 | x-decorator="FormItem" 29 | x-component="Checkbox" 30 | /> 31 | <SchemaField.String 32 | name="multiple" 33 | title="Check" 34 | enum={[ 35 | { 36 | label: 'Option 1', 37 | value: 1, 38 | }, 39 | { 40 | label: 'Option 2', 41 | value: 2, 42 | }, 43 | ]} 44 | x-decorator="FormItem" 45 | x-component="Checkbox.Group" 46 | /> 47 | </SchemaField> 48 | <FormButtonGroup> 49 | <Submit onSubmit={console.log}>Submit</Submit> 50 | </FormButtonGroup> 51 | </FormProvider> 52 | ) 53 | ``` 54 | 55 | ## JSON Schema case 56 | 57 | ```tsx 58 | import React from 'react' 59 | import { Checkbox, FormItem, FormButtonGroup, Submit } from '@formily/next' 60 | import { createForm } from '@formily/core' 61 | import { FormProvider, createSchemaField } from '@formily/react' 62 | 63 | const SchemaField = createSchemaField({ 64 | components: { 65 | Checkbox, 66 | FormItem, 67 | }, 68 | }) 69 | 70 | const form = createForm() 71 | 72 | const schema = { 73 | type: 'object', 74 | properties: { 75 | single: { 76 | type: 'boolean', 77 | title: 'Are you sure?', 78 | 'x-decorator': 'FormItem', 79 | 'x-component': 'Checkbox', 80 | }, 81 | multiple: { 82 | type: 'array', 83 | title: 'Check', 84 | enum: [ 85 | { 86 | label: 'Option 1', 87 | value: 1, 88 | }, 89 | { 90 | label: 'Option 2', 91 | value: 2, 92 | }, 93 | ], 94 | 'x-decorator': 'FormItem', 95 | 'x-component': 'Checkbox.Group', 96 | }, 97 | }, 98 | } 99 | 100 | export default () => ( 101 | <FormProvider form={form}> 102 | <SchemaField schema={schema} /> 103 | <FormButtonGroup> 104 | <Submit onSubmit={console.log}>Submit</Submit> 105 | </FormButtonGroup> 106 | </FormProvider> 107 | ) 108 | ``` 109 | 110 | ## Pure JSX case 111 | 112 | ```tsx 113 | import React from 'react' 114 | import { Checkbox, FormItem, FormButtonGroup, Submit } from '@formily/next' 115 | import { createForm } from '@formily/core' 116 | import { FormProvider, Field } from '@formily/react' 117 | 118 | const form = createForm() 119 | 120 | export default () => ( 121 | <FormProvider form={form}> 122 | <Field 123 | name="single" 124 | title="Are you sure" 125 | decorator={[FormItem]} 126 | component={[Checkbox]} 127 | /> 128 | <Field 129 | name="multiple" 130 | title="Check" 131 | dataSource={[ 132 | { 133 | label: 'Option 1', 134 | value: 1, 135 | }, 136 | { 137 | label: 'Option 2', 138 | value: 2, 139 | }, 140 | ]} 141 | decorator={[FormItem]} 142 | component={[Checkbox.Group]} 143 | /> 144 | <FormButtonGroup> 145 | <Submit onSubmit={console.log}>Submit</Submit> 146 | </FormButtonGroup> 147 | </FormProvider> 148 | ) 149 | ``` 150 | 151 | ## API 152 | 153 | Reference https://fusion.design/pc/component/basic/checkbox 154 | ``` -------------------------------------------------------------------------------- /packages/react/docs/api/components/RecordScope.md: -------------------------------------------------------------------------------- ```markdown 1 | --- 2 | order: 9 3 | --- 4 | 5 | # RecordScope 6 | 7 | ## Description 8 | 9 | Standard scoped injection component for injecting the following built-in variables: 10 | 11 | - `$record` current record data 12 | - `$record.$lookup` The parent record of the current record, you can always look up 13 | - `$record.$index` the index of the current record 14 | - `$index` The current record index, equivalent to `$record.$index`, considering that if the record data is not an object, it needs to be read independently 15 | - `$lookup` The parent record of the current record, equivalent to `$record.$lookup`, considering that if the record data is not an object, it needs to be read independently 16 | 17 | ## Signature 18 | 19 | ```ts 20 | interface IRecordScopeProps { 21 | getRecord(): any 22 | getIndex?(): number 23 | } 24 | 25 | type RecordScope = React.FC<React.PropsWithChildren<IRecordScopeProps>> 26 | ``` 27 | 28 | ## Usage 29 | 30 | Any auto-increment list extension component should use RecordScope internally to pass record scope variables. Components that have implemented this convention include: 31 | All components of the ArrayX family in @formily/antd and @formily/next 32 | 33 | ## Custom component extension use case 34 | 35 | ```tsx 36 | import React from 'react' 37 | import { createForm } from '@formily/core' 38 | import { FormProvider, createSchemaField, RecordScope } from '@formily/react' 39 | import { Input } from 'antd' 40 | 41 | const form = createForm() 42 | 43 | const MyCustomComponent = (props) => { 44 | return ( 45 | <RecordScope getRecord={() => props.record} getIndex={() => props.index}> 46 | {props.children} 47 | </RecordScope> 48 | ) 49 | } 50 | 51 | const SchemaField = createSchemaField({ 52 | components: { 53 | Input, 54 | MyCustomComponent, 55 | }, 56 | }) 57 | 58 | export default () => ( 59 | <FormProvider form={form}> 60 | <SchemaField 61 | schema={{ 62 | type: 'object', 63 | properties: { 64 | lookup: { 65 | type: 'void', 66 | 'x-component': 'MyCustomComponent', 67 | 'x-component-props': { 68 | record: { 69 | name: 'Lookup Name', 70 | code: 'Lookup Code', 71 | }, 72 | index: 1, 73 | }, 74 | properties: { 75 | record: { 76 | type: 'void', 77 | 'x-component': 'MyCustomComponent', 78 | 'x-component-props': { 79 | record: { 80 | name: 'Name', 81 | code: 'Code', 82 | }, 83 | index: 0, 84 | }, 85 | properties: { 86 | input: { 87 | type: 'string', 88 | 'x-component': 'Input', 89 | 'x-value': 90 | '{{`' + 91 | '${$record.name} ' + 92 | '${$record.code} ' + 93 | '${$record.$index} ' + 94 | '${$record.$lookup.name} ' + 95 | '${$record.$lookup.code} ' + 96 | '${$index} ' + 97 | '${$lookup.name} ' + 98 | '${$lookup.code} ' + 99 | '`}}', 100 | }, 101 | }, 102 | }, 103 | }, 104 | }, 105 | }, 106 | }} 107 | ></SchemaField> 108 | </FormProvider> 109 | ) 110 | ``` 111 | ``` -------------------------------------------------------------------------------- /packages/next/docs/components/Input.zh-CN.md: -------------------------------------------------------------------------------- ```markdown 1 | # Input 2 | 3 | > 文本输入框 4 | 5 | ## Markup Schema 案例 6 | 7 | ```tsx 8 | import React from 'react' 9 | import { Input, 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 | Input, 16 | FormItem, 17 | }, 18 | }) 19 | 20 | const form = createForm() 21 | 22 | export default () => ( 23 | <FormProvider form={form}> 24 | <SchemaField> 25 | <SchemaField.String 26 | name="input" 27 | title="输入框" 28 | x-decorator="FormItem" 29 | x-component="Input" 30 | required 31 | x-component-props={{ 32 | style: { 33 | width: 240, 34 | }, 35 | }} 36 | /> 37 | <SchemaField.String 38 | name="textarea" 39 | title="文本框" 40 | x-decorator="FormItem" 41 | required 42 | x-component="Input.TextArea" 43 | x-component-props={{ 44 | style: { 45 | width: 400, 46 | }, 47 | }} 48 | /> 49 | </SchemaField> 50 | <FormButtonGroup> 51 | <Submit onSubmit={console.log}>提交</Submit> 52 | </FormButtonGroup> 53 | </FormProvider> 54 | ) 55 | ``` 56 | 57 | ## JSON Schema 案例 58 | 59 | ```tsx 60 | import React from 'react' 61 | import { Input, FormItem, FormButtonGroup, Submit } from '@formily/next' 62 | import { createForm } from '@formily/core' 63 | import { FormProvider, createSchemaField } from '@formily/react' 64 | 65 | const SchemaField = createSchemaField({ 66 | components: { 67 | Input, 68 | FormItem, 69 | }, 70 | }) 71 | 72 | const form = createForm() 73 | 74 | const schema = { 75 | type: 'object', 76 | properties: { 77 | input: { 78 | type: 'string', 79 | title: '输入框', 80 | 'x-decorator': 'FormItem', 81 | 'x-component': 'Input', 82 | 'x-component-props': { 83 | style: { 84 | width: 240, 85 | }, 86 | }, 87 | }, 88 | textarea: { 89 | type: 'string', 90 | title: '输入框', 91 | 'x-decorator': 'FormItem', 92 | 'x-component': 'Input.TextArea', 93 | 'x-component-props': { 94 | style: { 95 | width: 240, 96 | }, 97 | }, 98 | }, 99 | }, 100 | } 101 | 102 | export default () => ( 103 | <FormProvider form={form}> 104 | <SchemaField schema={schema} /> 105 | <FormButtonGroup> 106 | <Submit onSubmit={console.log}>提交</Submit> 107 | </FormButtonGroup> 108 | </FormProvider> 109 | ) 110 | ``` 111 | 112 | ## 纯 JSX 案例 113 | 114 | ```tsx 115 | import React from 'react' 116 | import { Input, FormItem, FormButtonGroup, Submit } from '@formily/next' 117 | import { createForm } from '@formily/core' 118 | import { FormProvider, Field } from '@formily/react' 119 | 120 | const form = createForm() 121 | 122 | export default () => ( 123 | <FormProvider form={form}> 124 | <Field 125 | name="input" 126 | title="输入框" 127 | required 128 | decorator={[FormItem]} 129 | component={[ 130 | Input, 131 | { 132 | style: { 133 | width: 240, 134 | }, 135 | }, 136 | ]} 137 | /> 138 | <Field 139 | name="textarea" 140 | title="文本框" 141 | required 142 | decorator={[FormItem]} 143 | component={[ 144 | Input.TextArea, 145 | { 146 | style: { 147 | width: 400, 148 | }, 149 | }, 150 | ]} 151 | /> 152 | <FormButtonGroup> 153 | <Submit onSubmit={console.log}>提交</Submit> 154 | </FormButtonGroup> 155 | </FormProvider> 156 | ) 157 | ``` 158 | 159 | ## API 160 | 161 | 参考 https://fusion.design/pc/component/basic/input 162 | ``` -------------------------------------------------------------------------------- /docs/guide/advanced/build.md: -------------------------------------------------------------------------------- ```markdown 1 | # Pack on Demand 2 | 3 | ## Based on Umi Development 4 | 5 | #### Install `babel-plugin-import` 6 | 7 | ```shell 8 | npm install babel-plugin-import --save-dev 9 | ``` 10 | 11 | or 12 | 13 | ```shell 14 | yarn add babel-plugin-import --dev 15 | ``` 16 | 17 | #### Plugin Configuration 18 | 19 | Modify `.umirc.js` or `.umirc.ts` 20 | 21 | ```js 22 | export default { 23 | extraBabelPlugins: [ 24 | [ 25 | 'babel-plugin-import', 26 | { libraryName: 'antd', libraryDirectory: 'es', style: true }, 27 | 'antd', 28 | ], 29 | [ 30 | 'babel-plugin-import', 31 | { libraryName: '@formily/antd', libraryDirectory: 'esm', style: true }, 32 | '@formily/antd', 33 | ], 34 | ], 35 | } 36 | ``` 37 | 38 | ## Based on Create-react-app Development 39 | 40 | First, we need to customize the default configuration of `create-react-app`, here we use [react-app-rewired](https://github.com/timarney/react-app-rewired) (A community solution for custom configuration of `create-react-app`) 41 | Introduce `react-app-rewired` and modify the startup configuration in `package.json`. Due to the new [[email protected]](https://github.com/timarney/react-app-rewired#alternatives) version, you also need to install [customize-cra](https://github.com/arackaf/customize-cra). 42 | 43 | ```shell 44 | $ npm install react-app-rewired customize-cra --save-dev 45 | ``` 46 | 47 | or 48 | 49 | ```shell 50 | $ yarn add react-app-rewired customize-cra --dev 51 | ``` 52 | 53 | modify `package.json` 54 | 55 | ```diff 56 | "scripts": { 57 | - "start": "react-scripts start", 58 | + "start": "react-app-rewired start", 59 | - "build": "react-scripts build", 60 | + "build": "react-app-rewired build", 61 | - "test": "react-scripts test", 62 | + "test": "react-app-rewired test", 63 | } 64 | ``` 65 | 66 | Then create a `config-overrides.js` in the project root directory to modify the default configuration. 67 | 68 | ```js 69 | module.exports = function override(config, env) { 70 | // do stuff with the webpack config... 71 | return config 72 | } 73 | ``` 74 | 75 | #### Install babel-plugin-import 76 | 77 | ```shell 78 | npm install babel-plugin-import --save-dev 79 | ``` 80 | 81 | or 82 | 83 | ```shell 84 | yarn add babel-plugin-import --dev 85 | ``` 86 | 87 | modify `config-overrides.js` 88 | 89 | ```diff 90 | + const { override, fixBabelImports } = require('customize-cra'); 91 | 92 | - module.exports = function override(config, env) { 93 | - // do stuff with the webpack config... 94 | - return config; 95 | - }; 96 | + module.exports = override( 97 | + fixBabelImports('antd', { 98 | + libraryName: 'antd', 99 | + libraryDirectory: 'es', 100 | + style: true 101 | + }), 102 | + fixBabelImports('@formily/antd', { 103 | + libraryName: '@formily/antd', 104 | + libraryDirectory: 'esm', 105 | + style: true 106 | + }), 107 | + ); 108 | ``` 109 | 110 | ## Use in Webpack 111 | 112 | #### Install babel-plugin-import 113 | 114 | ```shell 115 | npm install babel-plugin-import --save-dev 116 | ``` 117 | 118 | or 119 | 120 | ```shell 121 | yarn add babel-plugin-import --dev 122 | ``` 123 | 124 | Modify `.babelrc` or babel-loader 125 | 126 | ```json 127 | { 128 | "plugins": [ 129 | [ 130 | "import", 131 | { 132 | "libraryName": "antd", 133 | "libraryDirectory": "es", 134 | "style": true 135 | }, 136 | "antd" 137 | ], 138 | [ 139 | "import", 140 | { 141 | "libraryName": "@formily/antd", 142 | "libraryDirectory": "esm", 143 | "style": true 144 | }, 145 | "@formily/antd" 146 | ] 147 | ] 148 | } 149 | ``` 150 | 151 | For more configuration, please refer to [babel-plugin-import](https://github.com/ant-design/babel-plugin-import) 152 | ``` -------------------------------------------------------------------------------- /packages/element/docs/demos/guide/form-collapse/json-schema.vue: -------------------------------------------------------------------------------- ```vue 1 | <template> 2 | <FormProvider :form="form"> 3 | <FormLayout :label-col="6" :wrapper-col="10"> 4 | <SchemaField :schema="schema" :scope="{ formCollapse }" /> 5 | <FormButtonGroup alignFormItem> 6 | <Button 7 | @click=" 8 | () => { 9 | form.query('tab3').take((field) => { 10 | field.visible = !field.visible 11 | }) 12 | } 13 | " 14 | > 15 | 显示/隐藏最后一个Tab 16 | </Button> 17 | <Button 18 | @click=" 19 | () => { 20 | formCollapse.toggleActiveKey('tab2') 21 | } 22 | " 23 | > 24 | 切换第二个Tab 25 | </Button> 26 | <Submit @submit="log">提交</Submit> 27 | </FormButtonGroup> 28 | </FormLayout> 29 | </FormProvider> 30 | </template> 31 | 32 | <script> 33 | import { createForm } from '@formily/core' 34 | import { FormProvider, createSchemaField } from '@formily/vue' 35 | import { 36 | FormItem, 37 | FormCollapse, 38 | FormButtonGroup, 39 | Form, 40 | FormLayout, 41 | Submit, 42 | Input, 43 | } from '@formily/element' 44 | import { Button } from 'element-ui' 45 | 46 | const { SchemaField } = createSchemaField({ 47 | components: { 48 | FormItem, 49 | FormCollapse, 50 | Input, 51 | }, 52 | }) 53 | 54 | const schema = { 55 | type: 'object', 56 | properties: { 57 | collapse: { 58 | type: 'void', 59 | title: '折叠面板', 60 | 'x-decorator': 'FormItem', 61 | 'x-component': 'FormCollapse', 62 | 'x-component-props': { 63 | formCollapse: '{{formCollapse}}', 64 | }, 65 | properties: { 66 | tab1: { 67 | type: 'void', 68 | 'x-component': 'FormCollapse.Item', 69 | 'x-component-props': { 70 | title: 'A1', 71 | }, 72 | properties: { 73 | aaa: { 74 | type: 'string', 75 | title: 'AAA', 76 | 'x-decorator': 'FormItem', 77 | required: true, 78 | 'x-component': 'Input', 79 | }, 80 | }, 81 | }, 82 | tab2: { 83 | type: 'void', 84 | 'x-component': 'FormCollapse.Item', 85 | 'x-component-props': { 86 | title: 'A2', 87 | }, 88 | properties: { 89 | bbb: { 90 | type: 'string', 91 | title: 'BBB', 92 | 'x-decorator': 'FormItem', 93 | required: true, 94 | 'x-component': 'Input', 95 | }, 96 | }, 97 | }, 98 | tab3: { 99 | type: 'void', 100 | 'x-component': 'FormCollapse.Item', 101 | 'x-component-props': { 102 | title: 'A3', 103 | }, 104 | properties: { 105 | ccc: { 106 | type: 'string', 107 | title: 'CCC', 108 | 'x-decorator': 'FormItem', 109 | required: true, 110 | 'x-component': 'Input', 111 | }, 112 | }, 113 | }, 114 | }, 115 | }, 116 | }, 117 | } 118 | 119 | export default { 120 | components: { 121 | Form, 122 | FormButtonGroup, 123 | Button, 124 | Submit, 125 | SchemaField, 126 | FormProvider, 127 | FormLayout, 128 | }, 129 | 130 | data() { 131 | const form = createForm() 132 | const formCollapse = FormCollapse.createFormCollapse() 133 | 134 | return { 135 | schema, 136 | form, 137 | formCollapse, 138 | } 139 | }, 140 | methods: { 141 | log(values) { 142 | console.log(values) 143 | }, 144 | }, 145 | } 146 | </script> 147 | 148 | <style lang="scss" scoped></style> 149 | ``` -------------------------------------------------------------------------------- /packages/element/docs/demos/guide/space/markup-schema.vue: -------------------------------------------------------------------------------- ```vue 1 | <template> 2 | <FormProvider :form="form"> 3 | <FormLayout :labelCol="6" :wrapperCol="16"> 4 | <SchemaField> 5 | <SchemaVoidField 6 | x-component="FormLayout" 7 | :x-component-props="{ 8 | labelCol: 6, 9 | wrapperCol: 10, 10 | }" 11 | > 12 | <SchemaVoidField 13 | title="姓名" 14 | x-decorator="FormItem" 15 | :x-decorator-props="{ 16 | asterisk: true, 17 | feedbackLayout: 'none', 18 | }" 19 | x-component="Space" 20 | > 21 | <SchemaStringField 22 | name="firstName" 23 | x-decorator="FormItem" 24 | x-component="Input" 25 | :required="true" 26 | /> 27 | <SchemaStringField 28 | name="lastName" 29 | x-decorator="FormItem" 30 | x-component="Input" 31 | :required="true" 32 | /> 33 | </SchemaVoidField> 34 | <SchemaVoidField 35 | title="文本串联" 36 | x-decorator="FormItem" 37 | :x-decorator-props="{ 38 | asterisk: true, 39 | feedbackLayout: 'none', 40 | }" 41 | x-component="Space" 42 | > 43 | <SchemaStringField 44 | name="aa" 45 | x-decorator="FormItem" 46 | x-component="Input" 47 | :x-decorator-props="{ 48 | addonAfter: '单位', 49 | }" 50 | :required="true" 51 | /> 52 | <SchemaStringField 53 | name="bb" 54 | x-decorator="FormItem" 55 | x-component="Input" 56 | :x-decorator-props="{ 57 | addonAfter: '单位', 58 | }" 59 | :required="true" 60 | /> 61 | <SchemaStringField 62 | name="cc" 63 | x-decorator="FormItem" 64 | x-component="Input" 65 | :x-decorator-props="{ 66 | addonAfter: '单位', 67 | }" 68 | :required="true" 69 | /> 70 | </SchemaVoidField> 71 | <SchemaStringField 72 | name="textarea" 73 | title="文本框" 74 | x-decorator="FormItem" 75 | :required="true" 76 | x-component="Input" 77 | :x-component-props="{ 78 | style: { 79 | width: 400, 80 | }, 81 | type: 'textarea', 82 | }" 83 | /> 84 | </SchemaVoidField> 85 | </SchemaField> 86 | <FormButtonGroup alignFormItem> 87 | <Submit onSubmit="log">提交</Submit> 88 | </FormButtonGroup> 89 | </FormLayout> 90 | </FormProvider> 91 | </template> 92 | 93 | <script> 94 | import { createForm } from '@formily/core' 95 | import { createSchemaField, FormProvider } from '@formily/vue' 96 | import { 97 | FormLayout, 98 | FormItem, 99 | Input, 100 | Space, 101 | FormButtonGroup, 102 | Submit, 103 | } from '@formily/element' 104 | 105 | const fields = createSchemaField({ 106 | components: { FormItem, FormLayout, Input, Space }, 107 | }) 108 | 109 | export default { 110 | components: { FormProvider, FormLayout, FormButtonGroup, Submit, ...fields }, 111 | data() { 112 | const form = createForm() 113 | return { 114 | form, 115 | } 116 | }, 117 | 118 | methods: { 119 | log(value) { 120 | console.log(value) 121 | }, 122 | }, 123 | } 124 | </script> 125 | ``` -------------------------------------------------------------------------------- /packages/react/docs/api/shared/observer.md: -------------------------------------------------------------------------------- ```markdown 1 | # observer 2 | 3 | ## observer 4 | 5 | ### Description 6 | 7 | The observer is a [HOC](https://reactjs.bootcss.com/docs/higher-order-components.html), which is used to add reactive features to react functional components. 8 | 9 | ### When to use 10 | 11 | When a component uses an [observable](https://reactive.formilyjs.org/api/observable) object inside, and you want the component to respond to changes in the observable object. 12 | 13 | ### API definition 14 | 15 | ```ts 16 | interface IObserverOptions { 17 | // Do you need observers to use forwardRef to pass ref attributes 18 | forwardRef?: boolean 19 | scheduler?: (updater: () => void) => void 20 | displayName?: string 21 | } 22 | 23 | function observer<P, Options extends IObserverOptions>( 24 | component: React.FunctionComponent<P>, 25 | options?: Options 26 | ): React.MemoExoticComponent< 27 | React.FunctionComponent< 28 | Options extends { forwardRef: true } 29 | ? React.PropsWithRef<P> 30 | : React.PropsWithoutRef<P> 31 | > 32 | > 33 | ``` 34 | 35 | ### Example 36 | 37 | ```tsx 38 | /** 39 | * defaultShowCode: true 40 | */ 41 | import React from 'react' 42 | import { observable } from '@formily/reactive' 43 | import { observer } from '@formily/reactive-react' 44 | 45 | const obs = observable({ 46 | value: 'Hello world', 47 | }) 48 | 49 | export default observer(() => { 50 | return ( 51 | <div> 52 | <div> 53 | <input 54 | style={{ 55 | height: 28, 56 | padding: '0 8px', 57 | border: '2px solid #888', 58 | borderRadius: 3, 59 | }} 60 | value={obs.value} 61 | onChange={(e) => { 62 | obs.value = e.target.value 63 | }} 64 | /> 65 | </div> 66 | <div>{obs.value}</div> 67 | </div> 68 | ) 69 | }) 70 | ``` 71 | 72 | ### Note 73 | 74 | `observer` can only receive callable function components, and does not support packaged components such as `React.forwardRef` | `React.memo`. 75 | 76 | ## Observer 77 | 78 | ### Description 79 | 80 | Similar to Vue's responsive slot, it receives a Function RenderProps, as long as any responsive data consumed inside the Function, it will be automatically re-rendered as the data changes, and it is easier to achieve local accurate rendering 81 | 82 | In fact, the function of this API is basically the same as that of FormConsumer, except that FormConsumer reveals the form instance of the current context in the RenderProps parameter. 83 | 84 | ### Signature 85 | 86 | ```ts 87 | interface IObserverProps { 88 | children?: () => React.ReactElement 89 | } 90 | 91 | type Observer = React.FC<React.PropsWithChildren<IObserverProps>> 92 | ``` 93 | 94 | ### Example 95 | 96 | ```tsx 97 | /** 98 | * defaultShowCode: true 99 | */ 100 | import React from 'react' 101 | import { observable } from '@formily/reactive' 102 | import { Observer } from '@formily/react' 103 | 104 | const obs = observable({ 105 | value: 'Hello world', 106 | }) 107 | 108 | export default () => { 109 | return ( 110 | <div> 111 | <div> 112 | <Observer> 113 | {() => ( 114 | <input 115 | style={{ 116 | height: 28, 117 | padding: '0 8px', 118 | border: '2px solid #888', 119 | borderRadius: 3, 120 | }} 121 | value={obs.value} 122 | onChange={(e) => { 123 | obs.value = e.target.value 124 | }} 125 | /> 126 | )} 127 | </Observer> 128 | </div> 129 | <Observer>{() => <div>{obs.value}</div>}</Observer> 130 | </div> 131 | ) 132 | } 133 | ``` 134 | ``` -------------------------------------------------------------------------------- /packages/react/src/__tests__/expression.spec.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import React from 'react' 2 | import { render, waitFor } from '@testing-library/react' 3 | import { createForm } from '@formily/core' 4 | import { 5 | FormProvider, 6 | ExpressionScope, 7 | createSchemaField, 8 | useField, 9 | Field, 10 | } from '..' 11 | 12 | test('expression scope', async () => { 13 | const Container = (props) => { 14 | return ( 15 | <ExpressionScope value={{ $innerScope: 'this is inner scope value' }}> 16 | {props.children} 17 | </ExpressionScope> 18 | ) 19 | } 20 | const Input = (props) => <div data-testid="test-input">{props.value}</div> 21 | const SchemaField = createSchemaField({ 22 | components: { 23 | Container, 24 | Input, 25 | }, 26 | }) 27 | const form = createForm() 28 | const { getByTestId } = render( 29 | <FormProvider form={form}> 30 | <SchemaField scope={{ $outerScope: 'this is outer scope value' }}> 31 | <SchemaField.Void x-component="Container"> 32 | <SchemaField.String 33 | name="input" 34 | x-component="Input" 35 | x-value="{{$innerScope + ' ' + $outerScope}}" 36 | /> 37 | </SchemaField.Void> 38 | </SchemaField> 39 | </FormProvider> 40 | ) 41 | 42 | expect(getByTestId('test-input').textContent).toBe( 43 | 'this is inner scope value this is outer scope value' 44 | ) 45 | }) 46 | 47 | test('x-compile-omitted', async () => { 48 | const form = createForm() 49 | const SchemaField = createSchemaField({ 50 | components: { 51 | Input: (props) => ( 52 | <div data-testid="input"> 53 | {props.aa} 54 | {useField().title} 55 | {props.extra} 56 | </div> 57 | ), 58 | }, 59 | }) 60 | 61 | const { queryByTestId } = render( 62 | <FormProvider form={form}> 63 | <SchemaField> 64 | <SchemaField.String 65 | name="target" 66 | x-compile-omitted={['x-component-props']} 67 | title="{{123 + '321'}}" 68 | x-component-props={{ 69 | aa: '{{fake}}', 70 | extra: 'extra', 71 | }} 72 | x-component="Input" 73 | /> 74 | <SchemaField.String name="btn" x-component="Button" /> 75 | </SchemaField> 76 | </FormProvider> 77 | ) 78 | await waitFor(() => { 79 | expect(queryByTestId('input')?.textContent).toBe('{{fake}}123321extra') 80 | }) 81 | }) 82 | 83 | test('field hidden & visible', async () => { 84 | const form = createForm({ initialValues: { empty: null } }) 85 | const { findByTestId } = render( 86 | <FormProvider form={form}> 87 | <div data-testid="testid"> 88 | <Field name="empty" component={['input']} /> 89 | </div> 90 | </FormProvider> 91 | ) 92 | await findByTestId('testid') 93 | // 94 | expect(form.fields.empty.hidden).toBe(false) 95 | expect(form.fields.empty.value).toBe(null) 96 | form.fields.empty.hidden = true 97 | expect(form.fields.empty.hidden).toBe(true) 98 | expect(form.fields.empty.value).toBe(null) 99 | form.fields.empty.hidden = false 100 | expect(form.fields.empty.hidden).toBe(false) 101 | expect(form.fields.empty.value).toBe(null) 102 | // 103 | expect(form.fields.empty.visible).toBe(true) 104 | expect(form.fields.empty.value).toBe(null) 105 | form.fields.empty.visible = false 106 | expect(form.fields.empty.visible).toBe(false) 107 | expect(form.fields.empty.value).toBe(undefined) 108 | form.fields.empty.visible = true 109 | expect(form.fields.empty.visible).toBe(true) 110 | expect(form.fields.empty.value).toBe(null) 111 | }) 112 | ``` -------------------------------------------------------------------------------- /packages/antd/docs/components/Submit.zh-CN.md: -------------------------------------------------------------------------------- ```markdown 1 | # Submit 2 | 3 | > 提交按钮 4 | 5 | ## 普通提交 6 | 7 | ```tsx 8 | import React from 'react' 9 | import { Input, FormItem, FormButtonGroup, Submit } from '@formily/antd' 10 | import { createForm } from '@formily/core' 11 | import { FormProvider, createSchemaField } from '@formily/react' 12 | 13 | const SchemaField = createSchemaField({ 14 | components: { 15 | Input, 16 | FormItem, 17 | }, 18 | }) 19 | 20 | const form = createForm() 21 | 22 | export default () => ( 23 | <FormProvider form={form}> 24 | <SchemaField> 25 | <SchemaField.String 26 | name="input" 27 | title="输入框" 28 | required 29 | x-decorator="FormItem" 30 | x-component="Input" 31 | /> 32 | <SchemaField.String 33 | name="input2" 34 | title="输入框" 35 | default="123" 36 | required 37 | x-decorator="FormItem" 38 | x-component="Input" 39 | /> 40 | </SchemaField> 41 | <FormButtonGroup> 42 | <Submit onSubmit={console.log}>提交</Submit> 43 | </FormButtonGroup> 44 | </FormProvider> 45 | ) 46 | ``` 47 | 48 | ## 防重复提交(Loading) 49 | 50 | ```tsx 51 | import React from 'react' 52 | import { Input, FormItem, FormButtonGroup, Submit } from '@formily/antd' 53 | import { createForm } from '@formily/core' 54 | import { FormProvider, createSchemaField } from '@formily/react' 55 | 56 | const SchemaField = createSchemaField({ 57 | components: { 58 | Input, 59 | FormItem, 60 | }, 61 | }) 62 | 63 | const form = createForm() 64 | 65 | export default () => ( 66 | <FormProvider form={form}> 67 | <SchemaField> 68 | <SchemaField.String 69 | name="input" 70 | title="输入框" 71 | required 72 | x-decorator="FormItem" 73 | x-component="Input" 74 | /> 75 | <SchemaField.String 76 | name="input2" 77 | title="输入框" 78 | default="123" 79 | required 80 | x-decorator="FormItem" 81 | x-component="Input" 82 | /> 83 | </SchemaField> 84 | <FormButtonGroup> 85 | <Submit 86 | onSubmit={(values) => { 87 | return new Promise((resolve) => { 88 | setTimeout(() => { 89 | console.log(values) 90 | resolve() 91 | }, 2000) 92 | }) 93 | }} 94 | onSubmitFailed={console.log} 95 | > 96 | 提交 97 | </Submit> 98 | </FormButtonGroup> 99 | </FormProvider> 100 | ) 101 | ``` 102 | 103 | ## API 104 | 105 | 按钮相关的 API 属性,我们参考 https://ant.design/components/button-cn/ 即可,剩下是 Submit 组件独有的 API 属性 106 | 107 | | 属性名 | 类型 | 描述 | 默认值 | 108 | | --------------- | ------------------------------------------------------------------------------------------------------ | ------------------------------------- | ------ | 109 | | onClick | `(event: MouseEvent) => void \| boolean` | 点击事件,如果返回 false 可以阻塞提交 | - | 110 | | onSubmit | `(values: any) => Promise<any> \| any` | 提交事件回调 | - | 111 | | onSubmitSuccess | (payload: any) => void | 提交成功响应事件 | - | 112 | | onSubmitFailed | (feedbacks: [IFormFeedback](https://core.formilyjs.org/zh-CN/api/models/form#iformfeedback)[]) => void | 提交校验失败事件回调 | - | 113 | ``` -------------------------------------------------------------------------------- /packages/next/docs/components/Submit.zh-CN.md: -------------------------------------------------------------------------------- ```markdown 1 | # Submit 2 | 3 | > 提交按钮 4 | 5 | ## 普通提交 6 | 7 | ```tsx 8 | import React from 'react' 9 | import { Input, 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 | Input, 16 | FormItem, 17 | }, 18 | }) 19 | 20 | const form = createForm() 21 | 22 | export default () => ( 23 | <FormProvider form={form}> 24 | <SchemaField> 25 | <SchemaField.String 26 | name="input" 27 | title="输入框" 28 | required 29 | x-decorator="FormItem" 30 | x-component="Input" 31 | /> 32 | <SchemaField.String 33 | name="input2" 34 | title="输入框" 35 | default="123" 36 | required 37 | x-decorator="FormItem" 38 | x-component="Input" 39 | /> 40 | </SchemaField> 41 | <FormButtonGroup> 42 | <Submit onSubmit={console.log}>提交</Submit> 43 | </FormButtonGroup> 44 | </FormProvider> 45 | ) 46 | ``` 47 | 48 | ## 防重复提交(Loading) 49 | 50 | ```tsx 51 | import React from 'react' 52 | import { Input, FormItem, FormButtonGroup, Submit } from '@formily/next' 53 | import { createForm } from '@formily/core' 54 | import { FormProvider, createSchemaField } from '@formily/react' 55 | 56 | const SchemaField = createSchemaField({ 57 | components: { 58 | Input, 59 | FormItem, 60 | }, 61 | }) 62 | 63 | const form = createForm() 64 | 65 | export default () => ( 66 | <FormProvider form={form}> 67 | <SchemaField> 68 | <SchemaField.String 69 | name="input" 70 | title="输入框" 71 | required 72 | x-decorator="FormItem" 73 | x-component="Input" 74 | /> 75 | <SchemaField.String 76 | name="input2" 77 | title="输入框" 78 | default="123" 79 | required 80 | x-decorator="FormItem" 81 | x-component="Input" 82 | /> 83 | </SchemaField> 84 | <FormButtonGroup> 85 | <Submit 86 | onSubmit={(values) => { 87 | return new Promise((resolve) => { 88 | setTimeout(() => { 89 | console.log(values) 90 | resolve() 91 | }, 2000) 92 | }) 93 | }} 94 | onSubmitFailed={console.log} 95 | > 96 | 提交 97 | </Submit> 98 | </FormButtonGroup> 99 | </FormProvider> 100 | ) 101 | ``` 102 | 103 | ## API 104 | 105 | 按钮相关的 API 属性,我们参考 https://fusion.design/pc/component/basic/button 即可,剩下是 Submit 组件独有的 API 属性 106 | 107 | | 属性名 | 类型 | 描述 | 默认值 | 108 | | --------------- | ------------------------------------------------------------------------------------------------------ | ------------------------------------- | ------ | 109 | | onClick | `(event: MouseEvent) => void \| boolean` | 点击事件,如果返回 false 可以阻塞提交 | - | 110 | | onSubmit | `(values: any) => Promise<any> \| any` | 提交事件回调 | - | 111 | | onSubmitSuccess | (payload: any) => void | 提交成功响应事件 | - | 112 | | onSubmitFailed | (feedbacks: [IFormFeedback](https://core.formilyjs.org/zh-CN/api/models/form#iformfeedback)[]) => void | 提交校验失败事件回调 | - | 113 | ``` -------------------------------------------------------------------------------- /packages/antd/docs/components/Input.md: -------------------------------------------------------------------------------- ```markdown 1 | # Input 2 | 3 | > Text input box 4 | 5 | ## Markup Schema example 6 | 7 | ```tsx 8 | import React from 'react' 9 | import { Input, FormItem, FormButtonGroup, Submit } from '@formily/antd' 10 | import { createForm } from '@formily/core' 11 | import { FormProvider, createSchemaField } from '@formily/react' 12 | 13 | const SchemaField = createSchemaField({ 14 | components: { 15 | Input, 16 | FormItem, 17 | }, 18 | }) 19 | 20 | const form = createForm() 21 | 22 | export default () => ( 23 | <FormProvider form={form}> 24 | <SchemaField> 25 | <SchemaField.String 26 | name="input" 27 | title="input box" 28 | x-decorator="FormItem" 29 | x-component="Input" 30 | required 31 | x-component-props={{ 32 | style: { 33 | width: 240, 34 | }, 35 | }} 36 | /> 37 | <SchemaField.String 38 | name="textarea" 39 | title="text box" 40 | x-decorator="FormItem" 41 | required 42 | x-component="Input.TextArea" 43 | x-component-props={{ 44 | style: { 45 | width: 400, 46 | }, 47 | }} 48 | /> 49 | </SchemaField> 50 | <FormButtonGroup> 51 | <Submit onSubmit={console.log}>Submit</Submit> 52 | </FormButtonGroup> 53 | </FormProvider> 54 | ) 55 | ``` 56 | 57 | ## JSON Schema case 58 | 59 | ```tsx 60 | import React from 'react' 61 | import { Input, FormItem, FormButtonGroup, Submit } from '@formily/antd' 62 | import { createForm } from '@formily/core' 63 | import { FormProvider, createSchemaField } from '@formily/react' 64 | 65 | const SchemaField = createSchemaField({ 66 | components: { 67 | Input, 68 | FormItem, 69 | }, 70 | }) 71 | 72 | const form = createForm() 73 | 74 | const schema = { 75 | type: 'object', 76 | properties: { 77 | input: { 78 | type: 'string', 79 | title: 'input box', 80 | 'x-decorator': 'FormItem', 81 | 'x-component': 'Input', 82 | 'x-component-props': { 83 | style: { 84 | width: 240, 85 | }, 86 | }, 87 | }, 88 | textarea: { 89 | type: 'string', 90 | title: 'input box', 91 | 'x-decorator': 'FormItem', 92 | 'x-component': 'Input.TextArea', 93 | 'x-component-props': { 94 | style: { 95 | width: 240, 96 | }, 97 | }, 98 | }, 99 | }, 100 | } 101 | 102 | export default () => ( 103 | <FormProvider form={form}> 104 | <SchemaField schema={schema} /> 105 | <FormButtonGroup> 106 | <Submit onSubmit={console.log}>Submit</Submit> 107 | </FormButtonGroup> 108 | </FormProvider> 109 | ) 110 | ``` 111 | 112 | ## Pure JSX case 113 | 114 | ```tsx 115 | import React from 'react' 116 | import { Input, FormItem, FormButtonGroup, Submit } from '@formily/antd' 117 | import { createForm } from '@formily/core' 118 | import { FormProvider, Field } from '@formily/react' 119 | 120 | const form = createForm() 121 | 122 | export default () => ( 123 | <FormProvider form={form}> 124 | <Field 125 | name="input" 126 | title="input box" 127 | required 128 | decorator={[FormItem]} 129 | component={[ 130 | Input, 131 | { 132 | style: { 133 | width: 240, 134 | }, 135 | }, 136 | ]} 137 | /> 138 | <Field 139 | name="textarea" 140 | title="text box" 141 | required 142 | decorator={[FormItem]} 143 | component={[ 144 | Input.TextArea, 145 | { 146 | style: { 147 | width: 400, 148 | }, 149 | }, 150 | ]} 151 | /> 152 | <FormButtonGroup> 153 | <Submit onSubmit={console.log}>Submit</Submit> 154 | </FormButtonGroup> 155 | </FormProvider> 156 | ) 157 | ``` 158 | 159 | ## API 160 | 161 | Reference https://ant.design/components/input-cn/ 162 | ``` -------------------------------------------------------------------------------- /packages/next/docs/components/Input.md: -------------------------------------------------------------------------------- ```markdown 1 | # Input 2 | 3 | > Text input box 4 | 5 | ## Markup Schema example 6 | 7 | ```tsx 8 | import React from 'react' 9 | import { Input, 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 | Input, 16 | FormItem, 17 | }, 18 | }) 19 | 20 | const form = createForm() 21 | 22 | export default () => ( 23 | <FormProvider form={form}> 24 | <SchemaField> 25 | <SchemaField.String 26 | name="input" 27 | title="input box" 28 | x-decorator="FormItem" 29 | x-component="Input" 30 | required 31 | x-component-props={{ 32 | style: { 33 | width: 240, 34 | }, 35 | }} 36 | /> 37 | <SchemaField.String 38 | name="textarea" 39 | title="text box" 40 | x-decorator="FormItem" 41 | required 42 | x-component="Input.TextArea" 43 | x-component-props={{ 44 | style: { 45 | width: 400, 46 | }, 47 | }} 48 | /> 49 | </SchemaField> 50 | <FormButtonGroup> 51 | <Submit onSubmit={console.log}>Submit</Submit> 52 | </FormButtonGroup> 53 | </FormProvider> 54 | ) 55 | ``` 56 | 57 | ## JSON Schema case 58 | 59 | ```tsx 60 | import React from 'react' 61 | import { Input, FormItem, FormButtonGroup, Submit } from '@formily/next' 62 | import { createForm } from '@formily/core' 63 | import { FormProvider, createSchemaField } from '@formily/react' 64 | 65 | const SchemaField = createSchemaField({ 66 | components: { 67 | Input, 68 | FormItem, 69 | }, 70 | }) 71 | 72 | const form = createForm() 73 | 74 | const schema = { 75 | type: 'object', 76 | properties: { 77 | input: { 78 | type: 'string', 79 | title: 'input box', 80 | 'x-decorator': 'FormItem', 81 | 'x-component': 'Input', 82 | 'x-component-props': { 83 | style: { 84 | width: 240, 85 | }, 86 | }, 87 | }, 88 | textarea: { 89 | type: 'string', 90 | title: 'input box', 91 | 'x-decorator': 'FormItem', 92 | 'x-component': 'Input.TextArea', 93 | 'x-component-props': { 94 | style: { 95 | width: 240, 96 | }, 97 | }, 98 | }, 99 | }, 100 | } 101 | 102 | export default () => ( 103 | <FormProvider form={form}> 104 | <SchemaField schema={schema} /> 105 | <FormButtonGroup> 106 | <Submit onSubmit={console.log}>Submit</Submit> 107 | </FormButtonGroup> 108 | </FormProvider> 109 | ) 110 | ``` 111 | 112 | ## Pure JSX case 113 | 114 | ```tsx 115 | import React from 'react' 116 | import { Input, FormItem, FormButtonGroup, Submit } from '@formily/next' 117 | import { createForm } from '@formily/core' 118 | import { FormProvider, Field } from '@formily/react' 119 | 120 | const form = createForm() 121 | 122 | export default () => ( 123 | <FormProvider form={form}> 124 | <Field 125 | name="input" 126 | title="input box" 127 | required 128 | decorator={[FormItem]} 129 | component={[ 130 | Input, 131 | { 132 | style: { 133 | width: 240, 134 | }, 135 | }, 136 | ]} 137 | /> 138 | <Field 139 | name="textarea" 140 | title="text box" 141 | required 142 | decorator={[FormItem]} 143 | component={[ 144 | Input.TextArea, 145 | { 146 | style: { 147 | width: 400, 148 | }, 149 | }, 150 | ]} 151 | /> 152 | <FormButtonGroup> 153 | <Submit onSubmit={console.log}>Submit</Submit> 154 | </FormButtonGroup> 155 | </FormProvider> 156 | ) 157 | ``` 158 | 159 | ## API 160 | 161 | Reference https://fusion.design/pc/component/basic/input 162 | ```