This is page 2 of 35. Use http://codebase.md/alibaba/formily?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/react/src/hooks/useExpressionScope.ts: -------------------------------------------------------------------------------- ```typescript import { useContext } from 'react' import { SchemaExpressionScopeContext } from '../shared/context' export const useExpressionScope = () => useContext(SchemaExpressionScopeContext) ``` -------------------------------------------------------------------------------- /packages/reactive/src/untracked.ts: -------------------------------------------------------------------------------- ```typescript import { createBoundaryFunction } from './internals' import { untrackStart, untrackEnd } from './reaction' export const untracked = createBoundaryFunction(untrackStart, untrackEnd) ``` -------------------------------------------------------------------------------- /packages/vue/tsconfig.build.json: -------------------------------------------------------------------------------- ```json { "extends": "./tsconfig.json", "compilerOptions": { "outDir": "./lib", "paths": { "@formily/*": ["packages/*", "devtools/*"] }, "declaration": false } } ``` -------------------------------------------------------------------------------- /packages/react/src/hooks/index.ts: -------------------------------------------------------------------------------- ```typescript export * from './useForm' export * from './useField' export * from './useParentForm' export * from './useFieldSchema' export * from './useFormEffects' export * from './useExpressionScope' ``` -------------------------------------------------------------------------------- /packages/vue/src/global.d.ts: -------------------------------------------------------------------------------- ```typescript /// <reference types="@formily/core" /> /// <reference types="@formily/json-schema" /> import * as Types from './types' declare global { namespace Formily.Vue { export { Types } } } ``` -------------------------------------------------------------------------------- /packages/vue/src/index.ts: -------------------------------------------------------------------------------- ```typescript export * from '@formily/json-schema' export * from './components' export * from './shared' export * from './hooks' export * from './types' export * as Vue2Components from './vue2-components' ``` -------------------------------------------------------------------------------- /packages/element/src/form-tab/style.ts: -------------------------------------------------------------------------------- ```typescript import './style.scss' import 'element-ui/packages/theme-chalk/src/tabs.scss' import 'element-ui/packages/theme-chalk/src/tab-pane.scss' import 'element-ui/packages/theme-chalk/src/badge.scss' ``` -------------------------------------------------------------------------------- /packages/react/src/global.d.ts: -------------------------------------------------------------------------------- ```typescript /// <reference types="@formily/core" /> /// <reference types="@formily/json-schema" /> import * as Types from './types' declare global { namespace Formily.React { export { Types } } } ``` -------------------------------------------------------------------------------- /packages/antd/src/form-grid/style.less: -------------------------------------------------------------------------------- ``` @root-entry-name: 'default'; @import (reference) '~antd/es/style/themes/index.less'; @form-grid-prefix-cls: ~'@{ant-prefix}-formily-grid'; .@{form-grid-prefix-cls}-layout { display: grid; } ``` -------------------------------------------------------------------------------- /packages/element/src/form-drawer/style.ts: -------------------------------------------------------------------------------- ```typescript import './style.scss' import 'element-ui/packages/theme-chalk/src/drawer.scss' import 'element-ui/packages/theme-chalk/src/button.scss' import 'element-ui/packages/theme-chalk/src/loading.scss' ``` -------------------------------------------------------------------------------- /packages/vue/docs/.vuepress/enhanceApp.js: -------------------------------------------------------------------------------- ```javascript import pageComponents from '@internal/page-components' export default ({ Vue }) => { for (const [name, component] of Object.entries(pageComponents)) { Vue.component(name, component) } } ``` -------------------------------------------------------------------------------- /packages/next/src/__builtins__/pickDataProps.ts: -------------------------------------------------------------------------------- ```typescript export const pickDataProps = (props: any = {}) => { return Object.keys(props).reduce((buf, key) => { if (key.includes('data-')) { buf[key] = props[key] } return buf }, {}) } ``` -------------------------------------------------------------------------------- /packages/core/tsconfig.build.json: -------------------------------------------------------------------------------- ```json { "extends": "./tsconfig.json", "compilerOptions": { "outDir": "./lib", "paths": { "@formily/*": ["packages/*", "devtools/*"] }, "declaration": true, "types": [] } } ``` -------------------------------------------------------------------------------- /docs/guide/scenes/step-form.md: -------------------------------------------------------------------------------- ```markdown # Step-by-Step Form Mainly use the [FormStep](https://antd.formilyjs.org/components/form-step) component in [@formily/antd](https://antd.formilyjs.org) or [@formily/next](ttps://next.formilyjs.org) ``` -------------------------------------------------------------------------------- /packages/next/tsconfig.json: -------------------------------------------------------------------------------- ```json { "extends": "../../tsconfig.json", "include": ["./src/**/*.js", "./src/**/*.ts", "./src/**/*.tsx"], "exclude": ["./src/__tests__/*"], "compilerOptions": { "lib": ["ESNext", "DOM"] } } ``` -------------------------------------------------------------------------------- /packages/antd/src/__builtins__/pickDataProps.ts: -------------------------------------------------------------------------------- ```typescript export const pickDataProps = (props: any = {}) => { const results = {} for (let key in props) { if (key.indexOf('data-') > -1) { results[key] = props[key] } } return results } ``` -------------------------------------------------------------------------------- /packages/reactive-vue/tsconfig.json: -------------------------------------------------------------------------------- ```json { "extends": "../../tsconfig.json", "compilerOptions": { "skipLibCheck": true }, "include": ["./src/**/*.ts", "./src/**/*.tsx"], "exclude": ["./src/__tests__/*", "./esm/*", "./lib/*"] } ``` -------------------------------------------------------------------------------- /packages/vue/tsconfig.json: -------------------------------------------------------------------------------- ```json { "extends": "../../tsconfig.json", "compilerOptions": { "skipLibCheck": true }, "include": ["./src/**/*.ts", "./src/**/*.tsx"], "exclude": ["./src/__tests__/*", "./esm/*", "./lib/*"] } ``` -------------------------------------------------------------------------------- /packages/element/src/form-collapse/style.ts: -------------------------------------------------------------------------------- ```typescript import './style.scss' import 'element-ui/packages/theme-chalk/src/collapse.scss' import 'element-ui/packages/theme-chalk/src/collapse-item.scss' import 'element-ui/packages/theme-chalk/src/badge.scss' ``` -------------------------------------------------------------------------------- /packages/antd/tsconfig.json: -------------------------------------------------------------------------------- ```json { "extends": "../../tsconfig.json", "include": ["./src/**/*.ts", "./src/**/*.tsx"], "exclude": ["./src/__tests__/*", "./esm/*", "./lib/*"], "compilerOptions": { "lib": ["ESNext", "DOM"] } } ``` -------------------------------------------------------------------------------- /packages/benchmark/tsconfig.json: -------------------------------------------------------------------------------- ```json { "extends": "../../tsconfig.json", "include": ["./src/**/*.ts", "./src/**/*.tsx"], "exclude": ["./src/__tests__/*", "./esm/*", "./lib/*"], "compilerOptions": { "lib": ["ESNext", "DOM"] } } ``` -------------------------------------------------------------------------------- /packages/grid/tsconfig.json: -------------------------------------------------------------------------------- ```json { "extends": "../../tsconfig.json", "include": ["./src/**/*.ts", "./src/**/*.tsx"], "exclude": ["./src/__tests__/*", "./esm/*", "./lib/*"], "compilerOptions": { "lib": ["ESNext", "DOM"] } } ``` -------------------------------------------------------------------------------- /packages/react/tsconfig.json: -------------------------------------------------------------------------------- ```json { "extends": "../../tsconfig.json", "include": ["./src/**/*.ts", "./src/**/*.tsx"], "exclude": ["./src/__tests__/*", "./esm/*", "./lib/*"], "compilerOptions": { "lib": ["ESNext", "DOM"] } } ``` -------------------------------------------------------------------------------- /packages/reactive-react/tsconfig.json: -------------------------------------------------------------------------------- ```json { "extends": "../../tsconfig.json", "include": ["./src/**/*.ts", "./src/**/*.tsx"], "exclude": ["./src/__tests__/*", "./esm/*", "./lib/*"], "compilerOptions": { "lib": ["ESNext", "DOM"] } } ``` -------------------------------------------------------------------------------- /packages/shared/src/uid.ts: -------------------------------------------------------------------------------- ```typescript let IDX = 36, HEX = '' while (IDX--) HEX += IDX.toString(36) export function uid(len?: number) { let str = '', num = len || 11 while (num--) str += HEX[(Math.random() * 36) | 0] return str } ``` -------------------------------------------------------------------------------- /packages/shared/tsconfig.json: -------------------------------------------------------------------------------- ```json { "extends": "../../tsconfig.json", "include": ["./src/**/*.ts", "./src/**/*.tsx"], "exclude": ["./src/__tests__/*", "./esm/*", "./lib/*"], "compilerOptions": { "lib": ["ESNext", "DOM"] } } ``` -------------------------------------------------------------------------------- /packages/antd/rollup.config.js: -------------------------------------------------------------------------------- ```javascript import baseConfig, { removeImportStyleFromInputFilePlugin, } from '../../scripts/rollup.base.js' export default baseConfig( 'formily.antd', 'Formily.Antd', removeImportStyleFromInputFilePlugin() ) ``` -------------------------------------------------------------------------------- /packages/element/src/__builtins__/shared/index.ts: -------------------------------------------------------------------------------- ```typescript export * from './transform-component' export * from './resolve-component' export * from './create-context' export * from './utils' export * from './portal' export * from './loading' export * from './types' ``` -------------------------------------------------------------------------------- /packages/next/rollup.config.js: -------------------------------------------------------------------------------- ```javascript import baseConfig, { removeImportStyleFromInputFilePlugin, } from '../../scripts/rollup.base.js' export default baseConfig( 'formily.next', 'Formily.Next', removeImportStyleFromInputFilePlugin() ) ``` -------------------------------------------------------------------------------- /packages/vue/src/hooks/useInjectionCleaner.ts: -------------------------------------------------------------------------------- ```typescript import { InjectionKey, provide, Ref, ref } from 'vue-demi' export const useInjectionCleaner = ( injectionKeys: InjectionKey<Ref<unknown>>[] ) => { injectionKeys.forEach((key) => provide(key, ref())) } ``` -------------------------------------------------------------------------------- /packages/react/src/hooks/useFieldSchema.ts: -------------------------------------------------------------------------------- ```typescript import { useContext } from 'react' import { SchemaContext } from '../shared' import { Schema } from '@formily/json-schema' export const useFieldSchema = (): Schema => { return useContext(SchemaContext) } ``` -------------------------------------------------------------------------------- /packages/vue/src/__tests__/shared.spec.ts: -------------------------------------------------------------------------------- ```typescript import { createForm } from '../' import { isRaw } from '@vue/composition-api' test('createForm returns an un reactive form instance.', () => { const form = createForm() expect(isRaw(form)).toBeTruthy() }) ``` -------------------------------------------------------------------------------- /.github/workflows/pr-welcome.yml: -------------------------------------------------------------------------------- ```yaml name: PR Welcome on: pull_request_target: types: [opened] jobs: welcome: runs-on: ubuntu-latest steps: - uses: actions-cool/[email protected] with: pr-emoji: '+1, heart' ``` -------------------------------------------------------------------------------- /docs/site/Section.less: -------------------------------------------------------------------------------- ``` .site-section { &-title { font-size: 50px; text-align: center; padding-bottom: 200px; position: relative; color: #45124e; @media (max-width: 480px) { font-size: 30px; } } } ``` -------------------------------------------------------------------------------- /packages/element/rollup.config.js: -------------------------------------------------------------------------------- ```javascript import baseConfig, { removeImportStyleFromInputFilePlugin, } from '../../scripts/rollup.base.js' export default baseConfig( 'formily.element', 'Formily.Element', removeImportStyleFromInputFilePlugin() ) ``` -------------------------------------------------------------------------------- /packages/react/src/hooks/useForm.ts: -------------------------------------------------------------------------------- ```typescript import { useContext } from 'react' import { Form } from '@formily/core' import { FormContext } from '../shared' export const useForm = <T extends object = any>(): Form<T> => { return useContext(FormContext) } ``` -------------------------------------------------------------------------------- /packages/next/src/array-table/style.ts: -------------------------------------------------------------------------------- ```typescript import '@alifd/next/lib/button/style' import '@alifd/next/lib/badge/style' import '@alifd/next/lib/pagination/style' import '@alifd/next/lib/select/style' import '@alifd/next/lib/table/style' import './main.scss' ``` -------------------------------------------------------------------------------- /packages/next/src/space/main.scss: -------------------------------------------------------------------------------- ```scss @import '~@alifd/next/lib/core/index-noreset.scss'; @import '~@alifd/next/lib/form/scss/variable.scss'; $space-prefix-cls: '#{$css-prefix}space'; .#{$space-prefix-cls}-item:empty { display: none !important; } ``` -------------------------------------------------------------------------------- /packages/react/src/hooks/useField.ts: -------------------------------------------------------------------------------- ```typescript import { useContext } from 'react' import { GeneralField } from '@formily/core' import { FieldContext } from '../shared' export const useField = <T = GeneralField>(): T => { return useContext(FieldContext) as any } ``` -------------------------------------------------------------------------------- /packages/core/tsconfig.json: -------------------------------------------------------------------------------- ```json { "extends": "../../tsconfig.json", "include": ["./src/**/*.ts", "./src/**/*.tsx"], "exclude": ["./src/__tests__/*", "./esm/*", "./lib/*"], "compilerOptions": { "lib": ["ESNext", "DOM"], "types": [] } } ``` -------------------------------------------------------------------------------- /packages/element/src/preview-text/style.ts: -------------------------------------------------------------------------------- ```typescript import 'element-ui/packages/theme-chalk/src/tag.scss' // 依赖 import '../input/style' import '../select/style' import '../cascader/style' import '../time-picker/style' import '../date-picker/style' import '../space/style' ``` -------------------------------------------------------------------------------- /packages/element/src/array-cards/style.ts: -------------------------------------------------------------------------------- ```typescript import './style.scss' import 'element-ui/packages/theme-chalk/src/card.scss' import 'element-ui/packages/theme-chalk/src/empty.scss' import 'element-ui/packages/theme-chalk/src/row.scss' // 依赖 import '../array-base/style' ``` -------------------------------------------------------------------------------- /packages/next/src/transfer/index.tsx: -------------------------------------------------------------------------------- ```typescript import { connect, mapProps } from '@formily/react' import { Transfer as NextTransfer } from '@alifd/next' export const Transfer = connect( NextTransfer, mapProps({ dataSource: true, }) ) export default Transfer ``` -------------------------------------------------------------------------------- /packages/core/src/__tests__/shared.ts: -------------------------------------------------------------------------------- ```typescript export const attach = <T extends { onMount: () => void }>(target: T): T => { target.onMount() return target } export const sleep = (duration = 100) => new Promise((resolve) => { setTimeout(resolve, duration) }) ``` -------------------------------------------------------------------------------- /packages/element/src/checkbox/style.ts: -------------------------------------------------------------------------------- ```typescript import 'element-ui/packages/theme-chalk/src/checkbox.scss' import 'element-ui/packages/theme-chalk/src/checkbox-group.scss' import 'element-ui/packages/theme-chalk/src/checkbox-button.scss' // 依赖 import '../preview-text/style' ``` -------------------------------------------------------------------------------- /packages/vue/src/hooks/useForm.ts: -------------------------------------------------------------------------------- ```typescript import { inject, Ref, ref } from 'vue-demi' import { Form } from '@formily/core' import { FormSymbol } from '../shared/context' export const useForm = (): Ref<Form> => { const form = inject(FormSymbol, ref()) return form } ``` -------------------------------------------------------------------------------- /packages/antd/src/array-collapse/style.less: -------------------------------------------------------------------------------- ``` @root-entry-name: 'default'; @import (reference) '~antd/es/style/themes/index.less'; @array-collapse-prefix-cls: ~'@{ant-prefix}-formily-array-collapse'; .@{array-collapse-prefix-cls}-item { margin-bottom: 10px !important; } ``` -------------------------------------------------------------------------------- /docs/guide/scenes/dialog-drawer.md: -------------------------------------------------------------------------------- ```markdown # Dialog and Drawers Mainly use the [FormDialog](https://antd.formilyjs.org/components/form-dialog) function and [FormDrawer]() function in [@formily/antd](https://antd.formilyjs.org) or [@formily/next](https://fusion.formilyjs.org) ``` -------------------------------------------------------------------------------- /packages/core/src/models/index.ts: -------------------------------------------------------------------------------- ```typescript export * from './Heart' export * from './LifeCycle' export * from './Graph' export * from './Query' export * from './Form' export * from './Field' export * from './ArrayField' export * from './ObjectField' export * from './VoidField' ``` -------------------------------------------------------------------------------- /packages/reactive-react/src/shared/immediate.ts: -------------------------------------------------------------------------------- ```typescript export const immediate = (callback?: () => void) => { let disposed = false Promise.resolve(0).then(() => { if (disposed) { disposed = false return } callback() }) return () => { disposed = true } } ``` -------------------------------------------------------------------------------- /packages/vue/src/hooks/useField.ts: -------------------------------------------------------------------------------- ```typescript import { inject, Ref, ref } from 'vue-demi' import { GeneralField } from '@formily/core' import { FieldSymbol } from '../shared/context' export const useField = <T = GeneralField>(): Ref<T> => { return inject(FieldSymbol, ref()) as any } ``` -------------------------------------------------------------------------------- /packages/vue/tsconfig.types.json: -------------------------------------------------------------------------------- ```json { "extends": "./tsconfig.json", "compilerOptions": { "outDir": "./type-artefacts", "paths": { "@formily/*": ["packages/*", "devtools/*"] }, "declaration": true, "sourceMap": false, "inlineSources": false } } ``` -------------------------------------------------------------------------------- /packages/antd/src/array-table/style.ts: -------------------------------------------------------------------------------- ```typescript import 'antd/lib/table/style/index' import 'antd/lib/button/style/index' import 'antd/lib/select/style/index' import 'antd/lib/space/style/index' import 'antd/lib/badge/style/index' import 'antd/lib/pagination/style/index' import './style.less' ``` -------------------------------------------------------------------------------- /packages/vue/src/shared/createForm.ts: -------------------------------------------------------------------------------- ```typescript import { createForm } from '@formily/core' import { markRaw } from 'vue-demi' const createRawForm = (...args: Parameters<typeof createForm>) => { const form = createForm(...args) return markRaw(form) } export { createRawForm as createForm } ``` -------------------------------------------------------------------------------- /packages/element/src/array-tabs/style.ts: -------------------------------------------------------------------------------- ```typescript import './style.scss' import 'element-ui/packages/theme-chalk/src/tabs.scss' import 'element-ui/packages/theme-chalk/src/tab-pane.scss' import 'element-ui/packages/theme-chalk/src/badge.scss' import 'element-ui/packages/theme-chalk/src/button.scss' ``` -------------------------------------------------------------------------------- /packages/antd/src/select-table/style.less: -------------------------------------------------------------------------------- ``` @root-entry-name: 'default'; @import (reference) '~antd/es/style/themes/index.less'; @select-table-prefix-cls: ~'@{ant-prefix}-formily-select-table'; .@{select-table-prefix-cls} { .@{select-table-prefix-cls}-search { margin-bottom: 8px; } } ``` -------------------------------------------------------------------------------- /packages/element/transformer.ts: -------------------------------------------------------------------------------- ```typescript import createTransformer from 'ts-import-plugin' const transformer = createTransformer({ libraryName: 'element-ui', libraryDirectory: 'lib', camel2DashComponentName: true, style: false, }) export default function () { return transformer } ``` -------------------------------------------------------------------------------- /docs/site/styles.less: -------------------------------------------------------------------------------- ``` .site-section { .codesandbox { width: 100%; height: 500px; border: 0; border-radius: 4px; overflow: hidden; box-shadow: 0 10px 30px #555; } img { width: 100%; border-radius: 4px; } } #root { overflow: hidden; } ``` -------------------------------------------------------------------------------- /devtools/chrome-extension/src/extension/content.ts: -------------------------------------------------------------------------------- ```typescript window.addEventListener( 'message', (event) => { const { source, ...payload } = event.data if (source === '@formily-devtools-inject-script') { chrome.runtime.sendMessage({ source, ...payload, }) } }, false ) ``` -------------------------------------------------------------------------------- /packages/next/src/__builtins__/index.ts: -------------------------------------------------------------------------------- ```typescript export * from './moment' export * from './hooks' export * from './toArray' export * from './mapStatus' export * from './mapSize' export * from './empty' export * from './loading' export * from './portal' export * from './pickDataProps' export * from './icons' ``` -------------------------------------------------------------------------------- /packages/reactive/src/index.ts: -------------------------------------------------------------------------------- ```typescript export * from './batch' export * from './action' export * from './untracked' export * from './observable' export * from './model' export * from './autorun' export * from './tracker' export * from './observe' export * from './externals' export * from './types' ``` -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- ```json { "version": "2.3.7", "npmClient": "yarn", "useWorkspaces": true, "npmClientArgs": [ "--ignore-engines" ], "command": { "version": { "forcePublish": true, "exact": true, "message": "chore(release): 😊 publish %s" } } } ``` -------------------------------------------------------------------------------- /packages/antd/src/number-picker/index.tsx: -------------------------------------------------------------------------------- ```typescript import { connect, mapReadPretty } from '@formily/react' import { InputNumber } from 'antd' import { PreviewText } from '../preview-text' export const NumberPicker = connect( InputNumber, mapReadPretty(PreviewText.NumberPicker) ) export default NumberPicker ``` -------------------------------------------------------------------------------- /packages/shared/src/case.ts: -------------------------------------------------------------------------------- ```typescript import { camelCase } from 'camel-case' import { pascalCase } from 'pascal-case' import { lowerCase } from 'lower-case' import { upperCase } from 'upper-case' import { paramCase } from 'param-case' export { lowerCase, upperCase, camelCase, pascalCase, paramCase } ``` -------------------------------------------------------------------------------- /packages/vue/scripts/postinstall.js: -------------------------------------------------------------------------------- ```javascript const { switchVersion, loadModule } = require('./utils.js') const Vue = loadModule('vue') try { if (Vue.version.startsWith('2.')) { switchVersion(2) } else if (Vue.version.startsWith('3.')) { switchVersion(3) } } catch (err) { // nothing to do } ``` -------------------------------------------------------------------------------- /packages/antd/src/preview-text/style.less: -------------------------------------------------------------------------------- ``` @root-entry-name: 'default'; @import (reference) '~antd/es/style/themes/index.less'; @form-text-prefix-cls: ~'@{ant-prefix}-form-text'; .@{form-text-prefix-cls} { font-size: 14px; font-weight: 500; .@{ant-prefix}-tag:last-child { margin-right: 0; } } ``` -------------------------------------------------------------------------------- /packages/next/src/select-table/main.scss: -------------------------------------------------------------------------------- ```scss @import '~@alifd/next/lib/core/index-noreset.scss'; @import '~@alifd/next/lib/form/scss/variable.scss'; $select-table-prefix-cls: '#{$css-prefix}formily-select-table'; .#{$select-table-prefix-cls} { .#{$select-table-prefix-cls}-search { margin-bottom: 8px; } } ``` -------------------------------------------------------------------------------- /docs/guide/scenes/more.md: -------------------------------------------------------------------------------- ```markdown # More Scenes Because Formily is a very complete solution at the form level, and it is also very flexible. It supports a lot of scenarios, but we can't list them all. Therefore, I still hope that the community can help Formily improve more scenarios! We would be very grateful!😀 ``` -------------------------------------------------------------------------------- /docs/guide/scenes/tab-form.md: -------------------------------------------------------------------------------- ```markdown # Tab/Accordion Form Mainly use the [FormTab](https://antd.formilyjs.org/components/form-tab) component and [FormCollapse](https://antd.formilyjs.org/components/form-collapse) component in [@formily/antd](https://antd.formilyjs.org) or [@formily/next](https://fusion.formilyjs.org) ``` -------------------------------------------------------------------------------- /packages/next/src/__builtins__/hooks/usePrefixCls.ts: -------------------------------------------------------------------------------- ```typescript import { ConfigProvider } from '@alifd/next' export const usePrefixCls = ( tag?: string, props?: { prefix?: string } ) => { const getContext = ConfigProvider['getContext'] const prefix = props?.prefix ?? getContext()?.prefix ?? 'next-' return `${prefix}${tag ?? ''}` } ``` -------------------------------------------------------------------------------- /packages/element/src/switch/index.ts: -------------------------------------------------------------------------------- ```typescript import { connect, mapProps } from '@formily/vue' import type { Switch as ElSwitchProps } from 'element-ui' import { Switch as ElSwitch } from 'element-ui' export type SwitchProps = ElSwitchProps export const Switch = connect(ElSwitch, mapProps({ readOnly: 'readonly' })) export default Switch ``` -------------------------------------------------------------------------------- /docs/guide/scenes/index.less: -------------------------------------------------------------------------------- ``` .array-items-item { border: 1px solid rgb(238, 238, 238); margin-bottom: 10px; padding: 3px 6px; display: flex; justify-content: space-around; transition: all 0.25s; .ant-formily-item { margin-bottom: 0 !important; } &:hover { border: 1px solid rgb(170, 170, 170); } } ``` -------------------------------------------------------------------------------- /packages/element/docs/.vuepress/enhanceApp.js: -------------------------------------------------------------------------------- ```javascript import pageComponents from '@internal/page-components' import Element from 'element-ui' import '@formily/element/style.ts' export default ({ Vue }) => { for (const [name, component] of Object.entries(pageComponents)) { Vue.component(name, component) } Vue.use(Element, { size: 'small' }) } ``` -------------------------------------------------------------------------------- /packages/next/src/switch/index.tsx: -------------------------------------------------------------------------------- ```typescript import { Switch as NextSwitch } from '@alifd/next' import { connect, mapProps } from '@formily/react' import { mapSize, mapStatus } from '../__builtins__' export const Switch = connect( NextSwitch, mapProps( { value: 'checked', }, mapSize, mapStatus ) ) export default Switch ``` -------------------------------------------------------------------------------- /packages/next/src/form-button-group/main.scss: -------------------------------------------------------------------------------- ```scss @import '~@alifd/next/lib/core/index-noreset.scss'; $btn-group-prefix-cls: '#{$css-prefix}formily-button-group'; .#{$btn-group-prefix-cls}-sticky { padding: 10px 0; border-top: 1px solid #eee; z-index: 999; &-inner { display: flex; .#{$css-prefix}formily-item { flex: 2; } } } ``` -------------------------------------------------------------------------------- /packages/element/src/transfer/index.ts: -------------------------------------------------------------------------------- ```typescript import { connect, mapProps } from '@formily/vue' import type { Transfer as ElTransferProps } from 'element-ui' import { Transfer as ElTransfer } from 'element-ui' export type TransferProps = ElTransferProps export const Transfer = connect(ElTransfer, mapProps({ dataSource: 'data' })) export default Transfer ``` -------------------------------------------------------------------------------- /packages/reactive-react/src/hooks/useDidUpdate.ts: -------------------------------------------------------------------------------- ```typescript import { useRef } from 'react' import { useLayoutEffect } from './useLayoutEffect' import { immediate } from '../shared' export const useDidUpdate = (callback?: () => void) => { const request = useRef(null) request.current = immediate(callback) useLayoutEffect(() => { request.current() callback() }) } ``` -------------------------------------------------------------------------------- /packages/reactive/src/__tests__/hasCollected.spec.ts: -------------------------------------------------------------------------------- ```typescript import { observable, hasCollected, autorun } from '../' test('hasCollected', () => { const obs = observable({ value: '' }) autorun(() => { expect( hasCollected(() => { obs.value }) ).toBe(true) expect(hasCollected(() => {})).toBe(false) expect(hasCollected()).toBe(false) }) }) ``` -------------------------------------------------------------------------------- /packages/shared/src/instanceof.ts: -------------------------------------------------------------------------------- ```typescript import { globalThisPolyfill } from './global' import { isStr, isFn } from './checkers' export const instOf = (value: any, cls: any) => { if (isFn(cls)) return value instanceof cls if (isStr(cls)) { return globalThisPolyfill[cls] ? value instanceof globalThisPolyfill[cls] : false } return false } ``` -------------------------------------------------------------------------------- /packages/path/src/__tests__/basic.spec.ts: -------------------------------------------------------------------------------- ```typescript import { Path } from '../' const { isPathPattern, match } = Path test('isPathPattern', () => { expect(isPathPattern('obj')).toBeTruthy() expect(isPathPattern(['obj', 'aa'])).toBeTruthy() expect(isPathPattern(/^obj/)).toBeTruthy() const matcher = match('obj.aa') expect(isPathPattern(matcher)).toBeTruthy() }) ``` -------------------------------------------------------------------------------- /.github/workflows/package-size.yml: -------------------------------------------------------------------------------- ```yaml name: Compressed Size on: [pull_request] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: node-version: 16 - uses: preactjs/compressed-size-action@v2 with: repo-token: '${{ secrets.GITHUB_TOKEN }}' ``` -------------------------------------------------------------------------------- /global.config.ts: -------------------------------------------------------------------------------- ```typescript import prettyFormat from 'pretty-format' global['prettyFormat'] = prettyFormat global['sleep'] = (time: number) => { return new Promise((resolve) => setTimeout(resolve, time)) } global['requestAnimationFrame'] = (fn: () => void) => setTimeout(fn, 0) global['document'].documentElement.style['grid-column-gap'] = true ``` -------------------------------------------------------------------------------- /packages/antd/src/select-table/useFlatOptions.tsx: -------------------------------------------------------------------------------- ```typescript const useFlatOptions = (tree: any[]) => { const flatData = (data) => { let list = [] data?.forEach((item) => { list = [...list, item] if (item?.children?.length) { list = [...list, ...flatData(item.children)] } }) return list } return flatData(tree) } export { useFlatOptions } ``` -------------------------------------------------------------------------------- /packages/next/src/select-table/useFlatOptions.tsx: -------------------------------------------------------------------------------- ```typescript const useFlatOptions = (tree: any[]) => { const flatData = (data) => { let list = [] data?.forEach((item) => { list = [...list, item] if (item?.children?.length) { list = [...list, ...flatData(item.children)] } }) return list } return flatData(tree) } export { useFlatOptions } ``` -------------------------------------------------------------------------------- /tsconfig.jest.json: -------------------------------------------------------------------------------- ```json { "extends": "./tsconfig.json", "compilerOptions": { "jsx": "react", "esModuleInterop": true, "moduleResolution": "node", "allowJs": true, "module": "commonjs", "target": "es5", "paths": { "@formily/*": ["./packages/*/src"] } }, "exclude": ["./packages/*/esm", "./packages/*/lib"] } ``` -------------------------------------------------------------------------------- /packages/next/src/__builtins__/loading.ts: -------------------------------------------------------------------------------- ```typescript import { Message } from '@alifd/next' export const loading = async ( title: React.ReactNode = 'Loading...', processor: () => Promise<any> ) => { let loading = setTimeout(() => { Message.loading(title as any) }, 100) try { return await processor() } finally { Message.hide() clearTimeout(loading) } } ``` -------------------------------------------------------------------------------- /packages/react/src/components/index.ts: -------------------------------------------------------------------------------- ```typescript export * from './FormProvider' export * from './FormConsumer' export * from './ArrayField' export * from './ObjectField' export * from './VoidField' export * from './RecursionField' export * from './ExpressionScope' export * from './RecordsScope' export * from './RecordScope' export * from './SchemaField' export * from './Field' ``` -------------------------------------------------------------------------------- /packages/antd/src/__builtins__/loading.ts: -------------------------------------------------------------------------------- ```typescript import { message } from 'antd' export const loading = async ( title: React.ReactNode = 'Loading...', processor: () => Promise<any> ) => { let hide = null let loading = setTimeout(() => { hide = message.loading(title) }, 100) try { return await processor() } finally { hide?.() clearTimeout(loading) } } ``` -------------------------------------------------------------------------------- /packages/next/src/__builtins__/mapSize.ts: -------------------------------------------------------------------------------- ```typescript import { useFormLayout, useFormShallowLayout } from '../form-layout' export const mapSize = (props: any) => { const layout = { ...useFormShallowLayout(), ...useFormLayout() } const takeSize = () => { return layout.size === 'default' ? 'medium' : layout.size } return { ...props, size: props.size || takeSize(), } } ``` -------------------------------------------------------------------------------- /packages/react/src/hooks/useAttach.ts: -------------------------------------------------------------------------------- ```typescript import { unstable_useCompatEffect } from '@formily/reactive-react' interface IRecycleTarget { onMount: () => void onUnmount: () => void } export const useAttach = <T extends IRecycleTarget>(target: T): T => { unstable_useCompatEffect(() => { target.onMount() return () => target.onUnmount() }, [target]) return target } ``` -------------------------------------------------------------------------------- /packages/element/src/array-tabs/style.scss: -------------------------------------------------------------------------------- ```scss @import '../__builtins__/styles/common.scss'; $array-table-prefix-cls: '#{$formily-prefix}-array-tabs'; .#{$array-table-prefix-cls} { .#{$formily-prefix}-array-tabs-addition { position: absolute; right: -56px; top: -1px; } .#{$array-table-prefix-cls}-errors-badge { line-height: 1; vertical-align: initial; } } ``` -------------------------------------------------------------------------------- /packages/antd/src/form-button-group/style.less: -------------------------------------------------------------------------------- ``` @root-entry-name: 'default'; @import (reference) '~antd/es/style/themes/index.less'; @btn-group-prefix-cls: ~'@{ant-prefix}-formily-button-group'; .@{btn-group-prefix-cls}-sticky { padding: 10px 0; border-top: 1px solid @border-color-split; z-index: 999; &-inner { display: flex; .@{ant-prefix}-formily-item { flex: 2; } } } ``` -------------------------------------------------------------------------------- /packages/element/docs/guide/switch.md: -------------------------------------------------------------------------------- ```markdown # Switch > 开关组件 ## Markup Schema 案例 <dumi-previewer demoPath="guide/switch/markup-schema" /> ## JSON Schema 案例 <dumi-previewer demoPath="guide/switch/json-schema" /> ## Template 案例 <dumi-previewer demoPath="guide/switch/template" /> ## API 参考 [https://element.eleme.io/#/zh-CN/component/switch](https://element.eleme.io/#/zh-CN/component/switch) ``` -------------------------------------------------------------------------------- /packages/reactive/src/__tests__/untracked.spec.ts: -------------------------------------------------------------------------------- ```typescript import { untracked, observable, autorun } from '../' test('basic untracked', () => { const obs = observable<any>({}) const fn = jest.fn() autorun(() => { untracked(() => { fn(obs.value) }) }) expect(fn).toBeCalledTimes(1) obs.value = 123 expect(fn).toBeCalledTimes(1) }) test('no params untracked', () => { untracked() }) ``` -------------------------------------------------------------------------------- /packages/vue/src/utils/resolveSchemaProps.ts: -------------------------------------------------------------------------------- ```typescript import { paramCase } from '@formily/shared' export const resolveSchemaProps = (props: Record<string, any>) => { const newProps = {} Object.keys(props).forEach((key) => { if (key.indexOf('x') === 0 && key.indexOf('x-') === -1) { newProps[paramCase(key)] = props[key] } else { newProps[key] = props[key] } }) return newProps } ``` -------------------------------------------------------------------------------- /packages/antd/src/array-cards/style.less: -------------------------------------------------------------------------------- ``` @root-entry-name: 'default'; @import (reference) '~antd/es/style/themes/index.less'; @array-base-prefix-cls: ~'@{ant-prefix}-formily-array-base'; @array-cards-prefix-cls: ~'@{ant-prefix}-formily-array-cards'; .@{array-cards-prefix-cls}-item { margin-bottom: 10px !important; } .ant-card-extra { .@{array-base-prefix-cls}-copy { margin-left: 6px; } } ``` -------------------------------------------------------------------------------- /packages/element/docs/guide/transfer.md: -------------------------------------------------------------------------------- ```markdown # Transfer > 穿梭框 ## Markup Schema 案例 <dumi-previewer demoPath="guide/transfer/markup-schema" /> ## JSON Schema 案例 <dumi-previewer demoPath="guide/transfer/json-schema" /> ## Template 案例 <dumi-previewer demoPath="guide/transfer/template" /> ## API 参考 [https://element.eleme.io/#/zh-CN/component/transfer](https://element.eleme.io/#/zh-CN/component/transfer) ``` -------------------------------------------------------------------------------- /packages/element/src/__builtins__/styles/common.scss: -------------------------------------------------------------------------------- ```scss $formily-prefix: 'formily-element'; $namespace: 'el'; @import '~element-ui/packages/theme-chalk/src/common/var.scss'; @mixin active { border-color: $--color-primary; outline: 0; border-right-width: $--border-width-base !important; } @mixin hover { border-color: $--border-color-hover; outline: 0; border-right-width: $--border-width-base !important; } ``` -------------------------------------------------------------------------------- /packages/element/docs/guide/cascader.md: -------------------------------------------------------------------------------- ```markdown # Cascader > 级联选择器 ## Markup Schema 案例 <dumi-previewer demoPath="guide/cascader/markup-schema" /> ## JSON Schema 案例 <dumi-previewer demoPath="guide/cascader/json-schema" /> ## Template 案例 <dumi-previewer demoPath="guide/cascader/template" /> ## API 参考 [https://element.eleme.io/#/zh-CN/component/cascader](https://element.eleme.io/#/zh-CN/component/cascader) ``` -------------------------------------------------------------------------------- /packages/antd/src/space/index.tsx: -------------------------------------------------------------------------------- ```typescript import React from 'react' import { Space as AntdSpace, SpaceProps } from 'antd' import { useFormLayout } from '../form-layout' export const Space: React.FC<React.PropsWithChildren<SpaceProps>> = (props) => { const layout = useFormLayout() return React.createElement(AntdSpace, { size: props.size ?? layout?.spaceGap, ...props, }) } export default Space ``` -------------------------------------------------------------------------------- /packages/core/src/models/types.ts: -------------------------------------------------------------------------------- ```typescript export type { Form } from './Form' export type { Field } from './Field' export type { Query } from './Query' export type { Heart } from './Heart' export type { Graph } from './Graph' export type { LifeCycle } from './LifeCycle' export type { ArrayField } from './ArrayField' export type { ObjectField } from './ObjectField' export type { VoidField } from './VoidField' ``` -------------------------------------------------------------------------------- /packages/element/src/array-table/style.ts: -------------------------------------------------------------------------------- ```typescript import './style.scss' import 'element-ui/packages/theme-chalk/src/table.scss' import 'element-ui/packages/theme-chalk/src/table-column.scss' import 'element-ui/packages/theme-chalk/src/button.scss' import 'element-ui/packages/theme-chalk/src/select.scss' import 'element-ui/packages/theme-chalk/src/badge.scss' // 依赖 import '../array-base/style' import '../space/style' ``` -------------------------------------------------------------------------------- /.github/workflows/check-pr-title.yml: -------------------------------------------------------------------------------- ```yaml name: Check PR title on: pull_request_target: types: - opened - reopened - edited - synchronize jobs: lint: runs-on: ubuntu-latest steps: - uses: aslafy-z/[email protected] with: preset: conventional-changelog-angular@^5.0.6 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ``` -------------------------------------------------------------------------------- /packages/element/src/form-drawer/style.scss: -------------------------------------------------------------------------------- ```scss @import '../__builtins__/styles/common.scss'; .#{$formily-prefix}-form-drawer { .el-drawer__body { display: flex; flex-direction: column; } &-body { flex: 1; overflow: auto; padding: $--dialog-padding-primary; } &-footer { padding: $--dialog-padding-primary; display: flex; justify-content: flex-end; align-items: center; } } ``` -------------------------------------------------------------------------------- /packages/next/src/number-picker/index.tsx: -------------------------------------------------------------------------------- ```typescript import { connect, mapProps, mapReadPretty } from '@formily/react' import { NumberPicker as InputNumber } from '@alifd/next' import { PreviewText } from '../preview-text' import { mapSize, mapStatus } from '../__builtins__' export const NumberPicker = connect( InputNumber, mapProps(mapSize, mapStatus), mapReadPretty(PreviewText.NumberPicker) ) export default NumberPicker ``` -------------------------------------------------------------------------------- /packages/element/tsconfig.json: -------------------------------------------------------------------------------- ```json { "extends": "../../tsconfig.json", "compilerOptions": { "outDir": "./lib", "skipLibCheck": true, "paths": { "@formily/*": ["../../packages/*", "../../devtools/*"] }, "plugins": [{ "transform": "./transformer.ts", "after": true }], "lib": ["ESNext", "DOM"] }, "include": ["./src/**/*.ts", "./src/**/*.tsx"], "exclude": ["./esm/*", "./lib/*"] } ``` -------------------------------------------------------------------------------- /packages/element/docs/guide/date-picker.md: -------------------------------------------------------------------------------- ```markdown # DatePicker > 日期选择器 ## Markup Schema 案例 <dumi-previewer demoPath="guide/date-picker/markup-schema" /> ## JSON Schema 案例 <dumi-previewer demoPath="guide/date-picker/json-schema" /> ## Template 案例 <dumi-previewer demoPath="guide/date-picker/template" /> ## API 参考 [https://element.eleme.io/#/zh-CN/component/date-picker](https://element.eleme.io/#/zh-CN/component/date-picker) ``` -------------------------------------------------------------------------------- /packages/element/docs/guide/time-picker.md: -------------------------------------------------------------------------------- ```markdown # TimePicker > 时间选择器 ## Markup Schema 案例 <dumi-previewer demoPath="guide/time-picker/markup-schema" /> ## JSON Schema 案例 <dumi-previewer demoPath="guide/time-picker/json-schema" /> ## Template 案例 <dumi-previewer demoPath="guide/time-picker/template" /> ## API 参考 [https://element.eleme.io/#/zh-CN/component/time-picker](https://element.eleme.io/#/zh-CN/component/time-picker) ``` -------------------------------------------------------------------------------- /.vscode/cspell.json: -------------------------------------------------------------------------------- ```json { "version": "0.1", "language": "en", "ignoreWords": [ "autorun", "mutators", "Formily", "formily", "untrack", "untracker", "untracked", "Untracking", "Unmount", "octokit", "repos", "alibaba", "Lifecycles", "antd", "Antd", "alifd", "Mixins", "builtins", "cascader", "Cascader", "middlewares" ] } ``` -------------------------------------------------------------------------------- /scripts/build-style/index.ts: -------------------------------------------------------------------------------- ```typescript import { runCopy, CopyBaseOptions } from './copy' import { buildAllStyles } from './buildAllStyles' // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types export function build({ allStylesOutputFile, ...opts }: CopyBaseOptions & { allStylesOutputFile: string }) { return Promise.all([buildAllStyles(allStylesOutputFile), runCopy(opts)]) } export { runCopy } ``` -------------------------------------------------------------------------------- /packages/element/docs/guide/input-number.md: -------------------------------------------------------------------------------- ```markdown # InputNumber > 数字输入框 ## Markup Schema 案例 <dumi-previewer demoPath="guide/input-number/markup-schema" /> ## JSON Schema 案例 <dumi-previewer demoPath="guide/input-number/json-schema" /> ## Template 案例 <dumi-previewer demoPath="guide/input-number/template" /> ## API 参考 [https://element.eleme.io/#/zh-CN/component/input-number](https://element.eleme.io/#/zh-CN/component/input-number) ``` -------------------------------------------------------------------------------- /packages/next/src/preview-text/main.scss: -------------------------------------------------------------------------------- ```scss @import '~@alifd/next/lib/core/index-noreset.scss'; $form-preview-prefix-cls: '#{$css-prefix}form-preview'; .#{$form-preview-prefix-cls} { font-weight: 400; word-break: break-all; .#{$css-prefix}tag { margin-right: 4px; } .#{$css-prefix}tag:last-child { margin-right: 0; } } p.#{$form-preview-prefix-cls} { margin: 0; font-size: inherit; line-height: inherit; } ``` -------------------------------------------------------------------------------- /packages/react/src/components/RecordsScope.tsx: -------------------------------------------------------------------------------- ```typescript import React from 'react' import { ExpressionScope } from './ExpressionScope' import { ReactFC, IRecordsScopeProps } from '../types' export const RecordsScope: ReactFC<IRecordsScopeProps> = (props) => { return ( <ExpressionScope value={{ get $records() { return props.getRecords?.() ?? [] }, }} > {props.children} </ExpressionScope> ) } ``` -------------------------------------------------------------------------------- /packages/element/src/array-collapse/style.ts: -------------------------------------------------------------------------------- ```typescript import './style.scss' import 'element-ui/packages/theme-chalk/src/empty.scss' import 'element-ui/packages/theme-chalk/src/row.scss' import 'element-ui/packages/theme-chalk/src/collapse.scss' import 'element-ui/packages/theme-chalk/src/collapse-item.scss' import 'element-ui/packages/theme-chalk/src/card.scss' import 'element-ui/packages/theme-chalk/src/badge.scss' // 依赖 import '../array-base/style' ``` -------------------------------------------------------------------------------- /packages/element/src/space/style.scss: -------------------------------------------------------------------------------- ```scss @import '../__builtins__/styles/common.scss'; .#{$formily-prefix}-space { display: inline-flex; &-vertical { flex-direction: column; } &-align { &-center { align-items: center; } &-start { align-items: flex-start; } &-end { align-items: flex-end; } &-baseline { align-items: baseline; } } &-item { display: contents; } } ``` -------------------------------------------------------------------------------- /packages/element/create-style.ts: -------------------------------------------------------------------------------- ```typescript import glob from 'glob' import path from 'path' import fs from 'fs-extra' glob( './*/style.scss', { cwd: path.resolve(__dirname, './src') }, (err, files) => { if (err) return console.error(err) fs.writeFile( path.resolve(__dirname, './src/style.ts'), `// auto generated code ${files .map((path) => { return `import '${path}'\n` }) .join('')}`, 'utf8' ) } ) ``` -------------------------------------------------------------------------------- /packages/next/src/cascader/index.tsx: -------------------------------------------------------------------------------- ```typescript import { connect, mapReadPretty, mapProps } from '@formily/react' import { CascaderSelect } from '@alifd/next' import { PreviewText } from '../preview-text' import { mapSize, mapStatus } from '../__builtins__' export const Cascader = connect( CascaderSelect, mapProps( { dataSource: true, }, mapSize, mapStatus ), mapReadPretty(PreviewText.Cascader) ) export default Cascader ``` -------------------------------------------------------------------------------- /packages/shared/src/index.ts: -------------------------------------------------------------------------------- ```typescript export * from './array' export * from './compare' export * from './checkers' export * from './clone' export * from './isEmpty' export * from './case' export * from './string' export * from './global' export * from './path' export * from './deprecate' export * from './subscribable' export * from './middleware' export * from './merge' export * from './instanceof' export * from './defaults' export * from './uid' ``` -------------------------------------------------------------------------------- /packages/shared/src/global.ts: -------------------------------------------------------------------------------- ```typescript /* istanbul ignore next */ function globalSelf() { try { if (typeof self !== 'undefined') { return self } } catch (e) {} try { if (typeof window !== 'undefined') { return window } } catch (e) {} try { if (typeof global !== 'undefined') { return global } } catch (e) {} return Function('return this')() } export const globalThisPolyfill: Window = globalSelf() ``` -------------------------------------------------------------------------------- /packages/reactive-react/src/shared/global.ts: -------------------------------------------------------------------------------- ```typescript /* istanbul ignore next */ function globalSelf() { try { if (typeof self !== 'undefined') { return self } } catch (e) {} try { if (typeof window !== 'undefined') { return window } } catch (e) {} try { if (typeof global !== 'undefined') { return global } } catch (e) {} return Function('return this')() } export const globalThisPolyfill: Window = globalSelf() ``` -------------------------------------------------------------------------------- /packages/element/src/cascader/index.ts: -------------------------------------------------------------------------------- ```typescript import { connect, mapProps, mapReadPretty } from '@formily/vue' import { Cascader as ELCascader } from 'element-ui' import type { Cascader as ElCascaderProps } from 'element-ui' import { PreviewText } from '../preview-text' export type CascaderProps = ElCascaderProps export const Cascader = connect( ELCascader, mapProps({ dataSource: 'options' }), mapReadPretty(PreviewText.Cascader) ) export default Cascader ``` -------------------------------------------------------------------------------- /packages/element/src/form-item/var.scss: -------------------------------------------------------------------------------- ```scss $form-item-prefix: '#{$formily-prefix}-form-item'; $--form-font-size: $--font-size-base !default; $--form-label-font-size: $--form-font-size !default; $--form-item-large-line-height: 40px; $--form-item-medium-line-height: 32px; $--form-item-small-line-height: 24px; $--form-item-label-top-line-height: 40px; $--form-error-line-height: 22px !default; $--form-item-margin-bottom: $--form-error-line-height !default; ``` -------------------------------------------------------------------------------- /packages/antd/src/__builtins__/hooks/usePrefixCls.ts: -------------------------------------------------------------------------------- ```typescript import { useContext } from 'react' import { ConfigProvider } from 'antd' export const usePrefixCls = ( tag?: string, props?: { prefixCls?: string } ) => { if ('ConfigContext' in ConfigProvider) { const { getPrefixCls } = useContext(ConfigProvider.ConfigContext) return getPrefixCls(tag, props?.prefixCls) } else { const prefix = props?.prefixCls ?? 'ant-' return `${prefix}${tag ?? ''}` } } ``` -------------------------------------------------------------------------------- /packages/antd/src/switch/index.tsx: -------------------------------------------------------------------------------- ```typescript import { Switch as AntdSwitch } from 'antd' import { connect, mapProps } from '@formily/react' export const Switch = connect( AntdSwitch, mapProps( { value: 'checked', }, (props) => { const onChange = props.onChange delete props['value'] return { ...props, onChange(checked) { onChange?.(checked, null) }, } } ) ) export default Switch ``` -------------------------------------------------------------------------------- /packages/next/src/tree-select/index.tsx: -------------------------------------------------------------------------------- ```typescript import { connect, mapReadPretty, mapProps } from '@formily/react' import { TreeSelect as NextTreeSelect } from '@alifd/next' import { PreviewText } from '../preview-text' import { mapSize, mapStatus } from '../__builtins__' export const TreeSelect = connect( NextTreeSelect, mapProps( { dataSource: true, }, mapSize, mapStatus ), mapReadPretty(PreviewText.TreeSelect) ) export default TreeSelect ``` -------------------------------------------------------------------------------- /packages/element/src/__builtins__/shared/loading.ts: -------------------------------------------------------------------------------- ```typescript import { Loading } from 'element-ui' export const loading = async ( loadingText = 'Loading...', processor: () => Promise<any> ) => { let loadingInstance = null let loading = setTimeout(() => { loadingInstance = Loading.service({ text: loadingText, background: 'transparent', }) }, 100) try { return await processor() } finally { loadingInstance?.close() clearTimeout(loading) } } ``` -------------------------------------------------------------------------------- /packages/vue/scripts/utils.js: -------------------------------------------------------------------------------- ```javascript const fs = require('fs-extra') const path = require('path') const dir = path.resolve(__dirname, '..', 'type-artefacts') function switchVersion(version) { fs.emptyDirSync(`${dir}/cur`) fs.copySync(`${dir}/v${version}`, `${dir}/cur`) } function loadModule(name) { try { return require(name) } catch (e) { return undefined } } module.exports.loadModule = loadModule module.exports.switchVersion = switchVersion ``` -------------------------------------------------------------------------------- /packages/element/src/password/index.ts: -------------------------------------------------------------------------------- ```typescript import { Input } from '../input' import { connect, mapProps, mapReadPretty } from '@formily/vue' import { PreviewText } from '../preview-text' import type { Input as ElInputProps } from 'element-ui' export type PasswordProps = ElInputProps export const Password = connect( Input, mapProps((props) => { return { ...props, showPassword: true, } }), mapReadPretty(PreviewText.Input) ) export default Password ``` -------------------------------------------------------------------------------- /packages/reactive-vue/src/observer/observerInVue3.ts: -------------------------------------------------------------------------------- ```typescript import { IObserverOptions } from '../types' import { useObserver } from '../hooks/useObserver' /* istanbul ignore next */ export const observer = function (opts: any, options?: IObserverOptions): any { const name = options?.name || opts.name || 'ObservableComponent' return { name, ...opts, setup(props: Record<string, any>, context: any) { useObserver(options) return opts?.setup?.(props, context) }, } } ``` -------------------------------------------------------------------------------- /packages/vue/docs/demos/api/components/form-provider.vue: -------------------------------------------------------------------------------- ```vue <template> <FormProvider :form="form"> <Field name="input" :component="[Input]" /> </FormProvider> </template> <script> import { Input } from 'ant-design-vue' import { createForm } from '@formily/core' import { FormProvider, Field } from '@formily/vue' import 'ant-design-vue/dist/antd.css' export default { components: { FormProvider, Field }, data() { return { Input, form: createForm(), } }, } </script> ``` -------------------------------------------------------------------------------- /docs/site/QrCode.less: -------------------------------------------------------------------------------- ``` .qrcode-group { display: flex; justify-content: center; .qrcode { width: 400px; margin: 20px; display: flex; flex-direction: column; justify-content: center; align-items: center; &-title { font-size: 20px; position: relative; &-content { position: absolute; left: 50%; bottom: 0; white-space: nowrap; transform: translateX(-50%); } } } } ``` -------------------------------------------------------------------------------- /packages/core/docs/api/entry/ActionResponse.tsx: -------------------------------------------------------------------------------- ```typescript import React from 'react' import './ActionResponse.less' type ActionResponseProps = { response?: React.ReactNode } export const ActionResponse: React.FC< React.PropsWithChildren<ActionResponseProps> > = (props) => { return ( <div className="as-wrapper"> <div className="as-actions">{props.children}</div> {props.response && ( <div className="as-response">Response:{props.response}</div> )} </div> ) } ``` -------------------------------------------------------------------------------- /packages/react/src/hooks/useFormEffects.ts: -------------------------------------------------------------------------------- ```typescript import { unstable_useCompatFactory } from '@formily/reactive-react' import { Form } from '@formily/core' import { uid } from '@formily/shared' import { useForm } from './useForm' export const useFormEffects = (effects?: (form: Form) => void) => { const form = useForm() unstable_useCompatFactory(() => { const id = uid() form.addEffects(id, effects) return { dispose() { form.removeEffects(id) }, } }) } ``` -------------------------------------------------------------------------------- /packages/react/src/components/FormConsumer.tsx: -------------------------------------------------------------------------------- ```typescript import React, { Fragment } from 'react' import { isFn } from '@formily/shared' import { observer } from '@formily/reactive-react' import { useForm } from '../hooks' import { IFormSpyProps, ReactFC } from '../types' export const FormConsumer: ReactFC<IFormSpyProps> = observer((props) => { const children = isFn(props.children) ? props.children(useForm()) : null return <Fragment>{children}</Fragment> }) FormConsumer.displayName = 'FormConsumer' ``` -------------------------------------------------------------------------------- /packages/reactive-react/src/types.ts: -------------------------------------------------------------------------------- ```typescript import React from 'react' export interface IObserverOptions { forwardRef?: boolean scheduler?: (updater: () => void) => void displayName?: string } export interface IObserverProps { children?: (() => React.ReactElement) | React.ReactNode } export type Modify<T, R> = Omit<T, keyof R> & R export type ReactPropsWithChildren<P> = Modify< { children?: React.ReactNode | undefined }, P > export type ReactFC<P = {}> = React.FC<ReactPropsWithChildren<P>> ``` -------------------------------------------------------------------------------- /packages/vue/docs/demos/api/components/field.vue: -------------------------------------------------------------------------------- ```vue <template> <FormProvider :form="form"> <Field name="input" :component="[Input, { placeholder: '请输入' }]" /> </FormProvider> </template> <script> import { Input } from 'ant-design-vue' import { createForm } from '@formily/core' import { FormProvider, Field } from '@formily/vue' import 'ant-design-vue/dist/antd.css' export default { components: { FormProvider, Field }, data() { return { Input, form: createForm(), } }, } </script> ``` -------------------------------------------------------------------------------- /packages/react/src/components/FormProvider.tsx: -------------------------------------------------------------------------------- ```typescript import React from 'react' import { useAttach } from '../hooks/useAttach' import { FormContext, ContextCleaner } from '../shared' import { IProviderProps, ReactFC } from '../types' export const FormProvider: ReactFC<IProviderProps> = (props) => { const form = useAttach(props.form) return ( <ContextCleaner> <FormContext.Provider value={form}>{props.children}</FormContext.Provider> </ContextCleaner> ) } FormProvider.displayName = 'FormProvider' ``` -------------------------------------------------------------------------------- /packages/react/src/hooks/useParentForm.ts: -------------------------------------------------------------------------------- ```typescript import { isObjectField, GeneralField, Form, ObjectField } from '@formily/core' import { useField } from './useField' import { useForm } from './useForm' export const useParentForm = (): Form | ObjectField => { const field = useField() const form = useForm() const findObjectParent = (field: GeneralField) => { if (!field) return form if (isObjectField(field)) return field return findObjectParent(field?.parent) } return findObjectParent(field) } ``` -------------------------------------------------------------------------------- /packages/path/src/contexts.ts: -------------------------------------------------------------------------------- ```typescript export type Context = { flag: string [key: string]: any } const ContextType = (flag: string, props?: any): Context => { return { flag, ...props, } } export const bracketContext = ContextType('[]') export const bracketArrayContext = ContextType('[\\d]') export const bracketDContext = ContextType('[[]]') export const parenContext = ContextType('()') export const braceContext = ContextType('{}') export const destructorContext = ContextType('{x}') ``` -------------------------------------------------------------------------------- /packages/reactive/docs/api/untracked.md: -------------------------------------------------------------------------------- ```markdown # untracked ## Description Usage is similar to batch, and will never be collected by dependencies within a given untracker function ## Signature ```ts interface untracked<T extends () => any> { (untracker?: T): ReturnType<T> } ``` ## Example ```ts import { observable, autorun, untracked } from '@formily/reactive' const obs = observable({ aa: 11, }) autorun(() => { console.log(untracked(() => obs.aa)) // will not trigger when changes }) obs.aa = 22 ``` ``` -------------------------------------------------------------------------------- /packages/vue/src/components/index.ts: -------------------------------------------------------------------------------- ```typescript export { default as FormProvider } from './FormProvider' export { default as FormConsumer } from './FormConsumer' export { default as ArrayField } from './ArrayField' export { default as ObjectField } from './ObjectField' export { default as VoidField } from './VoidField' export { default as RecursionField } from './RecursionField' export { default as Field } from './Field' export { createSchemaField } from './SchemaField' export { ExpressionScope } from './ExpressionScope' ``` -------------------------------------------------------------------------------- /docs/site/Contributors.less: -------------------------------------------------------------------------------- ``` .contri-list { display: flex; flex-wrap: wrap; .contri-user { display: flex; flex-direction: column; width: 120px; height: 120px; align-items: center; justify-content: center; &-avatar { display: block; width: 60px; height: 60px; border-radius: 60px; overflow: hidden; transition: all 0.15s ease-in-out; &:hover { opacity: 0.8; } } &-info { text-align: center; } } } ``` -------------------------------------------------------------------------------- /packages/reactive/docs/api/raw.md: -------------------------------------------------------------------------------- ```markdown # raw ## Description Obtain the source data from the observable object. Generally, this API is not recommended <Alert> Note: Only the source data of the current object can be obtained, excluding deep object properties </Alert> ## Signature ```ts interface raw<T extends object> { (target: T): T } ``` ## Example ```ts import { raw, observable } from '@formily/reactive' const obs = observable({}) obs.aa = { bb: 123 } console.log(raw(obs)) console.log(raw(obs.aa)) ``` ``` -------------------------------------------------------------------------------- /packages/core/docs/api/entry/ActionResponse.less: -------------------------------------------------------------------------------- ``` .as-wrapper { .as-actions { & button { margin-right: 5px; background-color: #fff; border: 2px solid #d4bbbb; border-radius: 6px; outline: none; padding: 8px 20px; cursor: pointer; transition: all 0.15s ease-in-out; &:hover { border: 2px solid #9db8f3; } } } .as-response { border: 2px dashed #f0bdbd; font-size: 14px; border-radius: 6px; padding: 8px 20px; margin-top: 10px; } } ``` -------------------------------------------------------------------------------- /packages/vue/src/hooks/useFormEffects.ts: -------------------------------------------------------------------------------- ```typescript import { onBeforeUnmount, watchEffect } from 'vue-demi' import { Form } from '@formily/core' import { uid } from '@formily/shared' import { useForm } from './useForm' export const useFormEffects = (effects?: (form: Form) => void): void => { const formRef = useForm() const stop = watchEffect((onCleanup) => { const id = uid() formRef.value.addEffects(id, effects) onCleanup(() => { formRef.value.removeEffects(id) }) }) onBeforeUnmount(() => stop()) } ``` -------------------------------------------------------------------------------- /packages/antd/src/style.ts: -------------------------------------------------------------------------------- ```typescript // auto generated code import './array-base/style.less' import './array-cards/style.less' import './array-collapse/style.less' import './array-items/style.less' import './array-table/style.less' import './editable/style.less' import './form-button-group/style.less' import './form-grid/style.less' import './form-item/style.less' import './form-layout/style.less' import './form/style.less' import './preview-text/style.less' import './radio/style.less' import './select-table/style.less' ``` -------------------------------------------------------------------------------- /packages/reactive-vue/src/observer/index.ts: -------------------------------------------------------------------------------- ```typescript import { isVue2 } from 'vue-demi' import { observer as observerV2 } from './observerInVue2' import { observer as observerV3 } from './observerInVue3' import collectData from './collectData' import { IObserverOptions } from '../types' export function observer<C>(baseComponent: C, options?: IObserverOptions): C { /* istanbul ignore else */ if (isVue2) { return observerV2(baseComponent, options) } else { return observerV3(baseComponent, options) } } export { collectData } ``` -------------------------------------------------------------------------------- /packages/reactive/src/observable.ts: -------------------------------------------------------------------------------- ```typescript import * as annotations from './annotations' import { MakeObModelSymbol } from './environment' import { createObservable } from './internals' export function observable<T extends object>(target: T): T { return createObservable(null, null, target) } observable.box = annotations.box observable.ref = annotations.ref observable.deep = annotations.observable observable.shallow = annotations.shallow observable.computed = annotations.computed observable[MakeObModelSymbol] = annotations.observable ``` -------------------------------------------------------------------------------- /packages/reactive/docs/api/typeChecker.md: -------------------------------------------------------------------------------- ```markdown # Type Checker ## isObservable #### Description Determine whether an object is observable #### Signature ```ts interface isObservable { (target: any): boolean } ``` ## isAnnotation #### Description Determine whether an object is Annotation #### Signature ```ts interface isAnnotation { (target: any): boolean } ``` ## isSupportObservable #### Description Determine whether an object can be observable #### Signature ```ts interface isSupportObservable { (target: any): boolean } ``` ``` -------------------------------------------------------------------------------- /packages/reactive/docs/api/hasCollected.md: -------------------------------------------------------------------------------- ```markdown # hasCollected ## describe Used to detect whether a certain piece of execution logic has dependent collection ## Signature ```ts interface hasCollected { (callback?: () => void): boolean } ``` ## Example ```ts import { observable, autorun } from '@formily/reactive' const obs = observable({ aa: 11, }) autorun(() => { console.log( hasCollected(() => { obs.aa }) ) //return true console.log( hasCollected(() => { 11 + 22 }) ) //return false }) obs.aa = 22 ``` ``` -------------------------------------------------------------------------------- /packages/react/src/components/ExpressionScope.tsx: -------------------------------------------------------------------------------- ```typescript import React, { useContext } from 'react' import { lazyMerge } from '@formily/shared' import { SchemaExpressionScopeContext } from '../shared' import { IExpressionScopeProps, ReactFC } from '../types' export const ExpressionScope: ReactFC<IExpressionScopeProps> = (props) => { const scope = useContext(SchemaExpressionScopeContext) return ( <SchemaExpressionScopeContext.Provider value={lazyMerge(scope, props.value)} > {props.children} </SchemaExpressionScopeContext.Provider> ) } ``` -------------------------------------------------------------------------------- /packages/antd/src/style.less: -------------------------------------------------------------------------------- ``` // auto generated code @import './array-base/style.less'; @import './array-cards/style.less'; @import './array-collapse/style.less'; @import './array-items/style.less'; @import './array-table/style.less'; @import './editable/style.less'; @import './form-button-group/style.less'; @import './form-grid/style.less'; @import './form-item/style.less'; @import './form-layout/style.less'; @import './form/style.less'; @import './preview-text/style.less'; @import './radio/style.less'; @import './select-table/style.less'; ``` -------------------------------------------------------------------------------- /packages/reactive/src/action.ts: -------------------------------------------------------------------------------- ```typescript import { batchStart, batchEnd, batchScopeStart, batchScopeEnd, untrackStart, untrackEnd, } from './reaction' import { createBoundaryAnnotation } from './internals' import { IAction } from './types' export const action: IAction = createBoundaryAnnotation( () => { batchStart() untrackStart() }, () => { untrackEnd() batchEnd() } ) action.scope = createBoundaryAnnotation( () => { batchScopeStart() untrackStart() }, () => { untrackEnd() batchScopeEnd() } ) ``` -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- ```json { "compilerOptions": { "esModuleInterop": true, "moduleResolution": "node", "jsx": "react", "module": "commonjs", "target": "es5", "allowJs": false, "noUnusedLocals": false, "preserveConstEnums": true, "skipLibCheck": true, "sourceMap": true, "inlineSources": true, "declaration": true, "experimentalDecorators": true, "downlevelIteration": true, "baseUrl": ".", "paths": { "@formily/*": ["packages/*/src", "devtools/*/src"] }, "lib": ["ESNext"] } } ``` -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- ```yaml blank_issues_enabled: true contact_links: - name: Create new issue url: https://formilyjs.org/guide/issue-helper about: The issue which is not created via https://formilyjs.org/guide/issue-helper will be closed immediately. - name: ✨ Question Answer / Idea url: https://github.com/alibaba/formily/discussions/new about: All questions can be solved here. At the same time you can provide all your ideas here. - name: 📖 View documentation url: https://formilyjs.org about: Official Formily documentation ``` -------------------------------------------------------------------------------- /packages/vue/src/hooks/useAttach.ts: -------------------------------------------------------------------------------- ```typescript import { onMounted, watch, Ref, onUnmounted, nextTick } from 'vue-demi' interface IRecycleTarget { onMount: () => void onUnmount: () => void } export const useAttach = <T extends IRecycleTarget>(target: Ref<T>): Ref<T> => { watch(target, (v, old, onInvalidate) => { if (v && v !== old) { old?.onUnmount() nextTick(() => v.onMount()) onInvalidate(() => v.onUnmount()) } }) onMounted(() => { target.value?.onMount() }) onUnmounted(() => { target.value?.onUnmount() }) return target } ``` -------------------------------------------------------------------------------- /packages/element/src/array-base/style.scss: -------------------------------------------------------------------------------- ```scss @import '../__builtins__/styles/common.scss'; $array-base-prefix-cls: '#{$formily-prefix}-array-base'; .#{$array-base-prefix-cls}-addition { transition: $--all-transition; } .#{$array-base-prefix-cls}-remove { i { font-size: $--font-size-base; } } .#{$array-base-prefix-cls}-move-down { i { font-size: $--font-size-base; } } .#{$array-base-prefix-cls}-move-up { i { font-size: $--font-size-base; } } .#{$array-base-prefix-cls}-sort-handle { i { font-size: $--font-size-base; cursor: move; } } ``` -------------------------------------------------------------------------------- /packages/next/src/style.ts: -------------------------------------------------------------------------------- ```typescript // auto generated code import './array-base/main.scss' import './array-cards/main.scss' import './array-collapse/main.scss' import './array-items/main.scss' import './array-table/main.scss' import './date-picker2/main.scss' import './editable/main.scss' import './form-button-group/main.scss' import './form-grid/main.scss' import './form-item/main.scss' import './form-layout/main.scss' import './form/main.scss' import './preview-text/main.scss' import './select-table/main.scss' import './space/main.scss' import './upload/main.scss' ``` -------------------------------------------------------------------------------- /packages/vue/src/shared/fragment.ts: -------------------------------------------------------------------------------- ```typescript import { Fragment as FragmentV2 } from 'vue-frag' import { DefineComponent } from '../types' import { isVue2, defineComponent } from 'vue-demi' export const Fragment = '#fragment' let FragmentComponent: DefineComponent<{}> if (isVue2) { FragmentComponent = { name: 'Fragment', ...FragmentV2, } as unknown as DefineComponent<{}> } else { /* istanbul ignore next */ FragmentComponent = defineComponent({ name: 'Fragment', render() { return this.$slots.default?.() }, }) } export { FragmentComponent } ``` -------------------------------------------------------------------------------- /packages/vue/src/hooks/useParentForm.ts: -------------------------------------------------------------------------------- ```typescript import { isObjectField, GeneralField, Form, ObjectField } from '@formily/core' import { computed, Ref } from 'vue-demi' import { useField } from './useField' import { useForm } from './useForm' export const useParentForm = (): Ref<Form | ObjectField> => { const field = useField() const form = useForm() const findObjectParent = (field: GeneralField) => { if (!field) return form.value if (isObjectField(field)) return field return findObjectParent(field?.parent) } return computed(() => findObjectParent(field.value)) } ``` -------------------------------------------------------------------------------- /docs/guide/advanced/layout.md: -------------------------------------------------------------------------------- ```markdown # Form Layout The form layout mainly uses [@formily/antd](https://antd.formilyjs.org) or [@formily/next](https://fusion.formilyjs.org): - [FormLayout](http://antd.formilyjs.org/components/form-layout) Component - [FormItem](http://antd.formilyjs.org/components/form-item) Component - [FormGrid](http://antd.formilyjs.org/components/form-grid) Component - [Space](http://antd.formilyjs.org/components/space) Component These 4 components can basically solve all complex form layout scenarios, we only need to flexibly combine these components. ``` -------------------------------------------------------------------------------- /packages/element/src/style.ts: -------------------------------------------------------------------------------- ```typescript // auto generated code import './array-base/style.scss' import './array-cards/style.scss' import './array-collapse/style.scss' import './array-items/style.scss' import './array-table/style.scss' import './array-tabs/style.scss' import './editable/style.scss' import './form-button-group/style.scss' import './form-collapse/style.scss' import './form-drawer/style.scss' import './form-grid/style.scss' import './form-item/style.scss' import './form-layout/style.scss' import './form-tab/style.scss' import './form/style.scss' import './space/style.scss' ``` -------------------------------------------------------------------------------- /packages/vue/src/utils/getRawComponent.ts: -------------------------------------------------------------------------------- ```typescript import { IFieldProps, VueComponent } from '../types' import { toRaw } from 'vue-demi' export const getRawComponent = ( props: IFieldProps<VueComponent, VueComponent> ) => { const { component, decorator } = props let newComponent: typeof props.component let newDecorator: typeof props.component if (Array.isArray(component)) { newComponent = [toRaw(component[0]), component[1]] } if (Array.isArray(decorator)) { newDecorator = [toRaw(decorator[0]), decorator[1]] } return { component: newComponent, decorator: newDecorator } } ``` -------------------------------------------------------------------------------- /packages/element/src/__builtins__/shared/resolve-component.ts: -------------------------------------------------------------------------------- ```typescript import { Component } from 'vue' import { h, toRaw } from 'vue-demi' import { SlotTypes } from '.' import { isVnode } from './utils' export const resolveComponent = ( child?: SlotTypes, props?: Record<string, any> ) => { if (child) { if (typeof child === 'string' || typeof child === 'number') { return child } else if (typeof child === 'function') { return (child as Function)(props) } else if (isVnode(child)) { return child } else { return h(toRaw(child as Component), { props }) } } return null } ``` -------------------------------------------------------------------------------- /packages/reactive/docs/api/toJS.md: -------------------------------------------------------------------------------- ```markdown # toJS ## Description Deep recursion converts observable objects into ordinary JS objects Note: If you mark an object that is already observable with markRaw, then toJS will not convert it into a normal object ## Signature ```ts interface toJS<T> { (target: T): T } ``` ## Example ```ts import { observable, autorun, toJS } from '@formily/reactive' const obs = observable({ aa: { bb: { cc: 123, }, }, }) const js = toJS(obs) autorun(() => { console.log(js.aa.bb.cc) // will not trigger when changes }) js.aa.bb.cc = 321 ``` ``` -------------------------------------------------------------------------------- /packages/reactive/docs/api/action.md: -------------------------------------------------------------------------------- ```markdown # action ## Description Define a batch action. The only difference with batch is that dependencies cannot be collected inside an action ## Signature ```ts interface action { <T>(callback?: () => T): T //In-situ action scope<T>(callback?: () => T): T //In-situ local action bound<T extends (...args: any[]) => any>(callback: T, context?: any): T //High-level binding } ``` ## Example ```ts import { observable, action } from '@formily/reactive' const obs = observable({}) const method = action.bound(() => { obs.aa = 123 obs.bb = 321 }) method() ``` ``` -------------------------------------------------------------------------------- /packages/next/src/main.scss: -------------------------------------------------------------------------------- ```scss // auto generated code @import './array-base/main.scss'; @import './array-cards/main.scss'; @import './array-collapse/main.scss'; @import './array-items/main.scss'; @import './array-table/main.scss'; @import './date-picker2/main.scss'; @import './editable/main.scss'; @import './form-button-group/main.scss'; @import './form-grid/main.scss'; @import './form-item/main.scss'; @import './form-layout/main.scss'; @import './form/main.scss'; @import './preview-text/main.scss'; @import './select-table/main.scss'; @import './space/main.scss'; @import './upload/main.scss'; ``` -------------------------------------------------------------------------------- /packages/next/src/__builtins__/mapStatus.ts: -------------------------------------------------------------------------------- ```typescript import { Field } from '@formily/core' export const mapStatus = (props: any, field: Field) => { const takeStatus = () => { if (!field) return if (field.loading || field.validating) return 'loading' if (field.selfErrors?.length) return 'error' if (field.selfWarnings?.length) return 'warning' return field.decoratorProps?.feedbackStatus } const takeState = (state: string) => { if (state === 'validating' || state === 'pending') return 'loading' return state } return { ...props, state: takeState(props.state) || takeStatus(), } } ``` -------------------------------------------------------------------------------- /packages/element/src/el-form-item/index.ts: -------------------------------------------------------------------------------- ```typescript import { isVoidField } from '@formily/core' import { connect, mapProps } from '@formily/vue' import type { FormItem as _ElFormItemProps } from 'element-ui' import { FormItem as ElFormItemComponent } from 'element-ui' export type ElFormItemProps = _ElFormItemProps & { title: string } export const ElFormItem = connect( ElFormItemComponent, mapProps({ title: 'label', required: true }, (props, field) => ({ error: !isVoidField(field) ? field.errors.length ? field.errors.join(',') : undefined : undefined, })) ) export default ElFormItem ``` -------------------------------------------------------------------------------- /docs/site/QrCode.tsx: -------------------------------------------------------------------------------- ```typescript import React from 'react' import './QrCode.less' export interface IQrCodeProps { title?: React.ReactNode link?: string } export const QrCode: React.FC<React.PropsWithChildren<IQrCodeProps>> = ( props ) => { return ( <div className="qrcode"> <div className="qrcode-title"> <div className="qrcode-title-content">{props.title}</div> </div> <div className="qrcode-content"> <img src={props.link} /> </div> </div> ) } export const QrCodeGroup: React.FC = (props) => ( <div className="qrcode-group">{props.children}</div> ) ``` -------------------------------------------------------------------------------- /packages/reactive/src/batch.ts: -------------------------------------------------------------------------------- ```typescript import { batchStart, batchEnd, batchScopeStart, batchScopeEnd, } from './reaction' import { BatchEndpoints, BatchCount } from './environment' import { createBoundaryAnnotation } from './internals' import { IBatch } from './types' import { isFn } from './checkers' export const batch: IBatch = createBoundaryAnnotation(batchStart, batchEnd) batch.scope = createBoundaryAnnotation(batchScopeStart, batchScopeEnd) batch.endpoint = (callback?: () => void) => { if (!isFn(callback)) return if (BatchCount.value === 0) { callback() } else { BatchEndpoints.add(callback) } } ``` -------------------------------------------------------------------------------- /packages/vue/docs/demos/api/components/form-consumer.vue: -------------------------------------------------------------------------------- ```vue <template> <FormProvider :form="form"> <Field name="input" :component="[Input]" /> <FormConsumer> <template #default="{ form }"> {{ form.values.input }} </template> </FormConsumer> </FormProvider> </template> <script> import { Input } from 'ant-design-vue' import { createForm } from '@formily/core' import { FormProvider, Field, FormConsumer } from '@formily/vue' import 'ant-design-vue/dist/antd.css' export default { components: { FormProvider, Field, FormConsumer }, data() { return { Input, form: createForm(), } }, } </script> ``` -------------------------------------------------------------------------------- /packages/next/create-style.ts: -------------------------------------------------------------------------------- ```typescript import glob from 'glob' import path from 'path' import fs from 'fs-extra' glob( './*/main.scss', { cwd: path.resolve(__dirname, './src') }, (err, files) => { if (err) return console.error(err) fs.writeFile( path.resolve(__dirname, './src/style.ts'), `// auto generated code ${files .map((path) => { return `import '${path}'\n` }) .join('')}`, 'utf8' ) fs.writeFile( path.resolve(__dirname, './src/main.scss'), `// auto generated code ${files .map((path) => { return `@import '${path}';\n` }) .join('')}`, 'utf8' ) } ) ``` -------------------------------------------------------------------------------- /docs/guide/advanced/custom.md: -------------------------------------------------------------------------------- ```markdown # Custom Components The realization of business custom components mainly uses the Hooks API and observer API in [@formily/react](https://react.formilyjs.org) or [@formily/vue](https://vue.formilyjs.org). To access the ready-made component library, we mainly use connect/mapProps/mapReadPretty API. If you want to implement some more complex custom components, we strongly recommend looking directly at the source code of [@formily/antd](https://github.com/alibaba/formily/tree/formily_next/packages/antd/src) or [@formily/next](https://github.com/alibaba/formily/tree/formily_next/packages/next/src). ``` -------------------------------------------------------------------------------- /scripts/build-style/buildAllStyles.ts: -------------------------------------------------------------------------------- ```typescript import typescript from 'rollup-plugin-typescript2' import { build, getRollupBasePlugin } from './helper' // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types export const buildAllStyles = async (outputFile: string) => { await build({ input: 'src/style.ts', output: { file: outputFile, }, plugins: [ typescript({ tsconfig: './tsconfig.json', tsconfigOverride: { compilerOptions: { module: 'ESNext', declaration: false, }, }, }), ...getRollupBasePlugin(), ], }) } ``` -------------------------------------------------------------------------------- /packages/antd/create-style.ts: -------------------------------------------------------------------------------- ```typescript import glob from 'glob' import path from 'path' import fs from 'fs-extra' glob( './*/style.less', { cwd: path.resolve(__dirname, './src') }, (err, files) => { if (err) return console.error(err) fs.writeFile( path.resolve(__dirname, './src/style.ts'), `// auto generated code ${files .map((path) => { return `import '${path}'\n` }) .join('')}`, 'utf8' ) fs.writeFile( path.resolve(__dirname, './src/style.less'), `// auto generated code ${files .map((path) => { return `@import '${path}';\n` }) .join('')}`, 'utf8' ) } ) ``` -------------------------------------------------------------------------------- /packages/shared/src/middleware.ts: -------------------------------------------------------------------------------- ```typescript export interface IMiddleware<Payload = any, Result = any> { (payload: Payload, next: (payload?: Payload) => Result): Result } export const applyMiddleware = (payload: any, fns: IMiddleware[] = []) => { const compose = (payload: any, fns: IMiddleware[]): Promise<any> => { const prevPayload = payload return Promise.resolve( fns[0](payload, (payload) => compose(payload ?? prevPayload, fns.slice(1)) ) ) } return new Promise((resolve, reject) => { compose( payload, fns.concat((payload) => { resolve(payload) }) ).catch(reject) }) } ``` -------------------------------------------------------------------------------- /packages/vue/docs/demos/api/components/schema-field.vue: -------------------------------------------------------------------------------- ```vue <template> <FormProvider :form="form"> <SchemaField> <SchemaStringField name="input" x-component="Input" /> </SchemaField> </FormProvider> </template> <script> import { Input } from 'ant-design-vue' import { createForm } from '@formily/core' import { FormProvider, createSchemaField } from '@formily/vue' import 'ant-design-vue/dist/antd.css' const { SchemaField, SchemaStringField } = createSchemaField({ components: { Input, }, }) export default { components: { FormProvider, SchemaField, SchemaStringField }, data() { return { form: createForm(), } }, } </script> ``` -------------------------------------------------------------------------------- /devtools/chrome-extension/src/extension/devtools.tsx: -------------------------------------------------------------------------------- ```typescript declare let chrome: any let created = false const createPanel = () => { if (created) { return } chrome.devtools.inspectedWindow.eval( 'window.__FORMILY_DEV_TOOLS_HOOK__ && window.__FORMILY_DEV_TOOLS_HOOK__.hasFormilyInstance', (hasFormily: boolean) => { if (!hasFormily) return created = true clearInterval(loadCheckInterval) chrome.devtools.panels.create( 'Formily', 'img/logo/scalable.png', './devpanel.html', function () {} ) } ) } const loadCheckInterval = setInterval(function () { createPanel() }, 1000) createPanel() ``` -------------------------------------------------------------------------------- /packages/reactive-react/src/hooks/index.ts: -------------------------------------------------------------------------------- ```typescript import { useForceUpdate } from './useForceUpdate' import { useCompatEffect } from './useCompatEffect' import { useCompatFactory } from './useCompatFactory' import { useDidUpdate } from './useDidUpdate' import { useLayoutEffect } from './useLayoutEffect' import { useObserver } from './useObserver' export const unstable_useForceUpdate = useForceUpdate export const unstable_useCompatEffect = useCompatEffect export const unstable_useCompatFactory = useCompatFactory export const unstable_useDidUpdate = useDidUpdate export const unstable_useLayoutEffect = useLayoutEffect export const unstable_useObserver = useObserver ``` -------------------------------------------------------------------------------- /packages/element/docs/demos/guide/form-item/template.vue: -------------------------------------------------------------------------------- ```vue <template> <Form :form="form"> <Field name="input" title="输入框" :decorator="[FormItem]" :component="[Input]" required /> <Submit @submit="onSubmit">提交</Submit> </Form> </template> <script> import { createForm } from '@formily/core' import { Field } from '@formily/vue' import { Form, FormItem, Input, Submit } from '@formily/element' const form = createForm() export default { components: { Form, Field, Submit }, data() { return { FormItem, Input, form, } }, methods: { onSubmit(value) { console.log(value) }, }, } </script> ``` -------------------------------------------------------------------------------- /packages/element/src/time-picker/index.ts: -------------------------------------------------------------------------------- ```typescript import { transformComponent } from '../__builtins__/shared' import { connect, mapProps, mapReadPretty } from '@formily/vue' import { PreviewText } from '../preview-text' import type { TimePicker as ElTimePickerProps } from 'element-ui' import { TimePicker as ElTimePicker } from 'element-ui' export type TimePickerProps = ElTimePickerProps const TransformElTimePicker = transformComponent<TimePickerProps>( ElTimePicker, { change: 'input', } ) export const TimePicker = connect( TransformElTimePicker, mapProps({ readOnly: 'readonly' }), mapReadPretty(PreviewText.TimePicker) ) export default TimePicker ``` -------------------------------------------------------------------------------- /packages/reactive-react/src/hooks/useObserver.ts: -------------------------------------------------------------------------------- ```typescript import { Tracker } from '@formily/reactive' import { IObserverOptions } from '../types' import { useForceUpdate } from './useForceUpdate' import { useCompatFactory } from './useCompatFactory' export const useObserver = <T extends () => any>( view: T, options?: IObserverOptions ): ReturnType<T> => { const forceUpdate = useForceUpdate() const tracker = useCompatFactory( () => new Tracker(() => { if (typeof options?.scheduler === 'function') { options.scheduler(forceUpdate) } else { forceUpdate() } }, options?.displayName) ) return tracker.track(view) } ``` -------------------------------------------------------------------------------- /docs/site/Section.tsx: -------------------------------------------------------------------------------- ```typescript import React from 'react' import './Section.less' export interface ISectionProps { title?: React.ReactNode style?: React.CSSProperties titleStyle?: React.CSSProperties scale?: number } export const Section: React.FC<React.PropsWithChildren<ISectionProps>> = ( props ) => { return ( <section className="site-section" style={props.style}> <div className="site-section-title" style={props.titleStyle}> {props.title} </div> <div className="site-section-body" style={{ transform: `scale(${props.scale || 1})` }} > {props.children} </div> </section> ) } ``` -------------------------------------------------------------------------------- /packages/element/docs/demos/guide/switch/template.vue: -------------------------------------------------------------------------------- ```vue <template> <FormProvider :form="form"> <Field name="switch" title="开关" :decorator="[FormItem]" :component="[Switch]" /> <Submit @submit="log">提交</Submit> </FormProvider> </template> <script> import { createForm } from '@formily/core' import { FormProvider, Field } from '@formily/vue' import { FormItem, Switch, Submit } from '@formily/element' const form = createForm() export default { components: { FormProvider, Field, Submit }, data() { return { FormItem, Switch, form, } }, methods: { log(value) { console.log(value) }, }, } </script> ``` -------------------------------------------------------------------------------- /packages/element/docs/demos/guide/password/template.vue: -------------------------------------------------------------------------------- ```vue <template> <FormProvider :form="form"> <Field name="input" title="密码框" :decorator="[FormItem]" :component="[Password]" /> <Submit @submit="log">提交</Submit> </FormProvider> </template> <script> import { createForm } from '@formily/core' import { FormProvider, Field } from '@formily/vue' import { FormItem, Password, Submit } from '@formily/element' const form = createForm() export default { components: { FormProvider, Field, Submit }, data() { return { FormItem, Password, form, } }, methods: { log(value) { console.log(value) }, }, } </script> ``` -------------------------------------------------------------------------------- /packages/validator/src/template.ts: -------------------------------------------------------------------------------- ```typescript import { isFn, isStr, FormPath } from '@formily/shared' import { IValidateResult, IValidatorRules } from './types' import { getValidateMessageTemplateEngine } from './registry' export const render = ( result: IValidateResult, rules: IValidatorRules ): IValidateResult => { const { message } = result if (isStr(message)) { const template = getValidateMessageTemplateEngine() if (isFn(template)) { result.message = template(message, rules) } result.message = result.message.replace( /\{\{\s*([\w.]+)\s*\}\}/g, (_, $0) => { return FormPath.getIn(rules, $0) } ) } return result } ``` -------------------------------------------------------------------------------- /docs/functions/npm-search.ts: -------------------------------------------------------------------------------- ```typescript import { Handler } from '@netlify/functions' import qs from 'querystring' import axios from 'axios' const headers = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': 'Content-Type', 'Access-Control-Allow-Methods': 'GET', } export const handler: Handler = async (event) => { if (event.httpMethod !== 'GET') { return { statusCode: 405, body: 'Method Not Allowed' } } const params = qs.parse(event.rawQuery) const results = await axios.get( `https://www.npmjs.com/search/suggestions?q=${params.q}&size=100` ) return { statusCode: 200, headers, body: JSON.stringify(results.data), } } ``` -------------------------------------------------------------------------------- /packages/vue/src/utils/formatVNodeData.ts: -------------------------------------------------------------------------------- ```typescript import { each } from '@formily/shared' type VNodeData = Record<string, any> export const formatVue3VNodeData = (data: VNodeData) => { const newData = {} each(data, (value, key) => { if (key === 'on' || key === 'nativeOn') { if (value) { each(value, (func, name) => { const eventName = `on${ key === 'on' ? name[0].toUpperCase() : name[0] }${name.slice(1)}` newData[eventName] = func }) } } else if (key === 'attrs' || key === 'props' || key === 'domProps') { Object.assign(newData, value) } else { newData[key] = value } }) return newData } ``` -------------------------------------------------------------------------------- /packages/antd/src/radio/index.tsx: -------------------------------------------------------------------------------- ```typescript import { connect, mapProps, mapReadPretty } from '@formily/react' import { Radio as AntdRadio } from 'antd' import { RadioProps, RadioGroupProps } from 'antd/lib/radio' import { PreviewText } from '../preview-text' type ComposedRadio = React.FC<React.PropsWithChildren<RadioProps>> & { Group?: React.FC<React.PropsWithChildren<RadioGroupProps>> __ANT_RADIO?: boolean } export const Radio: ComposedRadio = connect( AntdRadio, mapProps({ value: 'checked', }) ) Radio.__ANT_RADIO = true Radio.Group = connect( AntdRadio.Group, mapProps({ dataSource: 'options', }), mapReadPretty(PreviewText.Select) ) export default Radio ``` -------------------------------------------------------------------------------- /packages/reactive/docs/api/model.md: -------------------------------------------------------------------------------- ```markdown # model ## Description Quickly define the domain model, and automatically declare the model attributes: - Automatic declaration of getter/setter properties computed - Function automatically declare action - Common attributes are automatically declared observable ## Signature ```ts interface model<Target extends object> { (target: Target): Target } ``` ## Example ```ts import { model, autorun } from '@formily/reactive' const obs = model({ aa: 1, bb: 2, get cc() { return this.aa + this.bb }, update(aa, bb) { this.aa=aa this.bb=bb }, }) autorun(() => { console.log(obs.cc) }) obs.aa = 3 obs.update(4, 6) ``` ``` -------------------------------------------------------------------------------- /packages/antd/src/cascader/index.tsx: -------------------------------------------------------------------------------- ```typescript import React from 'react' import { connect, mapReadPretty, mapProps } from '@formily/react' import { Cascader as AntdCascader } from 'antd' import { PreviewText } from '../preview-text' import { LoadingOutlined } from '@ant-design/icons' export const Cascader = connect( AntdCascader, mapProps( { dataSource: 'options', }, (props, field) => { return { ...props, suffixIcon: field?.['loading'] || field?.['validating'] ? ( <LoadingOutlined /> ) : ( props.suffixIcon ), } } ), mapReadPretty(PreviewText.Cascader) ) export default Cascader ``` -------------------------------------------------------------------------------- /packages/vue/src/components/ExpressionScope.ts: -------------------------------------------------------------------------------- ```typescript import { lazyMerge } from '@formily/shared' import { computed, defineComponent, inject, provide, Ref } from 'vue-demi' import { SchemaExpressionScopeSymbol, Fragment, h } from '../shared' import { IExpressionScopeProps } from '../types' export const ExpressionScope = defineComponent({ name: 'ExpressionScope', props: ['value'], setup(props: IExpressionScopeProps, { slots }) { const scopeRef = inject<Ref>(SchemaExpressionScopeSymbol) const expressionScopeRef = computed(() => lazyMerge(scopeRef.value, props.value) ) provide(SchemaExpressionScopeSymbol, expressionScopeRef) return () => h(Fragment, {}, slots) }, }) ``` -------------------------------------------------------------------------------- /packages/next/src/__builtins__/toArray.ts: -------------------------------------------------------------------------------- ```typescript import React from 'react' import { isFragment } from 'react-is' export interface toArrayOption { keepEmpty?: boolean } export function toArray( children: React.ReactNode, option: toArrayOption = {} ): React.ReactElement[] { let ret: React.ReactElement[] = [] React.Children.forEach(children, (child: any) => { if ((child === undefined || child === null) && !option.keepEmpty) { return } if (Array.isArray(child)) { ret = ret.concat(toArray(child)) } else if (isFragment(child) && child.props) { ret = ret.concat(toArray(child.props.children, option)) } else { ret.push(child) } }) return ret } ``` -------------------------------------------------------------------------------- /packages/antd/src/tree-select/index.tsx: -------------------------------------------------------------------------------- ```typescript import React from 'react' import { connect, mapReadPretty, mapProps } from '@formily/react' import { TreeSelect as AntdTreeSelect } from 'antd' import { PreviewText } from '../preview-text' import { LoadingOutlined } from '@ant-design/icons' export const TreeSelect = connect( AntdTreeSelect, mapProps( { dataSource: 'treeData', }, (props, field) => { return { ...props, suffixIcon: field?.['loading'] || field?.['validating'] ? ( <LoadingOutlined /> ) : ( props.suffixIcon ), } } ), mapReadPretty(PreviewText.TreeSelect) ) export default TreeSelect ``` -------------------------------------------------------------------------------- /packages/element/src/array-cards/style.scss: -------------------------------------------------------------------------------- ```scss @import '../__builtins__/styles/common.scss'; $array-table-prefix-cls: '#{$formily-prefix}-array-cards'; .#{$array-table-prefix-cls} { .el-card__header { padding-top: 12.5px; padding-bottom: 12.5px; } .el-empty { padding: 0; } .#{$array-table-prefix-cls}-item { margin-bottom: 10px; } .#{$formily-prefix}-array-base-addition { width: 100%; border: $--border-width-base dashed $--border-color-base; &:hover { background-color: $--color-white; border-color: $--border-color-hover; } &:active, &:focus { background-color: $--color-white; border-color: $--color-primary; } } } ``` -------------------------------------------------------------------------------- /packages/shared/src/string.ts: -------------------------------------------------------------------------------- ```typescript // ansiRegex const ansiRegex = () => { const pattern = [ '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[a-zA-Z\\d]*)*)?\\u0007)', '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PRZcf-ntqry=><~]))', ].join('|') return new RegExp(pattern, 'g') } // astralRegex const regex = '[\uD800-\uDBFF][\uDC00-\uDFFF]' const astralRegex = (opts?: { exact: boolean }) => opts && opts.exact ? new RegExp(`^${regex}$`) : new RegExp(regex, 'g') // stripAnsi const stripAnsi = (input: any) => typeof input === 'string' ? input.replace(ansiRegex(), '') : input export const stringLength = (input: string) => stripAnsi(input).replace(astralRegex(), ' ').length ``` -------------------------------------------------------------------------------- /packages/shared/src/deprecate.ts: -------------------------------------------------------------------------------- ```typescript import { isFn, isStr } from './checkers' const caches = {} export function deprecate<P1 = any, P2 = any, P3 = any, P4 = any, P5 = any>( method: any, message?: string, help?: string ) { if (isFn(method)) { // eslint-disable-next-line @typescript-eslint/no-unused-vars return function (p1?: P1, p2?: P2, p3?: P3, p4?: P4, p5?: P5) { deprecate(message, help) return method.apply(this, arguments) } } if (isStr(method) && !caches[method]) { caches[method] = true console.warn( new Error( `${method} has been deprecated. Do not continue to use this api.${ message || '' }` ) ) } } ``` -------------------------------------------------------------------------------- /packages/validator/src/__tests__/parser.spec.ts: -------------------------------------------------------------------------------- ```typescript import { parseValidatorDescriptions } from '../parser' describe('parseValidatorDescriptions', () => { test('basic', () => { expect(parseValidatorDescriptions('date')).toEqual([{ format: 'date' }]) const validator = () => { return '' } expect(parseValidatorDescriptions(validator)).toEqual([{ validator }]) expect(parseValidatorDescriptions(['date'])).toEqual([{ format: 'date' }]) expect(parseValidatorDescriptions([validator])).toEqual([{ validator }]) expect(parseValidatorDescriptions({ format: 'date' })).toEqual([ { format: 'date' }, ]) expect(parseValidatorDescriptions({ validator })).toEqual([{ validator }]) }) }) ``` -------------------------------------------------------------------------------- /packages/next/src/input/index.tsx: -------------------------------------------------------------------------------- ```typescript import { connect, mapReadPretty, mapProps } from '@formily/react' import { Input as NextInput } from '@alifd/next' import { InputProps, TextAreaProps } from '@alifd/next/lib/input' import { PreviewText } from '../preview-text' import { mapSize, mapStatus } from '../__builtins__' type ComposedInput = React.FC<React.PropsWithChildren<InputProps>> & { TextArea?: React.FC<React.PropsWithChildren<TextAreaProps>> } export const Input: ComposedInput = connect( NextInput, mapProps(mapSize, mapStatus), mapReadPretty(PreviewText.Input) ) Input.TextArea = connect( NextInput.TextArea, mapProps(mapSize, mapStatus), mapReadPretty(PreviewText.Input) ) export default Input ``` -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- ```markdown _Before_ submitting a pull request, please make sure the following is done... - [ ] Ensure the pull request title and commit message follow the [Commit Specific](https://formilyjs.org/guide/contribution#pr-specification) in **English**. - [ ] Fork the repo and create your branch from `master` or `formily_next`. - [ ] If you've added code that should be tested, add tests! - [ ] If you've changed APIs, update the documentation. - [ ] Ensure the test suite passes (`npm test`). - [ ] Make sure your code lints (`npm run lint`) - we've done our best to make sure these rules match our internal linting guidelines. **Please do not delete the above content** --- ## What have you changed? ``` -------------------------------------------------------------------------------- /packages/path/benchmark.ts: -------------------------------------------------------------------------------- ```typescript import b from 'benny' import _ from 'lodash' import { Parser } from './src/parser' const str = 'aakkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk.bbmmmmmmmmmmmmmmmmmmmmmmmmmmm.cceeeeeeeeeeeeeeeeeee' b.suite( 'Path benchmark', b.add('Path parse', () => { _.times(1e3, () => { new Parser(str).parse() }) }), b.add('Normal foreach', () => { _.times(1e3, () => { if (!/[()*\[\]]/.test(str)) { str.replace(/\s+/g, '').split('.') } }) }), b.add('charCodeAt foreach', () => { _.times(1e3, () => { const res = [] for (let i = 0; i < str.length; i++) { res.push(str.charCodeAt(i)) } }) }), b.cycle(), b.complete() ) ``` -------------------------------------------------------------------------------- /devtools/chrome-extension/src/extension/inject.ts: -------------------------------------------------------------------------------- ```typescript import backend from 'raw-loader!./backend' function nullthrows(x: any, message?: string) { if (x != null) { return x } const error: any = new Error( message !== undefined ? message : 'Got unexpected ' + x ) error.framesToPop = 1 // Skip nullthrows's own stack frame. throw error } function injectCode(code) { const script = document.createElement('script') script.textContent = code // This script runs before the <head> element is created, // so we add the script to <html> instead. nullthrows(document.documentElement).appendChild(script) nullthrows(script.parentNode).removeChild(script) } injectCode(`;(function(){ var exports = {}; ${backend} })()`) ``` -------------------------------------------------------------------------------- /packages/vue/docs/demos/questions/default-slot.vue: -------------------------------------------------------------------------------- ```vue <template> <FormProvider :form="form"> <SchemaField :schema="schema" /> </FormProvider> </template> <script> import { Button } from 'ant-design-vue' import { createForm } from '@formily/core' import { FormProvider, createSchemaField } from '@formily/vue' import 'ant-design-vue/dist/antd.css' const { SchemaField } = createSchemaField({ components: { Button, }, }) const schema = { type: 'object', properties: { button: { type: 'void', 'x-component': 'Button', 'x-content': '一个普通的按钮', }, }, } export default { components: { FormProvider, SchemaField }, data() { return { form: createForm(), schema, } }, } </script> ``` -------------------------------------------------------------------------------- /packages/reactive/docs/guide/best-practice.md: -------------------------------------------------------------------------------- ```markdown # Best Practices When using @formily/reactive, we only need to pay attention to the following points: - Minimize the use of observable/observable.deep for deep packaging, instead of using observable.ref/observable.shallow as a last resort, the performance will be better - Multi-use computed properties in the domain model, which can intelligently cache the calculation results - Although batch operation is not necessary, use batch mode as much as possible to reduce the number of executions of Reaction - When using autorun/reaction, you must remember to call the dispose release function (that is, the second-order function returned by the calling function), otherwise there will be memory leaks ``` -------------------------------------------------------------------------------- /packages/vue/docs/demos/api/components/schema-field-with-schema.vue: -------------------------------------------------------------------------------- ```vue <template> <FormProvider :form="form"> <SchemaField :schema="{ type: 'object', properties: { input: { type: 'string', 'x-component': 'Input', }, }, }" > </SchemaField> </FormProvider> </template> <script> import { Input } from 'ant-design-vue' import { createForm } from '@formily/core' import { FormProvider, createSchemaField } from '@formily/vue' import 'ant-design-vue/dist/antd.css' const { SchemaField } = createSchemaField({ components: { Input, }, }) export default { components: { FormProvider, SchemaField }, data() { return { form: createForm(), } }, } </script> ``` -------------------------------------------------------------------------------- /packages/antd/src/transfer/index.tsx: -------------------------------------------------------------------------------- ```typescript import { connect, mapProps } from '@formily/react' import { Transfer as AntdTransfer } from 'antd' import { isVoidField } from '@formily/core' const renderTitle = (item: any) => item.title export const Transfer = connect( AntdTransfer, mapProps( { value: 'targetKeys', }, (props, field) => { if (isVoidField(field)) return props return { ...props, render: props.render || renderTitle, dataSource: field.dataSource?.map((item) => { return { ...item, title: item.title || item.label, key: item.key || item.value, } }) || [], } } ) ) export default Transfer ``` -------------------------------------------------------------------------------- /packages/vue/scripts/switch-cli.js: -------------------------------------------------------------------------------- ```javascript const { switchVersion } = require('./utils.js') const { exec } = require('child_process') const version = process.argv[2] const vueEntry = process.argv[3] || 'vue' if (version == '2') { switchVersion(2) console.log(`[formily-vue] Switched types for Vue 2`) exec(`npx vue-demi-switch 2 ${vueEntry}`) console.log(`[vue-demi] Switched for Vue 2 (entry: "${vueEntry}")`) } else if (version == '3') { switchVersion(3) console.log(`[formily-vue] Switched types for Vue 3`) exec(`npx vue-demi-switch 3 ${vueEntry}`) console.log(`[vue-demi] Switched for Vue 3 (entry: "${vueEntry}")`) } else { console.warn( `[formily-vue] expecting version "2" or "3" but got "${version}"` ) process.exit(1) } ``` -------------------------------------------------------------------------------- /packages/react/src/__tests__/shared.tsx: -------------------------------------------------------------------------------- ```typescript import React, { Component, Fragment } from 'react' import { render } from '@testing-library/react' export class ErrorBoundary extends Component { state = { error: null, } componentDidCatch(error: Error) { this.setState({ error, }) } render() { if (this.state.error) { return ( <div data-testid="error-boundary-message"> {this.state.error.message} </div> ) } return <Fragment>{this.props.children}</Fragment> } } export const expectThrowError = (callback: () => React.ReactElement) => { const { queryByTestId } = render(<ErrorBoundary>{callback()}</ErrorBoundary>) expect(queryByTestId('error-boundary-message')).toBeVisible() } ``` -------------------------------------------------------------------------------- /packages/reactive/benchmark.ts: -------------------------------------------------------------------------------- ```typescript import b from 'benny' import _ from 'lodash' import * as mobx from 'mobx' import * as vueReactivity from '@vue/reactivity' import * as formilyReactive from './src' function func(obs, times) { obs.arr = [] obs.obj = {} _.times(times, (v) => { obs.num = v obs.str = `${v}` obs.arr.push(v) obs.obj[`${v}`] = v }) } b.suite( 'Reactive Observable', b.add('Case MobX', () => { const obs = mobx.observable({}) func(obs, 1e3) }), b.add('Case @vue/reactivity', () => { const obs = vueReactivity.reactive({}) func(obs, 1e3) }), b.add('Case @formily/reactive', () => { const obs = formilyReactive.observable({}) func(obs, 1e3) }), b.cycle(), b.complete() ) ``` -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- ```yaml # These are supported funding model platforms github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] patreon: # Replace with a single Patreon username open_collective: formily # Replace with a single Open Collective username ko_fi: # Replace with a single Ko-fi username tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry liberapay: # Replace with a single Liberapay username issuehunt: # Replace with a single IssueHunt username otechie: # Replace with a single Otechie username custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] ``` -------------------------------------------------------------------------------- /packages/next/src/radio/index.tsx: -------------------------------------------------------------------------------- ```typescript import { connect, mapProps, mapReadPretty } from '@formily/react' import { Radio as NextRadio } from '@alifd/next' import { RadioProps, GroupProps as RadioGroupProps, } from '@alifd/next/lib/radio' import { PreviewText } from '../preview-text' import { mapSize } from '../__builtins__' type ComposedRadio = React.FC<React.PropsWithChildren<RadioProps>> & { Group?: React.FC<React.PropsWithChildren<RadioGroupProps>> } export const Radio: ComposedRadio = connect( NextRadio, mapProps( { value: 'checked', }, mapSize ) ) Radio.Group = connect( NextRadio.Group, mapProps( { dataSource: true, }, mapSize ), mapReadPretty(PreviewText.Select) ) export default Radio ``` -------------------------------------------------------------------------------- /docs/functions/contributors.ts: -------------------------------------------------------------------------------- ```typescript import { Handler } from '@netlify/functions' import { Octokit } from '@octokit/rest' const octokit = new Octokit({ baseUrl: 'https://api.github.com', auth: process.env.GITHUB_TOKEN, }) const headers = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': 'Content-Type', 'Access-Control-Allow-Methods': 'GET', } export const handler: Handler = async (event) => { if (event.httpMethod !== 'GET') { return { statusCode: 405, body: 'Method Not Allowed' } } return { statusCode: 200, headers, body: JSON.stringify( await octokit.repos.listContributors({ owner: 'alibaba', repo: 'formily', per_page: 1000, page: 1, }) ), } } ``` -------------------------------------------------------------------------------- /packages/react/src/components/VoidField.tsx: -------------------------------------------------------------------------------- ```typescript import React from 'react' import { useForm, useField } from '../hooks' import { useAttach } from '../hooks/useAttach' import { ReactiveField } from './ReactiveField' import { FieldContext } from '../shared' import { JSXComponent, IVoidFieldProps } from '../types' export const VoidField = <D extends JSXComponent, C extends JSXComponent>( props: IVoidFieldProps<D, C> ) => { const form = useForm() const parent = useField() const field = useAttach( form.createVoidField({ basePath: parent?.address, ...props }) ) return ( <FieldContext.Provider value={field}> <ReactiveField field={field}>{props.children}</ReactiveField> </FieldContext.Provider> ) } VoidField.displayName = 'VoidField' ``` -------------------------------------------------------------------------------- /devtools/chrome-extension/src/app/components/RightPanel.tsx: -------------------------------------------------------------------------------- ```typescript import React from 'react' import styled from 'styled-components' import ReactJson from 'react-json-view' export const RightPanel = styled(({ className, dataSource }) => { return ( <div className={className}> <ReactJson src={dataSource} name={dataSource && dataSource.displayName} theme="hopscotch" displayDataTypes={false} enableClipboard={false} sortKeys={true} onEdit={false} onAdd={false} onDelete={false} iconStyle="square" /> </div> ) })` border-left: 1px solid #3d424a; flex-grow: 2; overflow: auto; padding: 10px; .react-json-view { background: none !important; font-size: 12px !important; } ` ``` -------------------------------------------------------------------------------- /packages/antd/src/checkbox/index.tsx: -------------------------------------------------------------------------------- ```typescript import { connect, mapProps, mapReadPretty } from '@formily/react' import { Checkbox as AntdCheckbox } from 'antd' import { CheckboxProps, CheckboxGroupProps } from 'antd/lib/checkbox' import { PreviewText } from '../preview-text' type ComposedCheckbox = React.FC<React.PropsWithChildren<CheckboxProps>> & { Group?: React.FC<React.PropsWithChildren<CheckboxGroupProps>> __ANT_CHECKBOX?: boolean } export const Checkbox: ComposedCheckbox = connect( AntdCheckbox, mapProps({ value: 'checked', }) ) Checkbox.__ANT_CHECKBOX = true Checkbox.Group = connect( AntdCheckbox.Group, mapProps({ dataSource: 'options', }), mapReadPretty(PreviewText.Select, { mode: 'tags', }) ) export default Checkbox ``` -------------------------------------------------------------------------------- /packages/vue/src/shared/context.ts: -------------------------------------------------------------------------------- ```typescript import { InjectionKey, Ref } from 'vue-demi' import { Form, GeneralField } from '@formily/core' import { Schema } from '@formily/json-schema' import { ISchemaFieldVueFactoryOptions } from '../types' export const FormSymbol: InjectionKey<Ref<Form>> = Symbol('form') export const FieldSymbol: InjectionKey<Ref<GeneralField>> = Symbol('field') export const SchemaMarkupSymbol: InjectionKey<Ref<Schema>> = Symbol('schemaMarkup') export const SchemaSymbol: InjectionKey<Ref<Schema>> = Symbol('schema') export const SchemaExpressionScopeSymbol: InjectionKey< Ref<Record<string, any>> > = Symbol('schemaExpression') export const SchemaOptionsSymbol: InjectionKey< Ref<ISchemaFieldVueFactoryOptions> > = Symbol('schemaOptions') ``` -------------------------------------------------------------------------------- /packages/reactive/docs/api/batch.md: -------------------------------------------------------------------------------- ```markdown # batch ## Description Define batch operations, internal dependencies can be collected ## Signature ```ts interface batch { <T>(callback?: () => T): T //In-place batch scope<T>(callback?: () => T): T //In-situ local batch bound<T extends (...args: any[]) => any>(callback: T, context?: any): T //High-level binding endpoint(callback?: () => void): void //Register batch endpoint callback } ``` ## Example ```ts import { observable, autorun, batch } from '@formily/reactive' const obs = observable({}) autorun(() => { console.log(obs.aa, obs.bb, obs.cc, obs.dd) }) batch(() => { batch.scope(() => { obs.aa = 123 }) batch.scope(() => { obs.cc = 'ccccc' }) obs.bb = 321 obs.dd = 'dddd' }) ``` ``` -------------------------------------------------------------------------------- /packages/reactive/docs/api/tracker.md: -------------------------------------------------------------------------------- ```markdown # tracker ## Description Mainly used to access the manual tracking dependency tool of React/Vue. The tracker function will not be executed repeatedly when the dependency changes. It requires the user to manually execute it repeatedly, which will only trigger the scheduler ## Signature ```ts class Tracker { constructor(scheduler?: (reaction: this['track']) => void, name?: string) track: <T>(tracker?: () => T) => T dispose: () => void } ``` ## Example ```ts import { observable, Tracker } from '@formily/reactive' const obs = observable({ aa: 11, }) const view = () => { console.log(obs.aa) } const tracker = new Tracker(() => { tracker.track(view) }) tracker.track(view) obs.aa = 22 tracker.dispose() ``` ``` -------------------------------------------------------------------------------- /packages/react/docs/api/components/FormProvider.md: -------------------------------------------------------------------------------- ```markdown --- order: 6 --- # FormProvider ## Description The entry component is used to place the order context to the field component and is responsible for the communication of the entire form state. It is equivalent to a communication hub. ## Signature ```ts type FormProvider = React.FC<{ form: Form // form instance created by createForm }> ``` Form reference [Form](https://core.formilyjs.org/api/models/form) ## Example ```tsx import React from 'react' import { createForm } from '@formily/core' import { FormProvider, Field } from '@formily/react' import { Input } from 'antd' const form = createForm() export default () => ( <FormProvider form={form}> <Field name="input" component={[Input]} /> </FormProvider> ) ``` ``` -------------------------------------------------------------------------------- /packages/antd/src/select/index.tsx: -------------------------------------------------------------------------------- ```typescript import React from 'react' import { connect, mapReadPretty, mapProps, ReactFC } from '@formily/react' import { Select as AntdSelect } from 'antd' import { SelectProps } from 'antd/lib/select' import { PreviewText } from '../preview-text' import { LoadingOutlined } from '@ant-design/icons' export const Select: ReactFC<SelectProps<any, any>> = connect( AntdSelect, mapProps( { dataSource: 'options', loading: true, }, (props, field) => { return { ...props, suffixIcon: field?.['loading'] || field?.['validating'] ? ( <LoadingOutlined /> ) : ( props.suffixIcon ), } } ), mapReadPretty(PreviewText.Select) ) export default Select ``` -------------------------------------------------------------------------------- /packages/element/docs/demos/guide/input-number/template.vue: -------------------------------------------------------------------------------- ```vue <template> <FormProvider :form="form"> <Field name="input" title="输入框" :decorator="[FormItem]" :component="[ InputNumber, { style: { width: '240px', }, }, ]" /> <Submit @submit="log">提交</Submit> </FormProvider> </template> <script> import { createForm } from '@formily/core' import { FormProvider, Field } from '@formily/vue' import { FormItem, InputNumber, Submit } from '@formily/element' const form = createForm() export default { components: { FormProvider, Field, Submit }, data() { return { FormItem, InputNumber, form, } }, methods: { log(value) { console.log(value) }, }, } </script> ``` -------------------------------------------------------------------------------- /packages/react/src/components/Field.tsx: -------------------------------------------------------------------------------- ```typescript import React, { useEffect } from 'react' import { useField, useForm } from '../hooks' import { ReactiveField } from './ReactiveField' import { FieldContext } from '../shared' import { JSXComponent, IFieldProps } from '../types' export const Field = <D extends JSXComponent, C extends JSXComponent>( props: IFieldProps<D, C> ) => { const form = useForm() const parent = useField() const field = form.createField({ basePath: parent?.address, ...props }) useEffect(() => { field?.onMount() return () => { field?.onUnmount() } }, [field]) return ( <FieldContext.Provider value={field}> <ReactiveField field={field}>{props.children}</ReactiveField> </FieldContext.Provider> ) } Field.displayName = 'Field' ``` -------------------------------------------------------------------------------- /packages/element/docs/demos/guide/input/template.vue: -------------------------------------------------------------------------------- ```vue <template> <FormProvider :form="form"> <Field name="input" title="输入框" :decorator="[FormItem]" :component="[Input]" /> <Field name="textarea" title="文本框" :decorator="[FormItem]" :component="[Input.TextArea]" /> <Submit @submit="log">提交</Submit> </FormProvider> </template> <script> import { createForm } from '@formily/core' import { FormProvider, Field } from '@formily/vue' import { FormItem, Input, Submit } from '@formily/element' const form = createForm() export default { components: { FormProvider, Field, Submit }, data() { return { FormItem, Input, form, } }, methods: { log(value) { console.log(value) }, }, } </script> ``` -------------------------------------------------------------------------------- /packages/element/docs/demos/guide/form-item/markup-schema.vue: -------------------------------------------------------------------------------- ```vue <template> <Form :form="form"> <SchemaField> <SchemaStringField name="input" title="输入框" x-decorator="FormItem" x-component="Input" required /> </SchemaField> <Submit @submit="onSubmit">提交</Submit> </Form> </template> <script> import { createForm } from '@formily/core' import { createSchemaField } from '@formily/vue' import { Form, FormItem, Input, Submit } from '@formily/element' const form = createForm() const fields = createSchemaField({ components: { FormItem, Input, }, }) export default { components: { Form, ...fields, Submit }, data() { return { form, } }, methods: { onSubmit(value) { console.log(value) }, }, } </script> ``` -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- ```javascript module.exports = { collectCoverage: true, verbose: true, testEnvironment: 'jsdom', preset: 'ts-jest', testMatch: ['**/__tests__/**/*.spec.[jt]s?(x)'], setupFilesAfterEnv: [ require.resolve('jest-dom/extend-expect'), './global.config.ts', ], // moduleNameMapper: process.env.TEST_ENV === 'production' ? undefined : alias, globals: { 'ts-jest': { babelConfig: false, tsconfig: './tsconfig.jest.json', diagnostics: false, }, }, coveragePathIgnorePatterns: [ '/node_modules/', '/__tests__/', '/esm/', '/lib/', 'package.json', '/demo/', '/packages/builder/src/__tests__/', '/packages/builder/src/components/', '/packages/builder/src/configs/', 'package-lock.json', ], } ``` -------------------------------------------------------------------------------- /packages/element/docs/demos/guide/switch/markup-schema.vue: -------------------------------------------------------------------------------- ```vue <template> <FormProvider :form="form"> <SchemaField> <SchemaBooleanField name="switch" title="开关" x-decorator="FormItem" x-component="Switch" /> </SchemaField> <Submit @submit="log">提交</Submit> </FormProvider> </template> <script> import { createForm } from '@formily/core' import { createSchemaField, FormProvider } from '@formily/vue' import { FormItem, Switch, Submit } from '@formily/element' const form = createForm() const fields = createSchemaField({ components: { FormItem, Switch, }, }) export default { components: { FormProvider, ...fields, Submit }, data() { return { form, } }, methods: { log(value) { console.log(value) }, }, } </script> ``` -------------------------------------------------------------------------------- /packages/element/src/array-collapse/style.scss: -------------------------------------------------------------------------------- ```scss @import '../__builtins__/styles/common.scss'; $array-table-prefix-cls: '#{$formily-prefix}-array-collapse'; .#{$array-table-prefix-cls} { .el-card__header { padding-top: 12.5px; padding-bottom: 12.5px; } .el-empty { padding: 0; } .#{$array-table-prefix-cls}-item { margin-bottom: 10px; } .#{$array-table-prefix-cls}-errors-badge { line-height: 1; vertical-align: initial; } .#{$formily-prefix}-array-base-addition { width: 100%; border: $--border-width-base dashed $--border-color-base; &:hover { background-color: $--color-white; border-color: $--border-color-hover; } &:active, &:focus { background-color: $--color-white; border-color: $--color-primary; } } } ``` -------------------------------------------------------------------------------- /packages/element/docs/demos/guide/password/markup-schema.vue: -------------------------------------------------------------------------------- ```vue <template> <FormProvider :form="form"> <SchemaField> <SchemaStringField name="input" title="密码框" x-decorator="FormItem" x-component="Password" /> </SchemaField> <Submit @submit="log">提交</Submit> </FormProvider> </template> <script> import { createForm } from '@formily/core' import { createSchemaField, FormProvider } from '@formily/vue' import { FormItem, Password, Submit } from '@formily/element' const form = createForm() const fields = createSchemaField({ components: { FormItem, Password, }, }) export default { components: { FormProvider, ...fields, Submit }, data() { return { form, } }, methods: { log(value) { console.log(value) }, }, } </script> ``` -------------------------------------------------------------------------------- /packages/next/src/select-table/useSize.tsx: -------------------------------------------------------------------------------- ```typescript interface ISize { ( fieldSize: 'large' | 'default' | 'small', searchSize: 'large' | 'medium', tableSize: 'small' | 'medium' ): { searchSize: 'large' | 'medium' tableSize: 'small' | 'medium' } } const useSize: ISize = (fieldSize = 'default', searchSize, tableSize) => { const fieldSizeMap: any = { small: { searchSize: 'medium', tableSize: 'small', }, default: { searchSize: 'medium', tableSize: 'medium', }, large: { searchSize: 'large', tableSize: 'medium', }, } const { searchSize: fieldSearchSize, tableSize: fieldTableSize } = fieldSizeMap[fieldSize] return { searchSize: searchSize || fieldSearchSize, tableSize: tableSize || fieldTableSize, } } export { useSize } ``` -------------------------------------------------------------------------------- /packages/vue/docs/demos/questions/events.vue: -------------------------------------------------------------------------------- ```vue <template> <FormProvider :form="form"> <SchemaField :schema="schema" /> </FormProvider> </template> <script> import { Input } from 'ant-design-vue' import { createForm } from '@formily/core' import { FormProvider, createSchemaField } from '@formily/vue' import 'ant-design-vue/dist/antd.css' const { SchemaField } = createSchemaField({ components: { Input, }, }) const schema = { type: 'object', properties: { input: { type: 'string', 'x-component': 'Input', 'x-component-props': { '@change': (e) => console.log(e), onFocus: (e) => console.log(e), }, }, }, } export default { components: { FormProvider, SchemaField }, data() { return { form: createForm(), schema, } }, } </script> ```