This is page 8 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/element/package.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "name": "@formily/element", 3 | "version": "2.3.7", 4 | "license": "MIT", 5 | "main": "lib", 6 | "module": "esm", 7 | "umd:main": "dist/formily.element.umd.production.js", 8 | "unpkg": "dist/formily.element.umd.production.js", 9 | "jsdelivr": "dist/formily.element.umd.production.js", 10 | "jsnext:main": "esm", 11 | "types": "lib/index.d.ts", 12 | "engines": { 13 | "npm": ">=3.0.0" 14 | }, 15 | "sideEffects": [ 16 | "dist/*", 17 | "esm/*.js", 18 | "lib/*.js", 19 | "src/*.ts", 20 | "*.scss" 21 | ], 22 | "scripts": { 23 | "start": "vuepress dev docs", 24 | "build": "rimraf -rf lib esm dist && npm run create:style && npm run build:cjs && npm run build:esm && npm run build:umd && npm run build:style", 25 | "create:style": "ts-node create-style", 26 | "build:style": "ts-node build-style", 27 | "build:cjs": "ttsc --declaration", 28 | "build:esm": "ttsc --declaration --module es2015 --outDir esm", 29 | "build:umd": "rollup --config", 30 | "build:docs": "vuepress build docs" 31 | }, 32 | "devDependencies": { 33 | "@vue/composition-api": "^1.0.0-rc.7", 34 | "@vuepress-dumi/vuepress-plugin-dumi-previewer": "0.3.3", 35 | "@vuepress-dumi/vuepress-theme-dumi": "0.3.3", 36 | "@vuepress/plugin-back-to-top": "^1.8.2", 37 | "@vuepress/plugin-medium-zoom": "^1.8.2", 38 | "codesandbox": "^2.2.3", 39 | "core-js": "^2.4.0", 40 | "element-ui": "^2.15.7", 41 | "sass": "^1.34.1", 42 | "ts-import-plugin": "^2.0.0", 43 | "ttypescript": "^1.5.15", 44 | "vue": "^2.6.0", 45 | "vuepress": "^1.8.2", 46 | "vuepress-plugin-typescript": "^0.3.1" 47 | }, 48 | "dependencies": { 49 | "@formily/core": "2.3.7", 50 | "@formily/grid": "2.3.7", 51 | "@formily/json-schema": "2.3.7", 52 | "@formily/reactive": "2.3.7", 53 | "@formily/reactive-vue": "2.3.7", 54 | "@formily/shared": "2.3.7", 55 | "@formily/vue": "2.3.7", 56 | "portal-vue": "^2.1.7", 57 | "vue-demi": ">=0.13.6", 58 | "vue-slicksort": "^1.2.0" 59 | }, 60 | "peerDependencies": { 61 | "@vue/composition-api": "^1.0.0-beta.1", 62 | "element-ui": "^2.14.0", 63 | "vue": "^2.6.0" 64 | }, 65 | "peerDependenciesMeta": { 66 | "@vue/composition-api": { 67 | "optional": true 68 | } 69 | }, 70 | "publishConfig": { 71 | "access": "public" 72 | }, 73 | "gitHead": "ac79c196ae9324889aca5e0501146f9b37b04283" 74 | } 75 | ``` -------------------------------------------------------------------------------- /packages/element/docs/demos/guide/date-picker/template.vue: -------------------------------------------------------------------------------- ```vue 1 | <template> 2 | <Form :form="form"> 3 | <Field 4 | name="date" 5 | title="普通日期" 6 | :decorator="[FormItem]" 7 | :component="[DatePicker]" 8 | /> 9 | <Field 10 | name="week" 11 | title="周" 12 | :decorator="[FormItem]" 13 | :component="[ 14 | DatePicker, 15 | { 16 | type: 'week', 17 | }, 18 | ]" 19 | /> 20 | <Field 21 | name="month" 22 | title="月" 23 | :decorator="[FormItem]" 24 | :component="[ 25 | DatePicker, 26 | { 27 | type: 'month', 28 | }, 29 | ]" 30 | /> 31 | <Field 32 | name="year" 33 | title="年" 34 | :decorator="[FormItem]" 35 | :component="[ 36 | DatePicker, 37 | { 38 | type: 'year', 39 | }, 40 | ]" 41 | /> 42 | <Field 43 | name="dateTime" 44 | title="日期时间" 45 | :decorator="[FormItem]" 46 | :component="[ 47 | DatePicker, 48 | { 49 | type: 'datetime', 50 | }, 51 | ]" 52 | /> 53 | <ArrayField 54 | name="dates" 55 | title="多个日期" 56 | :decorator="[FormItem]" 57 | :component="[ 58 | DatePicker, 59 | { 60 | type: 'dates', 61 | }, 62 | ]" 63 | /> 64 | <ArrayField 65 | name="dateRange" 66 | title="日期范围" 67 | :decorator="[FormItem]" 68 | :component="[ 69 | DatePicker, 70 | { 71 | type: 'daterange', 72 | }, 73 | ]" 74 | /> 75 | <ArrayField 76 | name="monthRange" 77 | title="月范围" 78 | :decorator="[FormItem]" 79 | :component="[ 80 | DatePicker, 81 | { 82 | type: 'monthrange', 83 | }, 84 | ]" 85 | /> 86 | <ArrayField 87 | name="dateTimeRange" 88 | title="日期时间范围" 89 | :decorator="[FormItem]" 90 | :component="[ 91 | DatePicker, 92 | { 93 | type: 'datetimerange', 94 | }, 95 | ]" 96 | /> 97 | <Submit @submit="onSubmit">提交</Submit> 98 | </Form> 99 | </template> 100 | 101 | <script> 102 | import { createForm } from '@formily/core' 103 | import { Field, ArrayField } from '@formily/vue' 104 | import { Form, FormItem, DatePicker, Submit } from '@formily/element' 105 | 106 | const form = createForm() 107 | 108 | export default { 109 | components: { Form, Field, ArrayField, Submit }, 110 | data() { 111 | return { 112 | FormItem, 113 | DatePicker, 114 | form, 115 | } 116 | }, 117 | methods: { 118 | onSubmit(value) { 119 | console.log(value) 120 | }, 121 | }, 122 | } 123 | </script> 124 | ``` -------------------------------------------------------------------------------- /packages/antd/package.json: -------------------------------------------------------------------------------- ```json 1 | { 2 | "name": "@formily/antd", 3 | "version": "2.3.7", 4 | "license": "MIT", 5 | "main": "lib", 6 | "module": "esm", 7 | "umd:main": "dist/formily.antd.umd.production.js", 8 | "unpkg": "dist/formily.antd.umd.production.js", 9 | "jsdelivr": "dist/formily.antd.umd.production.js", 10 | "jsnext:main": "esm", 11 | "sideEffects": [ 12 | "dist/*", 13 | "esm/*.js", 14 | "lib/*.js", 15 | "src/*.ts", 16 | "*.less", 17 | "**/*/style.js" 18 | ], 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/alibaba/formily.git" 22 | }, 23 | "types": "esm/index.d.ts", 24 | "bugs": { 25 | "url": "https://github.com/alibaba/formily/issues" 26 | }, 27 | "homepage": "https://github.com/alibaba/formily#readme", 28 | "engines": { 29 | "npm": ">=3.0.0" 30 | }, 31 | "scripts": { 32 | "start": "dumi dev", 33 | "build": "rimraf -rf lib esm dist && npm run create:style && npm run build:cjs && npm run build:esm && npm run build:umd && npm run build:style", 34 | "create:style": "ts-node create-style", 35 | "build:style": "ts-node build-style", 36 | "build:cjs": "tsc --project tsconfig.build.json", 37 | "build:esm": "tsc --project tsconfig.build.json --module es2015 --outDir esm", 38 | "build:umd": "rollup --config", 39 | "build:docs": "dumi build" 40 | }, 41 | "devDependencies": { 42 | "@umijs/plugin-sass": "^1.1.1", 43 | "dumi": "^1.1.0-rc.8" 44 | }, 45 | "peerDependencies": { 46 | "@ant-design/icons": "4.x", 47 | "@types/react": ">=16.8.0", 48 | "@types/react-dom": ">=16.8.0", 49 | "antd": "<=4.22.8", 50 | "react": ">=16.8.0", 51 | "react-dom": ">=16.8.0", 52 | "react-is": ">=16.8.0" 53 | }, 54 | "peerDependenciesMeta": { 55 | "@types/react": { 56 | "optional": true 57 | }, 58 | "@types/react-dom": { 59 | "optional": true 60 | } 61 | }, 62 | "dependencies": { 63 | "@dnd-kit/core": "^6.0.0", 64 | "@dnd-kit/sortable": "^7.0.0", 65 | "@formily/core": "2.3.7", 66 | "@formily/grid": "2.3.7", 67 | "@formily/json-schema": "2.3.7", 68 | "@formily/react": "2.3.7", 69 | "@formily/reactive": "2.3.7", 70 | "@formily/reactive-react": "2.3.7", 71 | "@formily/shared": "2.3.7", 72 | "classnames": "^2.2.6", 73 | "react-sticky-box": "^0.9.3" 74 | }, 75 | "publishConfig": { 76 | "access": "public" 77 | }, 78 | "gitHead": "ac79c196ae9324889aca5e0501146f9b37b04283" 79 | } 80 | ``` -------------------------------------------------------------------------------- /packages/element/docs/demos/guide/select/template-async.vue: -------------------------------------------------------------------------------- ```vue 1 | <template> 2 | <Form :form="form"> 3 | <Field 4 | name="linkage" 5 | title="联动选择框" 6 | :decorator="[FormItem]" 7 | :component="[ 8 | Select, 9 | { 10 | style: { 11 | width: '240px', 12 | }, 13 | }, 14 | ]" 15 | :dataSource="[ 16 | { label: '发请求1', value: 1 }, 17 | { label: '发请求2', value: 2 }, 18 | ]" 19 | /> 20 | <Field 21 | name="select" 22 | title="异步选择框" 23 | :decorator="[FormItem]" 24 | :component="[ 25 | Select, 26 | { 27 | style: { 28 | width: '240px', 29 | }, 30 | }, 31 | ]" 32 | /> 33 | <Submit @submit="onSubmit">提交</Submit> 34 | </Form> 35 | </template> 36 | 37 | <script> 38 | import { createForm, onFieldReact } from '@formily/core' 39 | import { Field } from '@formily/vue' 40 | import { action } from '@formily/reactive' 41 | import { Form, FormItem, Select, Submit, Reset } from '@formily/element' 42 | 43 | const useAsyncDataSource = (pattern, service) => { 44 | onFieldReact(pattern, (field) => { 45 | field.loading = true 46 | service(field).then( 47 | action.bound((data) => { 48 | field.dataSource = data 49 | field.loading = false 50 | }) 51 | ) 52 | }) 53 | } 54 | 55 | const form = createForm({ 56 | effects: () => { 57 | useAsyncDataSource('select', async (field) => { 58 | const linkage = field.query('linkage').get('value') 59 | if (!linkage) return [] 60 | 61 | return new Promise((resolve) => { 62 | setTimeout(() => { 63 | if (linkage === 1) { 64 | resolve([ 65 | { 66 | label: 'AAA', 67 | value: 'aaa', 68 | }, 69 | { 70 | label: 'BBB', 71 | value: 'ccc', 72 | }, 73 | ]) 74 | } else if (linkage === 2) { 75 | resolve([ 76 | { 77 | label: 'CCC', 78 | value: 'ccc', 79 | }, 80 | { 81 | label: 'DDD', 82 | value: 'ddd', 83 | }, 84 | ]) 85 | } 86 | }, 1500) 87 | }) 88 | }) 89 | }, 90 | }) 91 | 92 | export default { 93 | components: { Form, Field, Submit, Reset }, 94 | data() { 95 | return { 96 | form, 97 | FormItem, 98 | Select, 99 | } 100 | }, 101 | methods: { 102 | onSubmit(value) { 103 | console.log(value) 104 | }, 105 | }, 106 | } 107 | </script> 108 | ``` -------------------------------------------------------------------------------- /packages/antd/src/select-table/useFilterOptions.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import * as React from 'react' 2 | import { isFn, isArr } from '@formily/shared' 3 | 4 | type IFilterOption = boolean | ((option: any, keyword: string) => boolean) 5 | 6 | function includes(test: React.ReactNode, search: string) { 7 | return toArray(test).join('').toUpperCase().includes(search) 8 | } 9 | 10 | function includesOption(option: any, search: string) { 11 | const searched = new Set() 12 | const _includesOption = (option: any) => { 13 | const keys = Object.keys(option || {}) 14 | return keys.some((key) => { 15 | if (key === '__level') { 16 | return false 17 | } 18 | const value = option[key] 19 | if (React.isValidElement(value)) return false 20 | if (key !== 'children' && !searched.has(value)) { 21 | if (typeof value === 'object') { 22 | searched.add(value) 23 | return _includesOption(value) 24 | } 25 | return includes(value, search) 26 | } 27 | return false 28 | }) 29 | } 30 | return _includesOption(option) 31 | } 32 | 33 | function toArray<T>(value: T | T[]): T[] { 34 | if (isArr(value)) { 35 | return value 36 | } 37 | return value !== undefined ? [value] : [] 38 | } 39 | 40 | const useFilterOptions = ( 41 | options: any[], 42 | searchValue?: string | string[], 43 | filterOption?: IFilterOption, 44 | checkStrictly?: boolean 45 | ) => 46 | React.useMemo(() => { 47 | if (!searchValue || filterOption === false) { 48 | return options 49 | } 50 | const filterFunc = isFn(filterOption) 51 | ? filterOption 52 | : (value: any, option: any) => includesOption(option, value.toUpperCase()) 53 | 54 | const doFilter = (arr: any[]) => { 55 | const filterArr: any[] = [] 56 | arr?.forEach((item) => { 57 | if (item?.children?.length) { 58 | const filterChildren = doFilter(item.children) 59 | if (filterChildren.length) { 60 | filterArr.push({ ...item, children: filterChildren }) 61 | } else if (filterFunc(searchValue, item) && checkStrictly !== false) { 62 | // 父子关系启用时,没有可用子元素,不添加父元素 63 | filterArr.push({ ...item, children: [] }) 64 | } 65 | } else if (filterFunc(searchValue, item)) { 66 | filterArr.push(item) 67 | } 68 | }) 69 | return filterArr 70 | } 71 | 72 | return doFilter(options) 73 | }, [options, searchValue, filterOption]) 74 | 75 | export { useFilterOptions } 76 | ``` -------------------------------------------------------------------------------- /packages/next/src/select-table/useFilterOptions.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import * as React from 'react' 2 | import { isFn, isArr } from '@formily/shared' 3 | 4 | type IFilterOption = boolean | ((option: any, keyword: string) => boolean) 5 | 6 | function includes(test: React.ReactNode, search: string) { 7 | return toArray(test).join('').toUpperCase().includes(search) 8 | } 9 | 10 | function includesOption(option: any, search: string) { 11 | const searched = new Set() 12 | const _includesOption = (option: any) => { 13 | const keys = Object.keys(option || {}) 14 | return keys.some((key) => { 15 | if (key === '__level') { 16 | return false 17 | } 18 | const value = option[key] 19 | if (React.isValidElement(value)) return false 20 | if (key !== 'children' && !searched.has(value)) { 21 | if (typeof value === 'object') { 22 | searched.add(value) 23 | return _includesOption(value) 24 | } 25 | return includes(value, search) 26 | } 27 | return false 28 | }) 29 | } 30 | return _includesOption(option) 31 | } 32 | 33 | function toArray<T>(value: T | T[]): T[] { 34 | if (isArr(value)) { 35 | return value 36 | } 37 | return value !== undefined ? [value] : [] 38 | } 39 | 40 | const useFilterOptions = ( 41 | options: any[], 42 | searchValue?: string | string[], 43 | filterOption?: IFilterOption, 44 | checkStrictly?: boolean 45 | ) => 46 | React.useMemo(() => { 47 | if (!searchValue || filterOption === false) { 48 | return options 49 | } 50 | const filterFunc = isFn(filterOption) 51 | ? filterOption 52 | : (value: any, option: any) => includesOption(option, value.toUpperCase()) 53 | 54 | const doFilter = (arr: any[]) => { 55 | const filterArr: any[] = [] 56 | arr?.forEach((item) => { 57 | if (item?.children?.length) { 58 | const filterChildren = doFilter(item.children) 59 | if (filterChildren.length) { 60 | filterArr.push({ ...item, children: filterChildren }) 61 | } else if (filterFunc(searchValue, item) && checkStrictly !== false) { 62 | // 父子关系启用时,没有可用子元素,不添加父元素 63 | filterArr.push({ ...item, children: [] }) 64 | } 65 | } else if (filterFunc(searchValue, item)) { 66 | filterArr.push(item) 67 | } 68 | }) 69 | return filterArr 70 | } 71 | 72 | return doFilter(options) 73 | }, [options, searchValue, filterOption]) 74 | 75 | export { useFilterOptions } 76 | ``` -------------------------------------------------------------------------------- /packages/element/docs/.vuepress/config.js: -------------------------------------------------------------------------------- ```javascript 1 | const path = require('path') 2 | const utils = require('./util') 3 | 4 | const componentFiles = utils 5 | .getFiles(path.resolve(__dirname, '../guide')) 6 | .map((item) => item.replace(/(\.md)/g, '')) 7 | .filter((item) => !['el-form', 'el-form-item', 'index'].includes(item)) 8 | 9 | module.exports = { 10 | title: 'Element', 11 | description: 'Alibaba unified front-end form solution', 12 | dest: './doc-site', 13 | theme: '@vuepress-dumi/dumi', 14 | head: [ 15 | [ 16 | 'link', 17 | { 18 | rel: 'icon', 19 | href: '//img.alicdn.com/imgextra/i3/O1CN01XtT3Tv1Wd1b5hNVKy_!!6000000002810-55-tps-360-360.svg', 20 | }, 21 | ], 22 | [ 23 | 'link', 24 | { 25 | rel: 'stylesheet', 26 | href: 'https://esm.sh/element-ui/lib/theme-chalk/index.css', 27 | }, 28 | ], 29 | ], 30 | themeConfig: { 31 | logo: '//img.alicdn.com/imgextra/i2/O1CN01Kq3OHU1fph6LGqjIz_!!6000000004056-55-tps-1141-150.svg', 32 | nav: [ 33 | { 34 | text: 'Element', 35 | link: '/guide/', 36 | }, 37 | { 38 | text: '主站', 39 | link: 'https://formilyjs.org', 40 | }, 41 | { 42 | text: 'GITHUB', 43 | link: 'https://github.com/alibaba/formily', 44 | }, 45 | ], 46 | sidebar: { 47 | '/guide/': ['', ...componentFiles], 48 | }, 49 | lastUpdated: 'Last Updated', 50 | smoothScroll: true, 51 | }, 52 | plugins: [ 53 | 'vuepress-plugin-typescript', 54 | '@vuepress/back-to-top', 55 | '@vuepress/last-updated', 56 | '@vuepress-dumi/dumi-previewer', 57 | [ 58 | '@vuepress/medium-zoom', 59 | { 60 | selector: '.content__default :not(a) > img', 61 | }, 62 | ], 63 | ], 64 | configureWebpack: (config, isServer) => { 65 | return { 66 | resolve: { 67 | alias: { 68 | '@formily/element': path.resolve(__dirname, '../../src'), 69 | vue$: 'vue/dist/vue.esm.js', 70 | }, 71 | }, 72 | } 73 | }, 74 | chainWebpack: (config, isServer) => { 75 | config.module 76 | .rule('js') // Find the rule. 77 | .use('babel-loader') // Find the loader 78 | .tap((options) => 79 | Object.assign(options, { 80 | // Modifying options 81 | presets: [ 82 | [ 83 | '@vue/babel-preset-jsx', 84 | { 85 | vModel: false, 86 | compositionAPI: true, 87 | }, 88 | ], 89 | ], 90 | }) 91 | ) 92 | }, 93 | } 94 | ``` -------------------------------------------------------------------------------- /packages/vue/docs/demos/index.vue: -------------------------------------------------------------------------------- ```vue 1 | <template> 2 | <FormProvider :form="form"> 3 | <Field 4 | name="name" 5 | title="Name" 6 | required 7 | :decorator="[FormItem]" 8 | :component="[Input, { placeholder: 'Please Input' }]" 9 | /> 10 | <Field 11 | name="password" 12 | title="Password" 13 | required 14 | :decorator="[FormItem]" 15 | :component="[Input, { type: 'password', placeholder: 'Please Input' }]" 16 | :reactions="createPasswordEqualValidate('confirm_password')" 17 | /> 18 | <Field 19 | name="confirm_password" 20 | title="Confirm Password" 21 | required 22 | :decorator="[FormItem]" 23 | :component="[Input, { type: 'password', placeholder: 'Please Input' }]" 24 | :reactions="createPasswordEqualValidate('password')" 25 | /> 26 | <FormConsumer> 27 | <template #default="{ form }"> 28 | <div style="white-space: pre"> 29 | {{ JSON.stringify(form.values, null, 2) }} 30 | </div> 31 | </template> 32 | </FormConsumer> 33 | </FormProvider> 34 | </template> 35 | 36 | <script> 37 | import { Form, Input } from 'ant-design-vue' 38 | import { createForm, isVoidField, setValidateLanguage } from '@formily/core' 39 | import { 40 | FormProvider, 41 | FormConsumer, 42 | Field, 43 | connect, 44 | mapProps, 45 | } from '@formily/vue' 46 | import 'ant-design-vue/dist/antd.css' 47 | 48 | setValidateLanguage('en') 49 | 50 | const FormItem = connect( 51 | Form.Item, 52 | mapProps( 53 | { validateStatus: true, title: 'label', required: true }, 54 | (props, field) => { 55 | return { 56 | help: !isVoidField(field) 57 | ? field.selfErrors.length 58 | ? field.selfErrors 59 | : undefined 60 | : undefined, 61 | extra: field.description, 62 | } 63 | } 64 | ) 65 | ) 66 | 67 | export default { 68 | components: { 69 | FormProvider, 70 | FormConsumer, 71 | Field, 72 | }, 73 | data() { 74 | const form = createForm({ validateFirst: true }) 75 | const createPasswordEqualValidate = (equalName) => (field) => { 76 | if ( 77 | form.values.confirm_password && 78 | field.value && 79 | form.values[equalName] !== field.value 80 | ) { 81 | field.selfErrors = ['Password does not match Confirm Password.'] 82 | } else { 83 | field.selfErrors = [] 84 | } 85 | } 86 | return { 87 | FormItem, 88 | Input, 89 | form, 90 | createPasswordEqualValidate, 91 | } 92 | }, 93 | } 94 | </script> 95 | ``` -------------------------------------------------------------------------------- /packages/antd/docs/index.md: -------------------------------------------------------------------------------- ```markdown 1 | --- 2 | title: Formily-Alibaba unified front-end form solution 3 | order: 10 4 | hero: 5 | title: Formily Antd 6 | desc: Formily Component System Based on Ant Design Encapsulation 7 | actions: 8 | - text: Home Site 9 | link: //formilyjs.org 10 | - text: Document 11 | link: /components 12 | features: 13 | - icon: https://img.alicdn.com/imgextra/i2/O1CN016i72sH1c5wh1kyy9U_!!6000000003550-55-tps-800-800.svg 14 | title: Easier To Use 15 | desc: Out of the box, rich cases 16 | - icon: https://img.alicdn.com/imgextra/i1/O1CN01bHdrZJ1rEOESvXEi5_!!6000000005599-55-tps-800-800.svg 17 | title: More Efficient 18 | desc: Stupid writing, super high performance 19 | - icon: https://img.alicdn.com/imgextra/i3/O1CN01xlETZk1G0WSQT6Xii_!!6000000000560-55-tps-800-800.svg 20 | title: More Professional 21 | desc: complete, flexible, elegant 22 | footer: Open-source MIT Licensed | Copyright © 2019-present<br />Powered by self 23 | --- 24 | 25 | ## Installation 26 | 27 | ```bash 28 | $ npm install --save antd moment 29 | $ npm install --save @formily/core @formily/react @formily/antd 30 | 31 | ``` 32 | 33 | ## Quick start 34 | 35 | ```tsx 36 | /** 37 | * defaultShowCode: true 38 | */ 39 | import React from 'react' 40 | import { NumberPicker, FormItem, Space } from '@formily/antd' 41 | import { createForm } from '@formily/core' 42 | import { FormProvider, FormConsumer, Field } from '@formily/react' 43 | 44 | const form = createForm() 45 | 46 | export default () => ( 47 | <FormProvider form={form}> 48 | <Space> 49 | <Field 50 | name="price" 51 | title="price" 52 | initialValue={5.2} 53 | decorator={[FormItem]} 54 | component={[ 55 | NumberPicker, 56 | { 57 | placeholder: 'Please enter', 58 | style: { 59 | width: 100, 60 | }, 61 | }, 62 | ]} 63 | /> 64 | <FormItem>×</FormItem> 65 | <Field 66 | name="count" 67 | title="quantity" 68 | initialValue={100} 69 | decorator={[FormItem]} 70 | component={[ 71 | NumberPicker, 72 | { 73 | placeholder: 'Please enter', 74 | style: { 75 | width: 100, 76 | }, 77 | }, 78 | ]} 79 | /> 80 | <FormConsumer> 81 | {(form) => ( 82 | <FormItem>={` ${form.values.price * form.values.count}元`}</FormItem> 83 | )} 84 | </FormConsumer> 85 | </Space> 86 | </FormProvider> 87 | ) 88 | ``` 89 | ``` -------------------------------------------------------------------------------- /packages/next/docs/index.md: -------------------------------------------------------------------------------- ```markdown 1 | --- 2 | title: Formily-Alibaba unified front-end form solution 3 | order: 10 4 | hero: 5 | title: Formily Fusion 6 | desc: Formily Component System Based on Alibaba Fusion Encapsulation 7 | actions: 8 | - text: Home Site 9 | link: //formilyjs.org 10 | - text: Document 11 | link: /components 12 | features: 13 | - icon: https://img.alicdn.com/imgextra/i2/O1CN016i72sH1c5wh1kyy9U_!!6000000003550-55-tps-800-800.svg 14 | title: Easier To Use 15 | desc: Out of the box, rich cases 16 | - icon: https://img.alicdn.com/imgextra/i1/O1CN01bHdrZJ1rEOESvXEi5_!!6000000005599-55-tps-800-800.svg 17 | title: More Efficient 18 | desc: Stupid writing, super high performance 19 | - icon: https://img.alicdn.com/imgextra/i3/O1CN01xlETZk1G0WSQT6Xii_!!6000000000560-55-tps-800-800.svg 20 | title: More Professional 21 | desc: complete, flexible, elegant 22 | footer: Open-source MIT Licensed | Copyright © 2019-present<br />Powered by self 23 | --- 24 | 25 | ## Installation 26 | 27 | ```bash 28 | $ npm install --save @alifd/next moment 29 | $ npm install --save @formily/core @formily/react @formily/next 30 | 31 | ``` 32 | 33 | ## Quick start 34 | 35 | ```tsx 36 | /** 37 | * defaultShowCode: true 38 | */ 39 | import React from 'react' 40 | import { NumberPicker, FormItem, Space } from '@formily/next' 41 | import { createForm } from '@formily/core' 42 | import { FormProvider, FormConsumer, Field } from '@formily/react' 43 | 44 | const form = createForm() 45 | 46 | export default () => ( 47 | <FormProvider form={form}> 48 | <Space> 49 | <Field 50 | name="price" 51 | title="price" 52 | initialValue={5.2} 53 | decorator={[FormItem]} 54 | component={[ 55 | NumberPicker, 56 | { 57 | placeholder: 'Please enter', 58 | style: { 59 | width: 100, 60 | }, 61 | }, 62 | ]} 63 | /> 64 | <FormItem>×</FormItem> 65 | <Field 66 | name="count" 67 | title="quantity" 68 | initialValue={100} 69 | decorator={[FormItem]} 70 | component={[ 71 | NumberPicker, 72 | { 73 | placeholder: 'Please enter', 74 | style: { 75 | width: 100, 76 | }, 77 | }, 78 | ]} 79 | /> 80 | <FormConsumer> 81 | {(form) => ( 82 | <FormItem>={` ${form.values.price * form.values.count}元`}</FormItem> 83 | )} 84 | </FormConsumer> 85 | </Space> 86 | </FormProvider> 87 | ) 88 | ``` 89 | ``` -------------------------------------------------------------------------------- /packages/core/docs/api/models/ArrayField.md: -------------------------------------------------------------------------------- ```markdown 1 | --- 2 | order: 2 3 | --- 4 | 5 | # ArrayField 6 | 7 | Call the ArrayField model returned by [createArrayField](/api/models/form#createarrayfield). 8 | 9 | Because ArrayField is inherited from the [Field](/api/models/field) model, most APIs can refer to the Field model. This document only explains the extension method 10 | 11 | ## Method 12 | 13 | <Alert> 14 | 15 | Note: The following method not only updates the array data, but also transposes the state of the child nodes. If you don't want to automatically transpose the state, you can directly call the `setValue` method to overwrite the update value. 16 | 17 | </Alert> 18 | 19 | ### push 20 | 21 | #### Description 22 | 23 | Append an element to the end of the array and trigger onInput 24 | 25 | #### Signature 26 | 27 | ```ts 28 | interface push { 29 | (...items: any[]): Promise<void> 30 | } 31 | ``` 32 | 33 | ### pop 34 | 35 | #### Description 36 | 37 | Pop the last element of the array and trigger onInput 38 | 39 | #### Signature 40 | 41 | ```ts 42 | interface pop { 43 | (): Promise<void> 44 | } 45 | ``` 46 | 47 | ### insert 48 | 49 | #### Description 50 | 51 | Insert an element into the array and trigger onInput 52 | 53 | #### Signature 54 | 55 | ```ts 56 | interface insert { 57 | (index: number, ...items: any[]): Promise<void> 58 | } 59 | ``` 60 | 61 | ### remove 62 | 63 | #### Description 64 | 65 | Delete the array element and trigger onInput 66 | 67 | #### Signature 68 | 69 | ```ts 70 | interface remove { 71 | (index: number): Promise<void> 72 | } 73 | ``` 74 | 75 | ### shift 76 | 77 | #### Description 78 | 79 | Pop the first element of the array and trigger onInput 80 | 81 | #### Signature 82 | 83 | ```ts 84 | interface shift { 85 | (): Promise<void> 86 | } 87 | ``` 88 | 89 | ### unshift 90 | 91 | #### Description 92 | 93 | Append an element to the head of the array and trigger onInput 94 | 95 | #### Signature 96 | 97 | ```ts 98 | interface unshift { 99 | (...items: any[]): Promise<void> 100 | } 101 | ``` 102 | 103 | ### move 104 | 105 | #### Description 106 | 107 | Move the array element and trigger onInput 108 | 109 | #### Signature 110 | 111 | ```ts 112 | interface move { 113 | (fromIndex: number, toIndex: number): Promise<void> 114 | } 115 | ``` 116 | 117 | ### moveUp 118 | 119 | #### Description 120 | 121 | Move the array element up and trigger onInput 122 | 123 | #### Signature 124 | 125 | ```ts 126 | interface moveUp { 127 | (index: number): Promise<void> 128 | } 129 | ``` 130 | 131 | ### moveDown 132 | 133 | #### Description 134 | 135 | Move the array element down and trigger onInput 136 | 137 | #### Signature 138 | 139 | ```ts 140 | interface moveDown { 141 | (index: number): Promise<void> 142 | } 143 | ``` 144 | 145 | ## Types of 146 | 147 | ### IArrayFieldState 148 | 149 | The main attributes refer to [IFieldState](/api/models/field#ifieldstate), but the data type of value is required to be an array 150 | ``` -------------------------------------------------------------------------------- /packages/react/docs/guide/index.md: -------------------------------------------------------------------------------- ```markdown 1 | # Introduction 2 | 3 | The core positioning of @formily/react is to realize a state binding relationship between ViewModel ([@formily/core](//core.formilyjs.org)) and components. It is not responsible for managing form data and form verification. It is only A rendering glue layer, but such a layer of glue is not dirty, it will elegantly decouple a lot of dirty logic and become maintainable. 4 | 5 | ## Ultra high performance 6 | 7 | With the responsive model of [@formily/core](//core.formilyjs.org), @formily/react can obtain super high performance advantages without any optimization, relying on tracking, accurate updates, on-demand rendering, let us The form of really does only need to focus on business logic, without considering performance issues. 8 | 9 | ## Out of the box 10 | 11 | @formily/react provides a series of React components, such as Field/ArrayField/ObjectField/VoidField. When using it, users only need to pass the component property to the Field component (supporting two-way binding conventions such as value/onChange). Quick access to @formily/react, the access cost is extremely low. 12 | 13 | ## JSON Schema Driver 14 | 15 | @formily/react provides protocol-driven components such as SchemaField. It is also driven by the standard JSON-Schema, so that form development can become more dynamic and configurable. What's more, we can achieve a protocol that allows multiple terminals Render the form. 16 | 17 | ## Scene Reuse 18 | 19 | With the help of protocol-driven capabilities, we can abstract a protocol fragment carrying business logic into a scene component to help users develop efficiently in certain scenes, such as scene components such as FormTab and FormStep. 20 | 21 | ## Smart tips 22 | 23 | Because formily is a complete Typescript project, users can develop on VSCode or WebStorm to get the maximum intelligent prompt experience 24 | 25 |  26 | 27 | ## Status observable 28 | 29 | Install [FormilyDevtools](https://chrome.google.com/webstore/detail/formily-devtools/kkocalmbfnplecdmbadaapgapdioecfm?hl=zh-CN) to observe the model status changes in real time and troubleshoot problems 30 | 31 |  32 | ``` -------------------------------------------------------------------------------- /packages/element/docs/demos/guide/form-dialog/json-schema.vue: -------------------------------------------------------------------------------- ```vue 1 | <template> 2 | <Button @click="handleOpen">点击打开表单</Button> 3 | </template> 4 | 5 | <script> 6 | import { FormDialog, FormLayout, FormItem, Input } from '@formily/element' 7 | import { Button } from 'element-ui' 8 | import { createSchemaField } from '@formily/vue' 9 | const { SchemaField } = createSchemaField({ 10 | components: { 11 | FormItem, 12 | Input, 13 | }, 14 | }) 15 | 16 | // 弹框表单组件 17 | const DialogForm = { 18 | data() { 19 | const schema = { 20 | type: 'object', 21 | properties: { 22 | aaa: { 23 | type: 'string', 24 | title: '输入框1', 25 | required: true, 26 | 'x-decorator': 'FormItem', 27 | 'x-component': 'Input', 28 | }, 29 | bbb: { 30 | type: 'string', 31 | title: '输入框2', 32 | required: true, 33 | 'x-decorator': 'FormItem', 34 | 'x-component': 'Input', 35 | }, 36 | ccc: { 37 | type: 'string', 38 | title: '输入框3', 39 | required: true, 40 | 'x-decorator': 'FormItem', 41 | 'x-component': 'Input', 42 | }, 43 | ddd: { 44 | type: 'string', 45 | title: '输入框4', 46 | required: true, 47 | 'x-decorator': 'FormItem', 48 | 'x-component': 'Input', 49 | }, 50 | }, 51 | } 52 | return { 53 | schema, 54 | } 55 | }, 56 | render(h) { 57 | return ( 58 | <FormLayout labelCol={6} wrapperCol={10}> 59 | <SchemaField schema={this.schema} /> 60 | <FormDialog.Footer> 61 | <span style={{ marginLeft: '4px' }}>扩展文案</span> 62 | </FormDialog.Footer> 63 | </FormLayout> 64 | ) 65 | }, 66 | } 67 | 68 | export default { 69 | components: { Button }, 70 | data() { 71 | return {} 72 | }, 73 | methods: { 74 | handleOpen() { 75 | FormDialog('弹框表单', DialogForm) 76 | .forOpen((payload, next) => { 77 | setTimeout(() => { 78 | next({ 79 | initialValues: { 80 | aaa: '123', 81 | }, 82 | }) 83 | }, 1000) 84 | }) 85 | .forConfirm((payload, next) => { 86 | setTimeout(() => { 87 | console.log(payload) 88 | next(payload) 89 | }, 1000) 90 | }) 91 | .forCancel((payload, next) => { 92 | setTimeout(() => { 93 | console.log(payload) 94 | next(payload) 95 | }, 1000) 96 | }) 97 | .open() 98 | .then(console.log) 99 | .catch(console.error) 100 | }, 101 | }, 102 | } 103 | </script> 104 | ``` -------------------------------------------------------------------------------- /packages/reactive-test-cases-for-react18/src/index.js: -------------------------------------------------------------------------------- ```javascript 1 | import React, { startTransition, useState } from 'react' 2 | import ReactDOM from 'react-dom' 3 | import MySlowList from './MySlowList' 4 | import { observable } from '@formily/reactive' 5 | import { observer } from '@formily/reactive-react' 6 | 7 | const App = observer(function App() { 8 | const [text, setText] = useState('hello') 9 | const [slowText] = useState(() => 10 | observable({ 11 | text, 12 | }) 13 | ) 14 | 15 | function handleChange(e) { 16 | setText(e.target.value) 17 | startTransition(() => { 18 | slowText.text = e.target.value 19 | }) 20 | } 21 | 22 | return ( 23 | <div className="App"> 24 | <h1>Concurrent React</h1> 25 | <label> 26 | Type into the input: <input value={text} onChange={handleChange} /> 27 | </label> 28 | <p> 29 | You entered: <b>{text}</b> 30 | </p> 31 | <p 32 | style={{ 33 | background: text !== slowText.text ? 'yellow' : '', 34 | }} 35 | > 36 | But we are showing: <Indicator text={slowText} /> 37 | </p> 38 | <p 39 | style={{ 40 | background: text !== slowText.text ? 'yellow' : '', 41 | }} 42 | > 43 | But we are showing: <Indicator text={slowText} /> 44 | </p> 45 | <p 46 | style={{ 47 | background: text !== slowText.text ? 'yellow' : '', 48 | }} 49 | > 50 | But we are showing: <Indicator text={slowText} /> 51 | </p> 52 | <p 53 | style={{ 54 | background: text !== slowText.text ? 'yellow' : '', 55 | }} 56 | > 57 | But we are showing: <Indicator text={slowText} /> 58 | </p> 59 | <p> 60 | Even though{' '} 61 | <b> 62 | each list item in this demo artificially blocks the main thread for 3 63 | milliseconds 64 | </b> 65 | , the app is able to stay responsive. 66 | </p> 67 | <hr /> 68 | <MySlowList text={slowText} /> 69 | </div> 70 | ) 71 | }) 72 | 73 | let Indicator = observer(({ text }) => { 74 | const [hover, setHover] = useState(false) 75 | return ( 76 | <p 77 | onMouseEnter={() => setHover(true)} 78 | onMouseLeave={() => setHover(false)} 79 | style={{ 80 | border: '1px solid black', 81 | padding: 20, 82 | background: hover ? 'yellow' : '', 83 | }} 84 | > 85 | But we are showing: <b>{text.text}</b> 86 | </p> 87 | ) 88 | }) 89 | 90 | const rootElement = document.getElementById('root') 91 | ReactDOM.createRoot(rootElement).render(<App />) 92 | ``` -------------------------------------------------------------------------------- /packages/element/docs/demos/guide/preview-text/extend.vue: -------------------------------------------------------------------------------- ```vue 1 | <template> 2 | <Form 3 | :labelCol="6" 4 | :wrapperCol="10" 5 | :form="form" 6 | :previewTextPlaceholder="vnode" 7 | > 8 | <SchemaField> 9 | <SchemaStringField 10 | x-decorator="FormItem" 11 | title="文本预览" 12 | x-component="Input" 13 | default="Hello world" 14 | /> 15 | <SchemaStringField 16 | x-decorator="FormItem" 17 | title="选择项预览" 18 | x-component="PreviewText.Select" 19 | :x-component-props="{ 20 | multiple: true, 21 | }" 22 | :default="['123', '222']" 23 | :enum="[ 24 | { label: 'A111', value: '123' }, 25 | { 26 | label: 'A222', 27 | value: '222', 28 | }, 29 | ]" 30 | /> 31 | <SchemaStringField 32 | x-decorator="FormItem" 33 | title="日期预览" 34 | x-component="PreviewText.DatePicker" 35 | default="2020-11-23 22:15:20" 36 | /> 37 | <SchemaStringField 38 | x-decorator="FormItem" 39 | title="日期范围预览" 40 | x-component="PreviewText.DatePicker" 41 | :default="['2020-11-23 22:15:20', '2020-11-24 22:15:20']" 42 | /> 43 | <SchemaStringField 44 | x-decorator="FormItem" 45 | title="Cascader预览" 46 | x-component="PreviewText.Cascader" 47 | :default="['hangzhou', 'yuhang']" 48 | :enum="[ 49 | { label: '杭州', value: 'hangzhou' }, 50 | { label: '余杭', value: 'yuhang' }, 51 | ]" 52 | /> 53 | </SchemaField> 54 | <FormButtonGroup alignFormItem> 55 | <Button 56 | @click=" 57 | () => { 58 | form.setState((state) => { 59 | state.editable = !state.editable 60 | }) 61 | } 62 | " 63 | >切换阅读态</Button 64 | > 65 | </FormButtonGroup> 66 | </Form> 67 | </template> 68 | 69 | <script> 70 | import { h } from 'vue-demi' 71 | import { createForm } from '@formily/core' 72 | import { createSchemaField } from '@formily/vue' 73 | import { 74 | Form, 75 | FormItem, 76 | Input, 77 | PreviewText, 78 | FormButtonGroup, 79 | } from '@formily/element' 80 | import { Button } from 'element-ui' 81 | 82 | const fields = createSchemaField({ 83 | components: { 84 | FormItem, 85 | Input, 86 | PreviewText, 87 | }, 88 | }) 89 | 90 | export default { 91 | components: { 92 | Form, 93 | FormButtonGroup, 94 | Button, 95 | ...fields, 96 | }, 97 | data() { 98 | const form = createForm() 99 | return { 100 | form, 101 | vnode: () => h('div', {}, '123'), 102 | } 103 | }, 104 | 105 | mounted() {}, 106 | } 107 | </script> 108 | ``` -------------------------------------------------------------------------------- /packages/core/docs/api/models/Query.md: -------------------------------------------------------------------------------- ```markdown 1 | --- 2 | order: 5 3 | --- 4 | 5 | # Query 6 | 7 | The Query object returned by calling the query method in the [Form](/api/models/form#query) or [Field](/api/models/field#query) instance 8 | 9 | ## Method 10 | 11 | ### take 12 | 13 | #### Description 14 | 15 | Extract the first result from the query result set 16 | 17 | Note that there must be a corresponding node to be able to read 18 | 19 | #### Signature 20 | 21 | ```ts 22 | interface take { 23 | (): GeneralField 24 | <Result>(getter: (field: GeneralField, address: FormPath) => Result): Result 25 | } 26 | ``` 27 | 28 | ### map 29 | 30 | #### Description 31 | 32 | Traverse and map the query result set 33 | 34 | Note that there must be a corresponding node to traverse 35 | 36 | #### Signature 37 | 38 | ```ts 39 | interface map { 40 | (): GeneralField[] 41 | <Result>( 42 | mapper?: (field: GeneralField, address: FormPath) => Result 43 | ): Result[] 44 | } 45 | ``` 46 | 47 | ### forEach 48 | 49 | #### Description 50 | 51 | Traverse the query result set 52 | 53 | Note that there must be a corresponding node to traverse 54 | 55 | #### Signature 56 | 57 | ```ts 58 | interface forEach { 59 | <Result>(eacher: (field: GeneralField, address: FormPath) => Result): void 60 | } 61 | ``` 62 | 63 | ### reduce 64 | 65 | #### Description 66 | 67 | Perform a reduce operation on the query result set 68 | 69 | Note that there must be a corresponding node to traverse 70 | 71 | #### Signature 72 | 73 | ```ts 74 | interface reduce { 75 | <Result>( 76 | reducer: (value: Result, field: GeneralField, address: FormPath) => Result, 77 | initial?: Result 78 | ): Result 79 | } 80 | ``` 81 | 82 | ### get 83 | 84 | #### Description 85 | 86 | Find the first result from the query result set and read its attributes 87 | 88 | Note that there must be a corresponding node to be able to read 89 | 90 | #### Signature 91 | 92 | ```ts 93 | interface get { 94 | <K extends keyof IGeneralFieldState>(key: K): IGeneralFieldState[K] 95 | } 96 | ``` 97 | 98 | ### getIn 99 | 100 | #### Description 101 | 102 | Find the first result from the query result set and read its attributes, support [FormPathPattern](/api/entry/form-path#formpathpattern) path syntax 103 | 104 | Note that there must be a corresponding node to be able to read 105 | 106 | #### Signature 107 | 108 | ```ts 109 | interface getIn { 110 | (pattern?: FormPathPattern): any 111 | } 112 | ``` 113 | 114 | ### value 115 | 116 | #### Description 117 | 118 | Query the specified path value, not limited to Field nodes 119 | 120 | #### Signature 121 | 122 | ```ts 123 | interface value { 124 | (): any 125 | } 126 | ``` 127 | 128 | ### initialValue 129 | 130 | #### Description 131 | 132 | Query the initial value of the specified path, not limited to the Field node 133 | 134 | #### Signature 135 | 136 | ```ts 137 | interface initialValue { 138 | (): any 139 | } 140 | ``` 141 | ``` -------------------------------------------------------------------------------- /packages/next/src/array-table/main.scss: -------------------------------------------------------------------------------- ```scss 1 | @import '~@alifd/next/lib/core/index-noreset.scss'; 2 | @import '~@alifd/next/lib/form/scss/variable.scss'; 3 | 4 | $array-table-prefix-cls: '#{$css-prefix}formily-array-table'; 5 | 6 | .#{$array-table-prefix-cls} { 7 | .#{$array-table-prefix-cls}-pagination { 8 | display: flex; 9 | justify-content: center; 10 | margin: 10px 0; 11 | 12 | .#{$array-table-prefix-cls}-status-select { 13 | min-width: 60px; 14 | margin-right: 6px; 15 | width: auto !important; 16 | 17 | .#{$css-prefix}input { 18 | min-width: 60px; 19 | } 20 | 21 | &.has-error { 22 | .#{$css-prefix}input { 23 | border-color: red !important; 24 | } 25 | } 26 | } 27 | } 28 | 29 | .#{$css-prefix}table { 30 | .#{$css-prefix}table-cell-wrapper { 31 | overflow: visible; 32 | word-break: normal; 33 | } 34 | 35 | td { 36 | visibility: visible; 37 | 38 | .#{$css-prefix}formily-item:not(.#{$css-prefix}formily-item-feedback-layout-popover) { 39 | margin-bottom: 0 !important; 40 | position: relative; 41 | 42 | .#{$css-prefix}formily-item-help { 43 | &.#{$css-prefix}formily-item-error-help { 44 | color: $form-error-color; 45 | } 46 | 47 | &.#{$css-prefix}formily-item-warning-help { 48 | color: $form-warning-color; 49 | } 50 | 51 | & { 52 | min-width: 30px; 53 | position: absolute; 54 | font-size: 12px; 55 | top: 100%; 56 | width: 100%; 57 | z-index: 1; 58 | border-radius: 3px; 59 | background-color: #fff; 60 | border: 1px solid #eee; 61 | padding: 6px 8px; 62 | margin-top: 6px; 63 | transform: translateY(0); 64 | opacity: 1; 65 | } 66 | &:after { 67 | content: ' '; 68 | background-color: #fff; 69 | position: absolute; 70 | display: block; 71 | width: 5px; 72 | height: 5px; 73 | pointer-events: none; 74 | -webkit-transform: rotate(45deg); 75 | top: -4px; 76 | transform: rotate(45deg); 77 | box-sizing: content-box !important; 78 | border-left: 1px solid #eee; 79 | border-top: 1px solid #eee; 80 | z-index: -1; 81 | } 82 | } 83 | } 84 | } 85 | } 86 | 87 | .#{$array-table-prefix-cls}-sort-helper { 88 | background: #fff; 89 | border: 1px solid #eee; 90 | z-index: 10; 91 | } 92 | } 93 | ``` -------------------------------------------------------------------------------- /packages/next/src/password/index.tsx: -------------------------------------------------------------------------------- ```typescript 1 | import React from 'react' 2 | import { connect, mapProps, mapReadPretty } from '@formily/react' 3 | import { Input } from '@alifd/next' 4 | import { PasswordProps } from '@alifd/next/lib/input' 5 | import { PasswordStrength } from './PasswordStrength' 6 | import { PreviewText } from '../preview-text' 7 | import { mapStatus, mapSize } from '../__builtins__' 8 | export interface IPasswordProps extends PasswordProps { 9 | checkStrength: boolean 10 | } 11 | 12 | export const Password = connect( 13 | (props: IPasswordProps) => { 14 | const { value, className, checkStrength, ...others } = props 15 | const blockStyle: React.CSSProperties = { 16 | position: 'absolute', 17 | zIndex: 1, 18 | height: 8, 19 | top: 0, 20 | background: '#fff', 21 | width: 1, 22 | transform: 'translate(-50%, 0)', 23 | } 24 | return ( 25 | <span className={className}> 26 | <Input.Password 27 | {...others} 28 | style={{ ...others.style, width: '100%' }} 29 | value={value} 30 | /> 31 | {checkStrength && ( 32 | <PasswordStrength value={String(value)}> 33 | {(score) => { 34 | return ( 35 | <div 36 | style={{ 37 | background: '#e0e0e0', 38 | marginBottom: 3, 39 | position: 'relative', 40 | }} 41 | > 42 | <div style={{ ...blockStyle, left: '20%' }} /> 43 | <div style={{ ...blockStyle, left: '40%' }} /> 44 | <div style={{ ...blockStyle, left: '60%' }} /> 45 | <div style={{ ...blockStyle, left: '80%' }} /> 46 | <div 47 | style={{ 48 | position: 'relative', 49 | backgroundImage: 50 | '-webkit-linear-gradient(left, #ff5500, #ff9300)', 51 | transition: 'all 0.35s ease-in-out', 52 | height: 8, 53 | width: '100%', 54 | marginTop: 5, 55 | clipPath: `polygon(0 0,${score}% 0,${score}% 100%,0 100%)`, 56 | }} 57 | /> 58 | </div> 59 | ) 60 | }} 61 | </PasswordStrength> 62 | )} 63 | </span> 64 | ) 65 | }, 66 | mapProps(mapSize, mapStatus), 67 | mapReadPretty(PreviewText.Input) 68 | ) 69 | 70 | export default Password 71 | ``` -------------------------------------------------------------------------------- /packages/element/docs/demos/guide/editable/json-schema.vue: -------------------------------------------------------------------------------- ```vue 1 | <template> 2 | <FormProvider :form="form"> 3 | <SchemaField :schema="schema" /> 4 | <FormButtonGroup> 5 | <Submit @submit="log">提交</Submit> 6 | </FormButtonGroup> 7 | </FormProvider> 8 | </template> 9 | 10 | <script> 11 | import { createForm } from '@formily/core' 12 | import { FormProvider, createSchemaField } from '@formily/vue' 13 | import { 14 | FormButtonGroup, 15 | FormItem, 16 | Submit, 17 | Input, 18 | DatePicker, 19 | Editable, 20 | } from '@formily/element' 21 | 22 | const { SchemaField } = createSchemaField({ 23 | components: { 24 | FormItem, 25 | Input, 26 | DatePicker, 27 | Editable, 28 | }, 29 | }) 30 | 31 | const schema = { 32 | type: 'object', 33 | properties: { 34 | date: { 35 | type: 'string', 36 | title: '日期', 37 | 'x-decorator': 'Editable', 38 | 'x-component': 'DatePicker', 39 | }, 40 | input: { 41 | type: 'string', 42 | title: '输入框', 43 | 'x-decorator': 'Editable', 44 | 'x-component': 'Input', 45 | }, 46 | void: { 47 | type: 'void', 48 | title: '虚拟节点容器', 49 | 'x-component': 'Editable.Popover', 50 | 'x-reactions': 51 | "{{(field) => field.title = field.query('.void.date2').get('value') || field.title}}", 52 | properties: { 53 | date2: { 54 | type: 'string', 55 | title: '日期', 56 | 'x-decorator': 'FormItem', 57 | 'x-component': 'DatePicker', 58 | }, 59 | input2: { 60 | type: 'string', 61 | title: '输入框', 62 | 'x-decorator': 'FormItem', 63 | 'x-component': 'Input', 64 | }, 65 | }, 66 | }, 67 | iobject: { 68 | type: 'object', 69 | title: '对象节点容器', 70 | 'x-component': 'Editable.Popover', 71 | 'x-reactions': 72 | '{{(field) => field.title = field.value && field.value.date || field.title}}', 73 | properties: { 74 | date: { 75 | type: 'string', 76 | title: '日期', 77 | 'x-decorator': 'FormItem', 78 | 'x-component': 'DatePicker', 79 | }, 80 | input: { 81 | type: 'string', 82 | title: '输入框', 83 | 'x-decorator': 'FormItem', 84 | 'x-component': 'Input', 85 | }, 86 | }, 87 | }, 88 | }, 89 | } 90 | 91 | export default { 92 | components: { 93 | FormButtonGroup, 94 | FormProvider, 95 | Submit, 96 | SchemaField, 97 | }, 98 | 99 | data() { 100 | const form = createForm() 101 | 102 | return { 103 | schema, 104 | form, 105 | } 106 | }, 107 | methods: { 108 | log(values) { 109 | console.log(values) 110 | }, 111 | }, 112 | } 113 | </script> 114 | 115 | <style lang="scss" scoped></style> 116 | ``` -------------------------------------------------------------------------------- /packages/element/docs/demos/guide/select/json-schema-async.vue: -------------------------------------------------------------------------------- ```vue 1 | <template> 2 | <Form :form="form"> 3 | <SchemaField :schema="schema" :scope="{ useAsyncDataSource, loadData }" /> 4 | <Submit @submit="onSubmit">提交</Submit> 5 | </Form> 6 | </template> 7 | 8 | <script> 9 | import { createForm } from '@formily/core' 10 | import { createSchemaField } from '@formily/vue' 11 | import { action } from '@formily/reactive' 12 | import { Form, FormItem, Select, Submit, Reset } from '@formily/element' 13 | 14 | const schema = { 15 | type: 'object', 16 | properties: { 17 | linkage: { 18 | type: 'string', 19 | title: '联动选择框', 20 | enum: [ 21 | { 22 | label: '发请求1', 23 | value: 1, 24 | }, 25 | { 26 | label: '发请求2', 27 | value: 2, 28 | }, 29 | ], 30 | 'x-decorator': 'FormItem', 31 | 'x-component': 'Select', 32 | 'x-component-props': { 33 | style: 'width: 240px;', 34 | }, 35 | }, 36 | select: { 37 | type: 'string', 38 | title: '异步选择框', 39 | 'x-decorator': 'FormItem', 40 | 'x-component': 'Select', 41 | 'x-component-props': { 42 | style: 'width: 240px;', 43 | }, 44 | 'x-reactions': ['{{useAsyncDataSource(loadData)}}'], 45 | }, 46 | }, 47 | } 48 | 49 | const useAsyncDataSource = (service) => (field) => { 50 | field.loading = true 51 | service(field).then( 52 | action.bound((data) => { 53 | field.dataSource = data 54 | field.loading = false 55 | }) 56 | ) 57 | } 58 | 59 | const loadData = async (field) => { 60 | const linkage = field.query('linkage').get('value') 61 | if (!linkage) return [] 62 | return new Promise((resolve) => { 63 | setTimeout(() => { 64 | if (linkage === 1) { 65 | resolve([ 66 | { 67 | label: 'AAA', 68 | value: 'aaa', 69 | }, 70 | { 71 | label: 'BBB', 72 | value: 'ccc', 73 | }, 74 | ]) 75 | } else if (linkage === 2) { 76 | resolve([ 77 | { 78 | label: 'CCC', 79 | value: 'ccc', 80 | }, 81 | { 82 | label: 'DDD', 83 | value: 'ddd', 84 | }, 85 | ]) 86 | } 87 | }, 1500) 88 | }) 89 | } 90 | 91 | const form = createForm() 92 | const { SchemaField } = createSchemaField({ 93 | components: { 94 | FormItem, 95 | Select, 96 | }, 97 | }) 98 | 99 | export default { 100 | components: { Form, SchemaField, Submit, Reset }, 101 | data() { 102 | return { 103 | form, 104 | schema, 105 | } 106 | }, 107 | methods: { 108 | useAsyncDataSource, 109 | loadData, 110 | onSubmit(value) { 111 | console.log(value) 112 | }, 113 | }, 114 | } 115 | </script> 116 | ``` -------------------------------------------------------------------------------- /packages/reactive/src/types.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { ArraySet } from './array' 2 | 3 | export * from './tree' 4 | 5 | export type PropertyKey = string | number | symbol 6 | 7 | export type OperationType = 8 | | 'add' 9 | | 'delete' 10 | | 'clear' 11 | | 'set' 12 | | 'get' 13 | | 'iterate' 14 | | 'has' 15 | export interface IOperation { 16 | target?: any 17 | oldTarget?: any 18 | key?: PropertyKey 19 | value?: any 20 | oldValue?: any 21 | type?: OperationType 22 | receiver?: any 23 | } 24 | 25 | export interface IChange { 26 | key?: PropertyKey 27 | path?: ObservablePath 28 | value?: any 29 | oldValue?: any 30 | type?: OperationType 31 | } 32 | 33 | export interface IEffectQueueItem { 34 | dispose?: void | Dispose 35 | deps?: any[] 36 | } 37 | 38 | export interface IMemoQueueItem { 39 | value?: any 40 | deps?: any[] 41 | } 42 | 43 | export interface IVisitor<Value = any, Target = any> { 44 | target?: Target 45 | key?: PropertyKey 46 | value?: Value 47 | } 48 | 49 | export type Annotation = (...args: any[]) => any 50 | 51 | export type Annotations<T = any> = { 52 | [key in keyof T]?: Annotation 53 | } 54 | 55 | export type ObservableListener = (operation: IOperation) => void 56 | 57 | export type ObservablePath = Array<string | number> 58 | 59 | export type Dispose = () => void 60 | 61 | export type Effect = () => void | Dispose 62 | 63 | export type Reaction = ((...args: any[]) => any) & { 64 | _boundary?: number 65 | _name?: string 66 | _isComputed?: boolean 67 | _dirty?: boolean 68 | _context?: any 69 | _disposed?: boolean 70 | _property?: PropertyKey 71 | _computesSet?: ArraySet<Reaction> 72 | _reactionsSet?: ArraySet<ReactionsMap> 73 | _scheduler?: (reaction: Reaction) => void 74 | _memos?: { 75 | queue: IMemoQueueItem[] 76 | cursor: number 77 | } 78 | _effects?: { 79 | queue: IEffectQueueItem[] 80 | cursor: number 81 | } 82 | } 83 | 84 | export type ReactionsMap = Map<PropertyKey, ArraySet<Reaction>> 85 | 86 | export interface IReactionOptions<T> { 87 | name?: string 88 | equals?: (oldValue: T, newValue: T) => boolean 89 | fireImmediately?: boolean 90 | } 91 | 92 | export type BindFunction<F = (...args: any[]) => any> = ( 93 | callback?: F, 94 | context?: any 95 | ) => F 96 | 97 | export type BoundaryFunction = <F extends (...args: any) => any>( 98 | fn?: F 99 | ) => ReturnType<F> 100 | 101 | export interface IBoundable { 102 | bound?: <T extends (...args: any[]) => any>(callback: T, context?: any) => T //高阶绑定 103 | } 104 | export interface IAction extends IBoundable { 105 | <T>(callback?: () => T): T //原地action 106 | scope?: (<T>(callback?: () => T) => T) & IBoundable //原地局部action 107 | } 108 | 109 | export interface IBatch extends IAction { 110 | endpoint?: (callback?: () => void) => void 111 | } 112 | ``` -------------------------------------------------------------------------------- /packages/element/docs/demos/guide/select/markup-schema-async.vue: -------------------------------------------------------------------------------- ```vue 1 | <template> 2 | <Form :form="form"> 3 | <SchemaField> 4 | <SchemaNumberField 5 | name="linkage" 6 | title="联动选择框" 7 | x-decorator="FormItem" 8 | x-component="Select" 9 | :enum="[ 10 | { label: '发请求1', value: 1 }, 11 | { label: '发请求2', value: 2 }, 12 | ]" 13 | :x-component-props="{ 14 | style: { 15 | width: '240px', 16 | }, 17 | }" 18 | /> 19 | <SchemaStringField 20 | name="select" 21 | title="异步选择框" 22 | x-decorator="FormItem" 23 | x-component="Select" 24 | :x-component-props="{ 25 | style: { 26 | width: '240px', 27 | }, 28 | }" 29 | /> 30 | </SchemaField> 31 | <Submit @submit="onSubmit">提交</Submit> 32 | </Form> 33 | </template> 34 | 35 | <script> 36 | import { createForm, onFieldReact } from '@formily/core' 37 | import { createSchemaField } from '@formily/vue' 38 | import { action } from '@formily/reactive' 39 | import { Form, FormItem, Select, Submit, Reset } from '@formily/element' 40 | 41 | const useAsyncDataSource = (pattern, service) => { 42 | onFieldReact(pattern, (field) => { 43 | field.loading = true 44 | service(field).then( 45 | action.bound((data) => { 46 | field.dataSource = data 47 | field.loading = false 48 | }) 49 | ) 50 | }) 51 | } 52 | 53 | const form = createForm({ 54 | effects: () => { 55 | useAsyncDataSource('select', async (field) => { 56 | const linkage = field.query('linkage').get('value') 57 | if (!linkage) return [] 58 | return new Promise((resolve) => { 59 | setTimeout(() => { 60 | if (linkage === 1) { 61 | resolve([ 62 | { 63 | label: 'AAA', 64 | value: 'aaa', 65 | }, 66 | { 67 | label: 'BBB', 68 | value: 'ccc', 69 | }, 70 | ]) 71 | } else if (linkage === 2) { 72 | resolve([ 73 | { 74 | label: 'CCC', 75 | value: 'ccc', 76 | }, 77 | { 78 | label: 'DDD', 79 | value: 'ddd', 80 | }, 81 | ]) 82 | } 83 | }, 1500) 84 | }) 85 | }) 86 | }, 87 | }) 88 | const fields = createSchemaField({ 89 | components: { 90 | FormItem, 91 | Select, 92 | }, 93 | }) 94 | 95 | export default { 96 | components: { Form, ...fields, Submit, Reset }, 97 | data() { 98 | return { 99 | form, 100 | } 101 | }, 102 | methods: { 103 | onSubmit(value) { 104 | console.log(value) 105 | }, 106 | }, 107 | } 108 | </script> 109 | ``` -------------------------------------------------------------------------------- /packages/element/docs/demos/guide/editable/markup-schema.vue: -------------------------------------------------------------------------------- ```vue 1 | <template> 2 | <FormProvider :form="form"> 3 | <SchemaField> 4 | <SchemaStringField 5 | name="date" 6 | title="日期" 7 | x-decorator="Editable" 8 | x-component="DatePicker" 9 | /> 10 | <SchemaStringField 11 | name="input" 12 | title="输入框" 13 | x-decorator="Editable" 14 | x-component="Input" 15 | /> 16 | <SchemaVoidField 17 | name="void" 18 | title="虚拟节点容器" 19 | x-component="Editable.Popover" 20 | :x-reactions=" 21 | (field) => { 22 | field.title = field.query('.void.date2').get('value') || field.title 23 | } 24 | " 25 | > 26 | <SchemaStringField 27 | name="date2" 28 | title="日期" 29 | x-decorator="FormItem" 30 | x-component="DatePicker" 31 | /> 32 | <SchemaStringField 33 | name="input2" 34 | title="输入框" 35 | x-decorator="FormItem" 36 | x-component="Input" 37 | /> 38 | </SchemaVoidField> 39 | <SchemaObjectField 40 | name="object" 41 | title="对象节点容器" 42 | x-component="Editable.Popover" 43 | :x-reactions=" 44 | (field) => { 45 | field.title = (field.value && field.value.date) || field.title 46 | } 47 | " 48 | > 49 | <SchemaStringField 50 | name="date" 51 | title="日期" 52 | x-decorator="FormItem" 53 | x-component="DatePicker" 54 | /> 55 | <SchemaStringField 56 | name="input" 57 | title="输入框" 58 | x-decorator="FormItem" 59 | x-component="Input" 60 | /> 61 | </SchemaObjectField> 62 | </SchemaField> 63 | <FormButtonGroup> 64 | <Submit @submit="log">提交</Submit> 65 | </FormButtonGroup> 66 | </FormProvider> 67 | </template> 68 | 69 | <script> 70 | import { createForm } from '@formily/core' 71 | import { FormProvider, createSchemaField } from '@formily/vue' 72 | import { 73 | FormButtonGroup, 74 | FormItem, 75 | Submit, 76 | Input, 77 | DatePicker, 78 | Editable, 79 | } from '@formily/element' 80 | import { Button } from 'element-ui' 81 | 82 | const SchemaField = createSchemaField({ 83 | components: { 84 | FormItem, 85 | Input, 86 | DatePicker, 87 | Editable, 88 | }, 89 | }) 90 | 91 | export default { 92 | components: { 93 | FormButtonGroup, 94 | FormProvider, 95 | Button, 96 | Submit, 97 | ...SchemaField, 98 | }, 99 | 100 | data() { 101 | const form = createForm() 102 | 103 | return { 104 | form, 105 | } 106 | }, 107 | methods: { 108 | log(values) { 109 | console.log(values) 110 | }, 111 | }, 112 | } 113 | </script> 114 | 115 | <style lang="scss" scoped></style> 116 | ``` -------------------------------------------------------------------------------- /packages/element/docs/demos/guide/date-picker/json-schema.vue: -------------------------------------------------------------------------------- ```vue 1 | <template> 2 | <Form :form="form"> 3 | <SchemaField :schema="schema" /> 4 | <Submit @submit="onSubmit">提交</Submit> 5 | </Form> 6 | </template> 7 | 8 | <script> 9 | import { createForm } from '@formily/core' 10 | import { createSchemaField } from '@formily/vue' 11 | import { Form, FormItem, DatePicker, Submit } from '@formily/element' 12 | 13 | const schema = { 14 | type: 'object', 15 | properties: { 16 | date: { 17 | type: 'string', 18 | title: '普通日期', 19 | 'x-decorator': 'FormItem', 20 | 'x-component': 'DatePicker', 21 | }, 22 | week: { 23 | type: 'string', 24 | title: '周', 25 | 'x-decorator': 'FormItem', 26 | 'x-component': 'DatePicker', 27 | 'x-component-props': { 28 | type: 'week', 29 | }, 30 | }, 31 | month: { 32 | type: 'string', 33 | title: '月', 34 | 'x-decorator': 'FormItem', 35 | 'x-component': 'DatePicker', 36 | 'x-component-props': { 37 | type: 'month', 38 | }, 39 | }, 40 | year: { 41 | type: 'string', 42 | title: '年', 43 | 'x-decorator': 'FormItem', 44 | 'x-component': 'DatePicker', 45 | 'x-component-props': { 46 | type: 'year', 47 | }, 48 | }, 49 | dateTime: { 50 | type: 'string', 51 | title: '日期时间', 52 | 'x-decorator': 'FormItem', 53 | 'x-component': 'DatePicker', 54 | 'x-component-props': { 55 | type: 'datetime', 56 | }, 57 | }, 58 | dates: { 59 | type: 'array', 60 | title: '多个日期', 61 | 'x-decorator': 'FormItem', 62 | 'x-component': 'DatePicker', 63 | 'x-component-props': { 64 | type: 'dates', 65 | }, 66 | }, 67 | dateRange: { 68 | type: 'string', 69 | title: '日期范围', 70 | 'x-decorator': 'FormItem', 71 | 'x-component': 'DatePicker', 72 | 'x-component-props': { 73 | type: 'daterange', 74 | }, 75 | }, 76 | monthRange: { 77 | type: 'string', 78 | title: '月范围', 79 | 'x-decorator': 'FormItem', 80 | 'x-component': 'DatePicker', 81 | 'x-component-props': { 82 | type: 'monthrange', 83 | }, 84 | }, 85 | dateTimeRange: { 86 | type: 'string', 87 | title: '日期时间范围', 88 | 'x-decorator': 'FormItem', 89 | 'x-component': 'DatePicker', 90 | 'x-component-props': { 91 | type: 'datetimerange', 92 | }, 93 | }, 94 | }, 95 | } 96 | 97 | const form = createForm() 98 | const { SchemaField } = createSchemaField({ 99 | components: { 100 | FormItem, 101 | DatePicker, 102 | }, 103 | }) 104 | 105 | export default { 106 | components: { Form, SchemaField, Submit }, 107 | data() { 108 | return { 109 | form, 110 | schema, 111 | } 112 | }, 113 | methods: { 114 | onSubmit(value) { 115 | console.log(value) 116 | }, 117 | }, 118 | } 119 | </script> 120 | ``` -------------------------------------------------------------------------------- /packages/reactive/docs/api/autorun.md: -------------------------------------------------------------------------------- ```markdown 1 | # autorun 2 | 3 | ## Description 4 | 5 | Receive a tracker function, if there is observable data in the function, the tracker function will be executed repeatedly when the data changes 6 | 7 | ## Signature 8 | 9 | ```ts 10 | interface autorun { 11 | (tracker: () => void, name?: string): void 12 | } 13 | ``` 14 | 15 | ## Example 16 | 17 | ```ts 18 | import { observable, autorun } from '@formily/reactive' 19 | 20 | const obs = observable({}) 21 | 22 | const dispose = autorun(() => { 23 | console.log(obs.aa) 24 | }) 25 | 26 | obs.aa = 123 27 | 28 | dispose() 29 | ``` 30 | 31 | ## autorun.memo 32 | 33 | ### Description 34 | 35 | Used in autorun to create persistent reference data, only re-execute memo internal functions due to dependency changes 36 | 37 | Note: Please do not use it in If/For statements, because it depends on the execution order to bind the current autorun 38 | 39 | ### Signature 40 | 41 | ```ts 42 | interface memo<T> { 43 | (callback: () => T, dependencies: any[] = []): T 44 | } 45 | ``` 46 | 47 | Note: The default dependency is `[]`, that is, if the dependency is not passed, it means that the second time will never be executed 48 | 49 | ### Example 50 | 51 | ```ts 52 | import { observable, autorun } from '@formily/reactive' 53 | 54 | const obs1 = observable({ 55 | aa: 0, 56 | }) 57 | 58 | const dispose = autorun(() => { 59 | const obs2 = autorun.memo(() => 60 | observable({ 61 | bb: 0, 62 | }) 63 | ) 64 | console.log(obs1.aa, obs2.bb++) 65 | }) 66 | 67 | obs1.aa++ 68 | obs1.aa++ 69 | obs1.aa++ 70 | //Execute four times, the output result is 71 | /** 72 | * 0 0 73 | * 1 1 74 | * twenty two 75 | * 3 3 76 | */ 77 | 78 | dispose() 79 | ``` 80 | 81 | ## autorun.effect 82 | 83 | ### Description 84 | 85 | In autorun, it is used to respond to the next micro task timing of autorun's first execution and the dispose of responding to autorun 86 | 87 | Note: Please do not use it in If/For statements, because it depends on the execution order to bind the current autorun 88 | 89 | ### Signature 90 | 91 | ```ts 92 | interface effect { 93 | (callback: () => void | (() => void), dependencies: any[] = [{}]): void 94 | } 95 | ``` 96 | 97 | Note: The default dependency is `[{}]`, that is, if the dependency is not passed, the representative will continue to execute, because the internal dirty check is a shallow comparison 98 | 99 | ### Example 100 | 101 | ```ts 102 | import { observable, autorun } from '@formily/reactive' 103 | 104 | const obs1 = observable({ 105 | aa: 0, 106 | }) 107 | const dispose = autorun(() => { 108 | const obs2 = autorun.memo(() => 109 | observable({ 110 | bb: 0, 111 | }) 112 | ) 113 | console.log(obs1.aa, obs2.bb++) 114 | autorun.effect(() => { 115 | obs2.bb++ 116 | }, []) 117 | }) 118 | obs1.aa++ 119 | obs1.aa++ 120 | obs1.aa++ 121 | //Execute five times, the output result is 122 | /** 123 | * 0 0 124 | * 1 1 125 | * twenty two 126 | * 3 3 127 | * 3 5 128 | */ 129 | 130 | dispose() 131 | ``` 132 | ``` -------------------------------------------------------------------------------- /packages/reactive/docs/api/observable.md: -------------------------------------------------------------------------------- ```markdown 1 | # observable 2 | 3 | > Mainly used to create observable objects with different responsive behaviors, and can be used as an annotation to define to mark responsive attributes 4 | 5 | ## observable/observable.deep 6 | 7 | ### Description 8 | 9 | Create deep hijacking responsive objects 10 | 11 | ### Signature 12 | 13 | ```ts 14 | interface observable<T extends object> { 15 | (target: T): T 16 | } 17 | 18 | interface deep<T extends object> { 19 | (target: T): T 20 | } 21 | ``` 22 | 23 | ### Example 24 | 25 | ```ts 26 | import { observable, autorun } from '@formily/reactive' 27 | 28 | const obs = observable({ 29 | aa: { 30 | bb: 123, 31 | }, 32 | }) 33 | 34 | autorun(() => { 35 | console.log(obs.aa.bb) 36 | }) 37 | 38 | obs.aa.bb = 321 39 | ``` 40 | 41 | ## observable.shallow 42 | 43 | ### Description 44 | 45 | Create shallow hijacking responsive objects, that is, only respond to the first-level attribute operations of the target object 46 | 47 | ### Signature 48 | 49 | ```ts 50 | interface shallow<T extends object> { 51 | (target: T): T 52 | } 53 | ``` 54 | 55 | ### Example 56 | 57 | ```ts 58 | import { observable, autorun } from '@formily/reactive' 59 | 60 | const obs = observable.shallow({ 61 | aa: { 62 | bb: 111, 63 | }, 64 | }) 65 | 66 | autorun(() => { 67 | console.log(obs.aa.bb) 68 | }) 69 | 70 | obs.aa.bb = 222 // will not respond 71 | obs.aa = { bb: 333 } // can respond 72 | ``` 73 | 74 | ## observable.computed 75 | 76 | ### Description 77 | 78 | Create a calculation buffer 79 | 80 | ### Signature 81 | 82 | ```ts 83 | interface computed { 84 | <T extends () => any>(target: T): { value: ReturnType<T> } 85 | <T extends { get?: () => any; set?: (value: any) => void }>(target: T): { 86 | value: ReturnType<T['get']> 87 | } 88 | } 89 | ``` 90 | 91 | ### Example 92 | 93 | ```ts 94 | import { observable, autorun } from '@formily/reactive' 95 | 96 | const obs = observable({ 97 | aa: 11, 98 | bb: 22, 99 | }) 100 | 101 | const computed = observable.computed(() => obs.aa + obs.bb) 102 | 103 | autorun(() => { 104 | console.log(computed.value) 105 | }) 106 | 107 | obs.aa = 33 108 | ``` 109 | 110 | ## observable.ref 111 | 112 | ### Description 113 | 114 | Create reference hijacking responsive objects 115 | 116 | ### Signature 117 | 118 | ```ts 119 | interface ref<T extends object> { 120 | (target: T): { value: T } 121 | } 122 | ``` 123 | 124 | ### Example 125 | 126 | ```ts 127 | import { observable, autorun } from '@formily/reactive' 128 | 129 | const ref = observable.ref(1) 130 | 131 | autorun(() => { 132 | console.log(ref.value) 133 | }) 134 | 135 | ref.value = 2 136 | ``` 137 | 138 | ## observable.box 139 | 140 | ### Description 141 | 142 | Similar to ref, except that the data is read and written through the get/set method 143 | 144 | ### Signature 145 | 146 | ```ts 147 | interface box<T extends object> { 148 | (target: T): { get: () => T; set: (value: T) => void } 149 | } 150 | ``` 151 | 152 | ### Example 153 | 154 | ```ts 155 | import { observable, autorun } from '@formily/reactive' 156 | 157 | const box = observable.box(1) 158 | 159 | autorun(() => { 160 | console.log(box.get()) 161 | }) 162 | 163 | box.set(2) 164 | ``` 165 | ``` -------------------------------------------------------------------------------- /packages/grid/src/observer.ts: -------------------------------------------------------------------------------- ```typescript 1 | const isHTMLElement = (node: Node): node is HTMLElement => node.nodeType === 1 2 | 3 | type ChildNode = { 4 | element?: HTMLElement 5 | observer?: MutationObserver 6 | dispose?: () => void 7 | } 8 | 9 | export class ChildListMutationObserver { 10 | observer: MutationObserver 11 | callback: MutationCallback 12 | childList: ChildNode[] = [] 13 | init: MutationObserverInit 14 | constructor(callback: MutationCallback) { 15 | this.callback = callback 16 | this.observer = new MutationObserver(this.handler) 17 | } 18 | 19 | observeChildList(element: HTMLElement) { 20 | Array.from(element.children).forEach((node: HTMLElement) => { 21 | this.addObserver(node) 22 | }) 23 | } 24 | 25 | addObserver(element: HTMLElement) { 26 | const child = this.childList.find((t) => t.element === element) 27 | if (!child) { 28 | const childIndex = this.childList.length 29 | const child = { 30 | element, 31 | observer: new MutationObserver(this.callback), 32 | dispose: () => { 33 | if (child.observer) { 34 | child.observer.disconnect() 35 | delete child.observer 36 | this.childList.splice(childIndex, 1) 37 | } 38 | }, 39 | } 40 | child.observer.observe(child.element, { 41 | ...this.init, 42 | subtree: false, 43 | childList: false, 44 | characterData: false, 45 | characterDataOldValue: false, 46 | attributeOldValue: false, 47 | }) 48 | this.childList.push(child) 49 | } 50 | } 51 | 52 | removeObserver(element: HTMLElement) { 53 | const child = this.childList.find((t) => t.element === element) 54 | if (child) { 55 | child.dispose?.() 56 | } 57 | } 58 | 59 | handler = (mutations: MutationRecord[]) => { 60 | mutations.forEach((mutation) => { 61 | if (mutation.type === 'childList') { 62 | mutation.addedNodes.forEach((node) => { 63 | if (isHTMLElement(node)) { 64 | this.addObserver(node) 65 | } 66 | }) 67 | mutation.removedNodes.forEach((node) => { 68 | if (isHTMLElement(node)) { 69 | this.removeObserver(node) 70 | } 71 | }) 72 | } 73 | }) 74 | this.callback(mutations, this.observer) 75 | } 76 | 77 | observe = (element: HTMLElement, init?: MutationObserverInit) => { 78 | this.init = init 79 | this.observeChildList(element) 80 | this.observer.observe(element, { 81 | ...this.init, 82 | subtree: false, 83 | childList: true, 84 | characterData: false, 85 | characterDataOldValue: false, 86 | attributeOldValue: false, 87 | }) 88 | } 89 | 90 | disconnect = () => { 91 | this.observer.disconnect() 92 | } 93 | } 94 | ``` -------------------------------------------------------------------------------- /packages/vue/src/vue2-components.ts: -------------------------------------------------------------------------------- ```typescript 1 | // This file just converts types 2 | import * as components from './components' 3 | 4 | import type Vue from 'vue' 5 | import type { VueConstructor } from 'vue' 6 | import type { 7 | IVoidFieldProps, 8 | IArrayFieldProps, 9 | IObjectFieldProps, 10 | IFieldProps, 11 | IRecursionFieldProps, 12 | IProviderProps, 13 | ISchemaMarkupFieldProps, 14 | ISchemaFieldProps, 15 | ISchemaFieldVueFactoryOptions, 16 | ISchemaTypeFieldProps, 17 | SchemaVueComponents, 18 | } from './types' 19 | 20 | const { 21 | Field: _Field, 22 | ArrayField: _ArrayField, 23 | FormConsumer: _FormConsumer, 24 | FormProvider: _FormProvider, 25 | ObjectField: _ObjectField, 26 | RecursionField: _RecursionField, 27 | VoidField: _VoidField, 28 | createSchemaField: _createSchemaField, 29 | } = components 30 | 31 | type DefineComponent<Props> = Vue & VueConstructor & Props 32 | 33 | type SchemaFieldComponents = { 34 | SchemaField: DefineComponent<Omit<ISchemaFieldProps, 'name' | 'components'>> 35 | SchemaMarkupField: DefineComponent<ISchemaMarkupFieldProps> 36 | SchemaStringField: DefineComponent<ISchemaTypeFieldProps> 37 | SchemaObjectField: DefineComponent<ISchemaTypeFieldProps> 38 | SchemaArrayField: DefineComponent<ISchemaTypeFieldProps> 39 | SchemaBooleanField: DefineComponent<ISchemaTypeFieldProps> 40 | SchemaDateField: DefineComponent<ISchemaTypeFieldProps> 41 | SchemaDateTimeField: DefineComponent<ISchemaTypeFieldProps> 42 | SchemaVoidField: DefineComponent<ISchemaTypeFieldProps> 43 | SchemaNumberField: DefineComponent<ISchemaTypeFieldProps> 44 | } 45 | 46 | type CreateSchemaField< 47 | Components extends SchemaVueComponents = SchemaVueComponents 48 | > = ( 49 | options: ISchemaFieldVueFactoryOptions<Components> 50 | ) => SchemaFieldComponents 51 | 52 | const Field = _Field as unknown as DefineComponent<Omit<IFieldProps, 'name'>> 53 | const ArrayField = _ArrayField as unknown as DefineComponent< 54 | Omit<IArrayFieldProps, 'name'> 55 | > 56 | const ObjectField = _ObjectField as unknown as DefineComponent< 57 | Omit<IObjectFieldProps, 'name'> 58 | > 59 | const VoidField = _VoidField as unknown as DefineComponent< 60 | Omit<IVoidFieldProps, 'name'> 61 | > 62 | const RecursionField = _RecursionField as unknown as DefineComponent< 63 | Omit<IRecursionFieldProps, 'name'> 64 | > 65 | const FormConsumer = _FormConsumer as unknown as DefineComponent<{}> 66 | const FormProvider = _FormProvider as unknown as DefineComponent<IProviderProps> 67 | const createSchemaField = _createSchemaField as unknown as CreateSchemaField 68 | 69 | export { 70 | Field, 71 | ArrayField, 72 | ObjectField, 73 | VoidField, 74 | RecursionField, 75 | FormConsumer, 76 | FormProvider, 77 | createSchemaField, 78 | } 79 | ``` -------------------------------------------------------------------------------- /packages/antd/docs/components/NumberPicker.zh-CN.md: -------------------------------------------------------------------------------- ```markdown 1 | # NumberPicker 2 | 3 | > 数字输入框 4 | 5 | ## Markup Schema 案例 6 | 7 | ```tsx 8 | import React from 'react' 9 | import { NumberPicker, 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 | NumberPicker, 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="NumberPicker" 30 | required 31 | x-component-props={{ 32 | style: { 33 | width: 240, 34 | }, 35 | }} 36 | /> 37 | </SchemaField> 38 | <FormButtonGroup> 39 | <Submit onSubmit={console.log}>提交</Submit> 40 | </FormButtonGroup> 41 | </FormProvider> 42 | ) 43 | ``` 44 | 45 | ## JSON Schema 案例 46 | 47 | ```tsx 48 | import React from 'react' 49 | import { NumberPicker, FormItem, FormButtonGroup, Submit } from '@formily/antd' 50 | import { createForm } from '@formily/core' 51 | import { FormProvider, createSchemaField } from '@formily/react' 52 | 53 | const SchemaField = createSchemaField({ 54 | components: { 55 | NumberPicker, 56 | FormItem, 57 | }, 58 | }) 59 | 60 | const form = createForm() 61 | 62 | const schema = { 63 | type: 'object', 64 | properties: { 65 | input: { 66 | type: 'string', 67 | title: '输入框', 68 | 'x-decorator': 'FormItem', 69 | 'x-component': 'NumberPicker', 70 | 'x-component-props': { 71 | style: { 72 | width: 240, 73 | }, 74 | }, 75 | }, 76 | }, 77 | } 78 | 79 | export default () => ( 80 | <FormProvider form={form}> 81 | <SchemaField schema={schema} /> 82 | <FormButtonGroup> 83 | <Submit onSubmit={console.log}>提交</Submit> 84 | </FormButtonGroup> 85 | </FormProvider> 86 | ) 87 | ``` 88 | 89 | ## 纯 JSX 案例 90 | 91 | ```tsx 92 | import React from 'react' 93 | import { NumberPicker, FormItem, FormButtonGroup, Submit } from '@formily/antd' 94 | import { createForm } from '@formily/core' 95 | import { FormProvider, Field } from '@formily/react' 96 | 97 | const form = createForm() 98 | 99 | export default () => ( 100 | <FormProvider form={form}> 101 | <Field 102 | name="input" 103 | title="输入框" 104 | required 105 | decorator={[FormItem]} 106 | component={[ 107 | NumberPicker, 108 | { 109 | style: { 110 | width: 240, 111 | }, 112 | }, 113 | ]} 114 | /> 115 | <FormButtonGroup> 116 | <Submit onSubmit={console.log}>提交</Submit> 117 | </FormButtonGroup> 118 | </FormProvider> 119 | ) 120 | ``` 121 | 122 | ## API 123 | 124 | 参考 https://ant.design/components/input-number-cn/ 125 | ``` -------------------------------------------------------------------------------- /packages/element/docs/demos/guide/array-cards/markup-schema.vue: -------------------------------------------------------------------------------- ```vue 1 | <template> 2 | <FormProvider :form="form"> 3 | <SchemaField> 4 | <SchemaArrayField 5 | name="string_array" 6 | :maxItems="3" 7 | x-decorator="FormItem" 8 | x-component="ArrayCards" 9 | :x-component-props="{ 10 | title: '字符串数组', 11 | }" 12 | > 13 | <SchemaVoidField> 14 | <SchemaVoidField x-component="ArrayCards.Index" /> 15 | <SchemaStringField 16 | name="input" 17 | x-decorator="FormItem" 18 | title="Input" 19 | required 20 | x-component="Input" 21 | /> 22 | <SchemaVoidField x-component="ArrayCards.Remove" /> 23 | <SchemaVoidField x-component="ArrayCards.MoveUp" /> 24 | <SchemaVoidField x-component="ArrayCards.MoveDown" /> 25 | </SchemaVoidField> 26 | <SchemaVoidField x-component="ArrayCards.Addition" title="添加条目" /> 27 | </SchemaArrayField> 28 | <SchemaArrayField 29 | name="array" 30 | :maxItems="3" 31 | x-decorator="FormItem" 32 | x-component="ArrayCards" 33 | :x-component-props="{ 34 | title: '对象数组', 35 | }" 36 | > 37 | <SchemaObjectField> 38 | <SchemaVoidField x-component="ArrayCards.Index" /> 39 | <SchemaStringField 40 | name="input" 41 | x-decorator="FormItem" 42 | title="Input" 43 | required 44 | x-component="Input" 45 | /> 46 | <SchemaVoidField x-component="ArrayCards.Remove" /> 47 | <SchemaVoidField x-component="ArrayCards.MoveUp" /> 48 | <SchemaVoidField x-component="ArrayCards.MoveDown" /> 49 | </SchemaObjectField> 50 | <SchemaVoidField x-component="ArrayCards.Addition" title="添加条目" /> 51 | </SchemaArrayField> 52 | </SchemaField> 53 | <Submit @submit="log">提交</Submit> 54 | </FormProvider> 55 | </template> 56 | 57 | <script> 58 | import { createForm } from '@formily/core' 59 | import { FormProvider, createSchemaField } from '@formily/vue' 60 | import { 61 | FormItem, 62 | FormButtonGroup, 63 | Submit, 64 | Input, 65 | ArrayCards, 66 | } from '@formily/element' 67 | import { Button } from 'element-ui' 68 | 69 | const SchemaField = createSchemaField({ 70 | components: { 71 | FormItem, 72 | Input, 73 | ArrayCards, 74 | }, 75 | }) 76 | 77 | export default { 78 | components: { 79 | FormProvider, 80 | FormButtonGroup, 81 | Button, 82 | Submit, 83 | ...SchemaField, 84 | }, 85 | 86 | data() { 87 | const form = createForm() 88 | 89 | return { 90 | form, 91 | } 92 | }, 93 | methods: { 94 | log(values) { 95 | console.log(values) 96 | }, 97 | }, 98 | } 99 | </script> 100 | 101 | <style lang="scss" scoped></style> 102 | ``` -------------------------------------------------------------------------------- /packages/next/docs/components/NumberPicker.zh-CN.md: -------------------------------------------------------------------------------- ```markdown 1 | # NumberPicker 2 | 3 | > 数字输入框 4 | 5 | ## Markup Schema 案例 6 | 7 | ```tsx 8 | import React from 'react' 9 | import { NumberPicker, 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 | NumberPicker, 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="NumberPicker" 30 | required 31 | x-component-props={{ 32 | style: { 33 | width: 240, 34 | }, 35 | }} 36 | /> 37 | </SchemaField> 38 | <FormButtonGroup> 39 | <Submit onSubmit={console.log}>提交</Submit> 40 | </FormButtonGroup> 41 | </FormProvider> 42 | ) 43 | ``` 44 | 45 | ## JSON Schema 案例 46 | 47 | ```tsx 48 | import React from 'react' 49 | import { NumberPicker, FormItem, FormButtonGroup, Submit } from '@formily/next' 50 | import { createForm } from '@formily/core' 51 | import { FormProvider, createSchemaField } from '@formily/react' 52 | 53 | const SchemaField = createSchemaField({ 54 | components: { 55 | NumberPicker, 56 | FormItem, 57 | }, 58 | }) 59 | 60 | const form = createForm() 61 | 62 | const schema = { 63 | type: 'object', 64 | properties: { 65 | input: { 66 | type: 'string', 67 | title: '输入框', 68 | 'x-decorator': 'FormItem', 69 | 'x-component': 'NumberPicker', 70 | 'x-component-props': { 71 | style: { 72 | width: 240, 73 | }, 74 | }, 75 | }, 76 | }, 77 | } 78 | 79 | export default () => ( 80 | <FormProvider form={form}> 81 | <SchemaField schema={schema} /> 82 | <FormButtonGroup> 83 | <Submit onSubmit={console.log}>提交</Submit> 84 | </FormButtonGroup> 85 | </FormProvider> 86 | ) 87 | ``` 88 | 89 | ## 纯 JSX 案例 90 | 91 | ```tsx 92 | import React from 'react' 93 | import { NumberPicker, FormItem, FormButtonGroup, Submit } from '@formily/next' 94 | import { createForm } from '@formily/core' 95 | import { FormProvider, Field } from '@formily/react' 96 | 97 | const form = createForm() 98 | 99 | export default () => ( 100 | <FormProvider form={form}> 101 | <Field 102 | name="input" 103 | title="输入框" 104 | required 105 | decorator={[FormItem]} 106 | component={[ 107 | NumberPicker, 108 | { 109 | style: { 110 | width: 240, 111 | }, 112 | }, 113 | ]} 114 | /> 115 | <FormButtonGroup> 116 | <Submit onSubmit={console.log}>提交</Submit> 117 | </FormButtonGroup> 118 | </FormProvider> 119 | ) 120 | ``` 121 | 122 | ## API 123 | 124 | 参考 https://fusion.design/pc/component/basic/number-picker 125 | ``` -------------------------------------------------------------------------------- /packages/element/docs/demos/guide/date-picker/markup-schema.vue: -------------------------------------------------------------------------------- ```vue 1 | <template> 2 | <Form :form="form"> 3 | <SchemaField> 4 | <SchemaStringField 5 | name="date" 6 | title="普通日期" 7 | x-decorator="FormItem" 8 | x-component="DatePicker" 9 | /> 10 | <SchemaStringField 11 | name="week" 12 | title="周" 13 | x-decorator="FormItem" 14 | x-component="DatePicker" 15 | :x-component-props="{ 16 | type: 'week', 17 | }" 18 | /> 19 | <SchemaStringField 20 | name="month" 21 | title="月" 22 | x-decorator="FormItem" 23 | x-component="DatePicker" 24 | :x-component-props="{ 25 | type: 'month', 26 | }" 27 | /> 28 | <SchemaStringField 29 | name="year" 30 | title="年" 31 | x-decorator="FormItem" 32 | x-component="DatePicker" 33 | :x-component-props="{ 34 | type: 'year', 35 | }" 36 | /> 37 | <SchemaStringField 38 | name="dateTime" 39 | title="日期时间" 40 | x-decorator="FormItem" 41 | x-component="DatePicker" 42 | :x-component-props="{ 43 | type: 'datetime', 44 | }" 45 | /> 46 | <SchemaArrayField 47 | name="dates" 48 | title="多个日期" 49 | x-decorator="FormItem" 50 | x-component="DatePicker" 51 | :x-component-props="{ 52 | type: 'dates', 53 | }" 54 | /> 55 | <SchemaArrayField 56 | name="dateRange" 57 | title="日期范围" 58 | x-decorator="FormItem" 59 | x-component="DatePicker" 60 | :x-component-props="{ 61 | type: 'daterange', 62 | }" 63 | /> 64 | <SchemaArrayField 65 | name="monthRange" 66 | title="月范围" 67 | x-decorator="FormItem" 68 | x-component="DatePicker" 69 | :x-component-props="{ 70 | type: 'monthrange', 71 | }" 72 | /> 73 | <SchemaArrayField 74 | name="dateTimeRange" 75 | title="日期时间范围" 76 | x-decorator="FormItem" 77 | x-component="DatePicker" 78 | :x-component-props="{ 79 | type: 'datetimerange', 80 | }" 81 | /> 82 | </SchemaField> 83 | <Submit @submit="onSubmit">提交</Submit> 84 | </Form> 85 | </template> 86 | 87 | <script> 88 | import { createForm } from '@formily/core' 89 | import { createSchemaField } from '@formily/vue' 90 | import { Form, FormItem, DatePicker, Submit } from '@formily/element' 91 | 92 | const form = createForm() 93 | const fields = createSchemaField({ 94 | components: { 95 | FormItem, 96 | DatePicker, 97 | }, 98 | }) 99 | 100 | export default { 101 | components: { Form, ...fields, Submit }, 102 | data() { 103 | return { 104 | form, 105 | } 106 | }, 107 | methods: { 108 | onSubmit(value) { 109 | console.log(value) 110 | }, 111 | }, 112 | } 113 | </script> ``` -------------------------------------------------------------------------------- /packages/antd/src/__builtins__/render.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { ReactElement } from 'react' 2 | import * as ReactDOM from 'react-dom' 3 | import type { Root } from 'react-dom/client' 4 | 5 | // 移植自rc-util: https://github.com/react-component/util/blob/master/src/React/render.ts 6 | 7 | type CreateRoot = (container: ContainerType) => Root 8 | 9 | // Let compiler not to search module usage 10 | const fullClone = { 11 | ...ReactDOM, 12 | } as typeof ReactDOM & { 13 | __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED?: { 14 | usingClientEntryPoint?: boolean 15 | } 16 | createRoot?: CreateRoot 17 | } 18 | 19 | const { version, render: reactRender, unmountComponentAtNode } = fullClone 20 | 21 | let createRoot: CreateRoot 22 | try { 23 | const mainVersion = Number((version || '').split('.')[0]) 24 | if (mainVersion >= 18 && fullClone.createRoot) { 25 | // eslint-disable-next-line @typescript-eslint/no-var-requires 26 | createRoot = fullClone.createRoot 27 | } 28 | } catch (e) { 29 | // Do nothing; 30 | } 31 | 32 | function toggleWarning(skip: boolean) { 33 | const { __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED } = fullClone 34 | 35 | if ( 36 | __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED && 37 | typeof __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED === 'object' 38 | ) { 39 | __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.usingClientEntryPoint = 40 | skip 41 | } 42 | } 43 | 44 | const MARK = '__antd_mobile_root__' 45 | 46 | // ========================== Render ========================== 47 | type ContainerType = (Element | DocumentFragment) & { 48 | [MARK]?: Root 49 | } 50 | 51 | function legacyRender(node: ReactElement, container: ContainerType) { 52 | reactRender(node, container) 53 | } 54 | 55 | function concurrentRender(node: ReactElement, container: ContainerType) { 56 | toggleWarning(true) 57 | const root = container[MARK] || createRoot(container) 58 | toggleWarning(false) 59 | root.render(node) 60 | container[MARK] = root 61 | } 62 | 63 | export function render(node: ReactElement, container: ContainerType) { 64 | if (createRoot as unknown) { 65 | concurrentRender(node, container) 66 | return 67 | } 68 | legacyRender(node, container) 69 | } 70 | 71 | // ========================== Unmount ========================= 72 | function legacyUnmount(container: ContainerType) { 73 | return unmountComponentAtNode(container) 74 | } 75 | 76 | async function concurrentUnmount(container: ContainerType) { 77 | // Delay to unmount to avoid React 18 sync warning 78 | return Promise.resolve().then(() => { 79 | container[MARK]?.unmount() 80 | delete container[MARK] 81 | }) 82 | } 83 | 84 | export function unmount(container: ContainerType) { 85 | if (createRoot as unknown) { 86 | return concurrentUnmount(container) 87 | } 88 | 89 | return legacyUnmount(container) 90 | } ``` -------------------------------------------------------------------------------- /packages/next/src/__builtins__/render.ts: -------------------------------------------------------------------------------- ```typescript 1 | import { ReactElement } from 'react' 2 | import * as ReactDOM from 'react-dom' 3 | import type { Root } from 'react-dom/client' 4 | 5 | // 移植自rc-util: https://github.com/react-component/util/blob/master/src/React/render.ts 6 | 7 | type CreateRoot = (container: ContainerType) => Root 8 | 9 | // Let compiler not to search module usage 10 | const fullClone = { 11 | ...ReactDOM, 12 | } as typeof ReactDOM & { 13 | __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED?: { 14 | usingClientEntryPoint?: boolean 15 | } 16 | createRoot?: CreateRoot 17 | } 18 | 19 | const { version, render: reactRender, unmountComponentAtNode } = fullClone 20 | 21 | let createRoot: CreateRoot 22 | try { 23 | const mainVersion = Number((version || '').split('.')[0]) 24 | if (mainVersion >= 18 && fullClone.createRoot) { 25 | // eslint-disable-next-line @typescript-eslint/no-var-requires 26 | createRoot = fullClone.createRoot 27 | } 28 | } catch (e) { 29 | // Do nothing; 30 | } 31 | 32 | function toggleWarning(skip: boolean) { 33 | const { __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED } = fullClone 34 | 35 | if ( 36 | __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED && 37 | typeof __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED === 'object' 38 | ) { 39 | __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.usingClientEntryPoint = 40 | skip 41 | } 42 | } 43 | 44 | const MARK = '__antd_mobile_root__' 45 | 46 | // ========================== Render ========================== 47 | type ContainerType = (Element | DocumentFragment) & { 48 | [MARK]?: Root 49 | } 50 | 51 | function legacyRender(node: ReactElement, container: ContainerType) { 52 | reactRender(node, container) 53 | } 54 | 55 | function concurrentRender(node: ReactElement, container: ContainerType) { 56 | toggleWarning(true) 57 | const root = container[MARK] || createRoot(container) 58 | toggleWarning(false) 59 | root.render(node) 60 | container[MARK] = root 61 | } 62 | 63 | export function render(node: ReactElement, container: ContainerType) { 64 | if (createRoot as unknown) { 65 | concurrentRender(node, container) 66 | return 67 | } 68 | legacyRender(node, container) 69 | } 70 | 71 | // ========================== Unmount ========================= 72 | function legacyUnmount(container: ContainerType) { 73 | return unmountComponentAtNode(container) 74 | } 75 | 76 | async function concurrentUnmount(container: ContainerType) { 77 | // Delay to unmount to avoid React 18 sync warning 78 | return Promise.resolve().then(() => { 79 | container[MARK]?.unmount() 80 | delete container[MARK] 81 | }) 82 | } 83 | 84 | export function unmount(container: ContainerType) { 85 | if (createRoot as unknown) { 86 | return concurrentUnmount(container) 87 | } 88 | 89 | return legacyUnmount(container) 90 | } ```