├── .codecov.yml ├── .dumi ├── app.tsx └── tsconfig.json ├── .dumirc.ts ├── .eslintignore ├── .eslintrc.js ├── .fatherrc.base.ts ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ └── question.md ├── dependabot.yml └── workflows │ ├── build.yml │ ├── codeql.yml │ ├── coverage.yml │ ├── issue-labeled.yml │ ├── issue-open-check.yml │ ├── pkg.pr.new.yml │ └── rebase.yml ├── .gitignore ├── .npmrc ├── .prettierignore ├── .prettierrc.js ├── CONTRIBUTING.md ├── LICENSE.md ├── README.es-PR.md ├── README.md ├── README.zh-CN.md ├── docs ├── changelog.en-US.md ├── changelog.md ├── components.en-US.md ├── components.md ├── components │ ├── customization-value-type.tsx │ ├── schema.$tab-api.md │ ├── schema.en-US.md │ ├── schema.md │ ├── valueEnum-map.tsx │ └── valueType.tsx ├── docs │ ├── faq.en-US.md │ ├── faq.md │ ├── index.en-US.md │ ├── index.md │ ├── intro.en-US.md │ └── intro.md ├── index.en-US.md ├── index.md └── playground │ ├── index.en-US.md │ ├── index.md │ ├── pro-descriptions.en-US.md │ ├── pro-descriptions.md │ ├── pro-form.en-US.md │ ├── pro-form.md │ ├── pro-layout.en-US.md │ ├── pro-layout.md │ ├── pro-table.en-US.md │ └── pro-table.md ├── lerna.json ├── package.json ├── packages ├── card │ ├── .fatherrc.ts │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── ProCard.tsx │ │ ├── components │ │ │ ├── Actions │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── Card │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── CheckCard │ │ │ │ ├── Group.tsx │ │ │ │ ├── demos │ │ │ │ │ ├── avatar.tsx │ │ │ │ │ ├── basic.tsx │ │ │ │ │ ├── compose.tsx │ │ │ │ │ ├── custom.tsx │ │ │ │ │ ├── defaultChecked.tsx │ │ │ │ │ ├── description.tsx │ │ │ │ │ ├── disabled.tsx │ │ │ │ │ ├── extra.tsx │ │ │ │ │ ├── form.tsx │ │ │ │ │ ├── grid.tsx │ │ │ │ │ ├── group.tsx │ │ │ │ │ ├── image.tsx │ │ │ │ │ ├── list.tsx │ │ │ │ │ ├── loading.tsx │ │ │ │ │ ├── multiple.tsx │ │ │ │ │ ├── single.tsx │ │ │ │ │ ├── size.tsx │ │ │ │ │ └── title.tsx │ │ │ │ ├── index.en-US.md │ │ │ │ ├── index.md │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── Divider │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── Loading │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── Operation │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── Statistic │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── StatisticCard │ │ │ │ ├── demos │ │ │ │ │ ├── basic.tsx │ │ │ │ │ ├── chart.tsx │ │ │ │ │ ├── fomula.tsx │ │ │ │ │ ├── footer.tsx │ │ │ │ │ ├── group-chart.tsx │ │ │ │ │ ├── group.tsx │ │ │ │ │ ├── horizontal-left.tsx │ │ │ │ │ ├── horizontal.tsx │ │ │ │ │ ├── icon.tsx │ │ │ │ │ ├── layout.tsx │ │ │ │ │ ├── status.tsx │ │ │ │ │ ├── tabs-statistic.tsx │ │ │ │ │ ├── tabs.tsx │ │ │ │ │ ├── total-layout.tsx │ │ │ │ │ ├── total.tsx │ │ │ │ │ └── trend.tsx │ │ │ │ ├── index.en-US.md │ │ │ │ ├── index.md │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── TabPane │ │ │ │ └── index.tsx │ │ │ ├── card.en-US.md │ │ │ └── card.md │ │ ├── demos │ │ │ ├── actions.tsx │ │ │ ├── basic.tsx │ │ │ ├── bordered.tsx │ │ │ ├── collapsible.tsx │ │ │ ├── colspan.tsx │ │ │ ├── divider.tsx │ │ │ ├── group.tsx │ │ │ ├── gutter.tsx │ │ │ ├── headerBordered.tsx │ │ │ ├── headless.tsx │ │ │ ├── hoverable.tsx │ │ │ ├── inner.tsx │ │ │ ├── layout.tsx │ │ │ ├── loading.tsx │ │ │ ├── multipleLine.tsx │ │ │ ├── responsive.tsx │ │ │ ├── split.tsx │ │ │ ├── split2.tsx │ │ │ ├── split23.tsx │ │ │ ├── steps-v.tsx │ │ │ ├── tabs-card.tsx │ │ │ └── tabs.tsx │ │ ├── index.tsx │ │ └── typing.ts │ └── tsconfig.json ├── components │ ├── .fatherrc.ts │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ └── index.tsx │ └── tsconfig.json ├── descriptions │ ├── .fatherrc.ts │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── components │ │ │ ├── descriptions.en-US.md │ │ │ └── descriptions.md │ │ ├── demos │ │ │ ├── arrayDataIndex.tsx │ │ │ ├── base.demo-test.tsx │ │ │ ├── base.tsx │ │ │ ├── columns.tsx │ │ │ ├── customization-value-type.tsx │ │ │ ├── dynamic-descriptions.tsx │ │ │ ├── editable.tsx │ │ │ ├── format.tsx │ │ │ ├── request.tsx │ │ │ └── use-data-source.tsx │ │ ├── index.tsx │ │ └── useFetchData.tsx │ └── tsconfig.json ├── field │ ├── .fatherrc.ts │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── FieldHOC │ │ │ └── index.tsx │ │ ├── components │ │ │ ├── Cascader │ │ │ │ └── index.tsx │ │ │ ├── Checkbox │ │ │ │ └── index.tsx │ │ │ ├── Code │ │ │ │ └── index.tsx │ │ │ ├── ColorPicker │ │ │ │ ├── index.tsx │ │ │ │ └── old.tsx │ │ │ ├── DatePicker │ │ │ │ └── index.tsx │ │ │ ├── Digit │ │ │ │ └── index.tsx │ │ │ ├── DigitRange │ │ │ │ └── index.tsx │ │ │ ├── FromNow │ │ │ │ └── index.tsx │ │ │ ├── Image │ │ │ │ └── index.tsx │ │ │ ├── IndexColumn │ │ │ │ └── index.tsx │ │ │ ├── Money │ │ │ │ └── index.tsx │ │ │ ├── Options │ │ │ │ └── index.tsx │ │ │ ├── Password │ │ │ │ └── index.tsx │ │ │ ├── Percent │ │ │ │ ├── index.tsx │ │ │ │ └── util.ts │ │ │ ├── Progress │ │ │ │ └── index.tsx │ │ │ ├── Radio │ │ │ │ └── index.tsx │ │ │ ├── RangePicker │ │ │ │ └── index.tsx │ │ │ ├── Rate │ │ │ │ └── index.tsx │ │ │ ├── Second │ │ │ │ └── index.tsx │ │ │ ├── Segmented │ │ │ │ └── index.tsx │ │ │ ├── Select │ │ │ │ ├── LightSelect │ │ │ │ │ └── index.tsx │ │ │ │ ├── SearchSelect │ │ │ │ │ └── index.tsx │ │ │ │ └── index.tsx │ │ │ ├── Slider │ │ │ │ └── index.tsx │ │ │ ├── Status │ │ │ │ └── index.tsx │ │ │ ├── Switch │ │ │ │ └── index.tsx │ │ │ ├── Text │ │ │ │ └── index.tsx │ │ │ ├── TextArea │ │ │ │ ├── index.tsx │ │ │ │ └── readonly.tsx │ │ │ ├── TimePicker │ │ │ │ └── index.tsx │ │ │ ├── TreeSelect │ │ │ │ └── index.tsx │ │ │ ├── field.en-US.md │ │ │ └── field.md │ │ ├── demos │ │ │ ├── base.tsx │ │ │ ├── base_test.tsx │ │ │ ├── search-value-autoClearSearchValue.tsx │ │ │ ├── search-value.tsx │ │ │ ├── select-request.tsx │ │ │ └── tree-select-search-value.tsx │ │ └── index.tsx │ └── tsconfig.json ├── form │ ├── .fatherrc.ts │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── BaseForm │ │ │ ├── BaseForm.tsx │ │ │ ├── EditOrReadOnlyContext.ts │ │ │ ├── LightWrapper │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── createField.tsx │ │ │ └── index.ts │ │ ├── FieldContext.tsx │ │ ├── components │ │ │ ├── Captcha │ │ │ │ └── index.tsx │ │ │ ├── Cascader │ │ │ │ └── index.tsx │ │ │ ├── Checkbox │ │ │ │ └── index.tsx │ │ │ ├── ColorPicker │ │ │ │ └── index.tsx │ │ │ ├── DateMonthRangePicker │ │ │ │ └── index.tsx │ │ │ ├── DatePicker │ │ │ │ ├── DatePicker.tsx │ │ │ │ ├── MonthPicker.tsx │ │ │ │ ├── QuarterPicker.tsx │ │ │ │ ├── WeekPicker.tsx │ │ │ │ ├── YearPicker.tsx │ │ │ │ └── index.tsx │ │ │ ├── DateQuarterRangePicker │ │ │ │ └── index.tsx │ │ │ ├── DateRangePicker │ │ │ │ └── index.tsx │ │ │ ├── DateTimePicker │ │ │ │ └── index.tsx │ │ │ ├── DateTimeRangePicker │ │ │ │ └── index.tsx │ │ │ ├── DateWeekRangePicker │ │ │ │ └── index.tsx │ │ │ ├── DateYearRangePicker │ │ │ │ └── index.tsx │ │ │ ├── Dependency │ │ │ │ ├── demos │ │ │ │ │ ├── dependency.tsx │ │ │ │ │ └── dependency2.tsx │ │ │ │ ├── index.en-US.md │ │ │ │ ├── index.md │ │ │ │ └── index.tsx │ │ │ ├── Digit │ │ │ │ └── index.tsx │ │ │ ├── DigitRange │ │ │ │ └── index.tsx │ │ │ ├── Field │ │ │ │ └── index.tsx │ │ │ ├── FieldSet │ │ │ │ ├── demos │ │ │ │ │ ├── captCha.tsx │ │ │ │ │ ├── components-other-readonly.tsx │ │ │ │ │ ├── components-other.tsx │ │ │ │ │ ├── datatime.tsx │ │ │ │ │ ├── fieldSet-light.tsx │ │ │ │ │ ├── form-fieldset.tsx │ │ │ │ │ ├── pro-form-captCha.tsx │ │ │ │ │ ├── search-select.tsx │ │ │ │ │ └── upload.tsx │ │ │ │ ├── index.en-US.md │ │ │ │ ├── index.md │ │ │ │ └── index.tsx │ │ │ ├── FormItem │ │ │ │ └── index.tsx │ │ │ ├── FormItemRender │ │ │ │ └── index.tsx │ │ │ ├── Group │ │ │ │ ├── demos │ │ │ │ │ ├── base-use.tsx │ │ │ │ │ ├── countLimit.tsx │ │ │ │ │ ├── customize.tsx │ │ │ │ │ ├── dependency.tsx │ │ │ │ │ ├── horizontal-layout.tsx │ │ │ │ │ ├── list-tooltip.tsx │ │ │ │ │ ├── list.tsx │ │ │ │ │ ├── nested-list.tsx │ │ │ │ │ └── pro-form-list.tsx │ │ │ │ ├── index.en-US.md │ │ │ │ ├── index.md │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── List │ │ │ │ ├── ListContainer.tsx │ │ │ │ ├── ListItem.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── LoginForm │ │ │ │ ├── demos │ │ │ │ │ ├── login-form-page.tsx │ │ │ │ │ └── login-form.tsx │ │ │ │ ├── index.en-US.md │ │ │ │ └── index.md │ │ │ ├── ModalForm │ │ │ │ ├── demos │ │ │ │ │ ├── drawer-form-nested.tsx │ │ │ │ │ ├── drawer-form.tsx │ │ │ │ │ ├── modal-form-reset.tsx │ │ │ │ │ ├── modal-form-submitter.tsx │ │ │ │ │ ├── modal-form.tsx │ │ │ │ │ └── visible-on-visible-change.tsx │ │ │ │ ├── index.en-US.md │ │ │ │ └── index.md │ │ │ ├── Money │ │ │ │ └── index.tsx │ │ │ ├── QueryFilter │ │ │ │ ├── demos │ │ │ │ │ ├── light-filter-bordered.tsx │ │ │ │ │ ├── light-filter-collapse.tsx │ │ │ │ │ ├── light-filter-footer.tsx │ │ │ │ │ ├── light-filter-placement.tsx │ │ │ │ │ ├── light-filter-test.tsx │ │ │ │ │ ├── light-filter.tsx │ │ │ │ │ ├── query-filter-collapsed.tsx │ │ │ │ │ ├── query-filter-defaultColsNumber.tsx │ │ │ │ │ ├── query-filter-defaultFormItemsNumber.tsx │ │ │ │ │ ├── query-filter-test.tsx │ │ │ │ │ ├── query-filter-vertical.tsx │ │ │ │ │ ├── query-filter.tsx │ │ │ │ │ └── search-filter.tsx │ │ │ │ ├── index.en-US.md │ │ │ │ └── index.md │ │ │ ├── Radio │ │ │ │ └── index.tsx │ │ │ ├── Rate │ │ │ │ └── index.tsx │ │ │ ├── SchemaForm │ │ │ │ ├── demos │ │ │ │ │ ├── ModalAndDrawerForm.tsx │ │ │ │ │ ├── customization-value-type.tsx │ │ │ │ │ ├── dependencies.tsx │ │ │ │ │ ├── dependency.tsx │ │ │ │ │ ├── dynamic-rerender.tsx │ │ │ │ │ ├── embed.tsx │ │ │ │ │ ├── form-list-required.tsx │ │ │ │ │ ├── schema.tsx │ │ │ │ │ ├── steps-form.tsx │ │ │ │ │ └── valueType.tsx │ │ │ │ ├── index.en-US.md │ │ │ │ ├── index.md │ │ │ │ ├── index.tsx │ │ │ │ ├── layoutType │ │ │ │ │ ├── Embed.tsx │ │ │ │ │ ├── StepsForm.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── typing.ts │ │ │ │ └── valueType │ │ │ │ │ ├── dependency.tsx │ │ │ │ │ ├── divider.tsx │ │ │ │ │ ├── field.tsx │ │ │ │ │ ├── formList.tsx │ │ │ │ │ ├── formSet.tsx │ │ │ │ │ ├── group.tsx │ │ │ │ │ ├── ignore.tsx │ │ │ │ │ └── index.tsx │ │ │ ├── Segmented │ │ │ │ └── index.tsx │ │ │ ├── Select │ │ │ │ └── index.tsx │ │ │ ├── Slider │ │ │ │ └── index.tsx │ │ │ ├── StepsForm │ │ │ │ ├── demos │ │ │ │ │ ├── add-or-edit-step-form.tsx │ │ │ │ │ ├── customize-steps-from.tsx │ │ │ │ │ ├── modal-step-form.tsx │ │ │ │ │ ├── multi-card-step-form.tsx │ │ │ │ │ ├── steps-form-vertical.tsx │ │ │ │ │ └── steps-from.tsx │ │ │ │ ├── index.en-US.md │ │ │ │ └── index.md │ │ │ ├── Submitter │ │ │ │ └── index.tsx │ │ │ ├── Switch │ │ │ │ └── index.tsx │ │ │ ├── Text │ │ │ │ └── index.tsx │ │ │ ├── TextArea │ │ │ │ └── index.tsx │ │ │ ├── TimePicker │ │ │ │ └── index.tsx │ │ │ ├── TreeSelect │ │ │ │ └── index.tsx │ │ │ ├── UploadButton │ │ │ │ └── index.tsx │ │ │ ├── UploadDragger │ │ │ │ └── index.tsx │ │ │ ├── form.en-US.md │ │ │ ├── form.md │ │ │ └── index.ts │ │ ├── demos │ │ │ ├── antd.modify.tsx │ │ │ ├── antd.nest.tsx │ │ │ ├── antd.tsx │ │ │ ├── base-test.tsx │ │ │ ├── base.tsx │ │ │ ├── components-test.tsx │ │ │ ├── config-provider.tsx │ │ │ ├── dependency.tsx │ │ │ ├── form-control-render.tsx │ │ │ ├── form-item-render.tsx │ │ │ ├── form-layout-grid.tsx │ │ │ ├── form-layout.tsx │ │ │ ├── formRef.tsx │ │ │ ├── label-col.tsx │ │ │ ├── labelInValue.tsx │ │ │ ├── layout-change.tsx │ │ │ ├── layout-footer.tsx │ │ │ ├── linkage-customization.tsx │ │ │ ├── modalform-test.tsx │ │ │ ├── money.tsx │ │ │ ├── params-formref.tsx │ │ │ ├── pro-form-dependency.debug.tsx │ │ │ ├── pro-form-editableTable.tsx │ │ │ ├── sync-to-url.tsx │ │ │ └── typings.d.ts │ │ ├── helpers │ │ │ ├── grid.tsx │ │ │ └── index.ts │ │ ├── index.tsx │ │ ├── layouts │ │ │ ├── DrawerForm │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── LightFilter │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── LoginForm │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── LoginFormPage │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── ModalForm │ │ │ │ └── index.tsx │ │ │ ├── ProForm │ │ │ │ └── index.tsx │ │ │ ├── QueryFilter │ │ │ │ ├── Actions.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── StepsForm │ │ │ │ ├── StepForm.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ └── index.ts │ │ └── typing.ts │ └── tsconfig.json ├── layout │ ├── .fatherrc.ts │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── ProLayout.tsx │ │ ├── WrapContent.tsx │ │ ├── assert │ │ │ └── Logo.tsx │ │ ├── components │ │ │ ├── AppsLogoComponents │ │ │ │ ├── AppsLogo.tsx │ │ │ │ ├── DefaultContent.tsx │ │ │ │ ├── SimpleContent.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── style │ │ │ │ │ ├── default.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ └── simple.ts │ │ │ │ └── types.d.ts │ │ │ ├── CollapsedIcon │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── Footer.tsx │ │ │ ├── FooterToolbar │ │ │ │ ├── index.tsx │ │ │ │ └── style │ │ │ │ │ ├── index.ts │ │ │ │ │ └── stylish.ts │ │ │ ├── GlobalFooter │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── GlobalHeader │ │ │ │ ├── ActionsContent.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── rightContentStyle.ts │ │ │ │ └── style.ts │ │ │ ├── GridContent │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── Header │ │ │ │ ├── index.tsx │ │ │ │ └── style │ │ │ │ │ ├── header.ts │ │ │ │ │ └── stylish.ts │ │ │ ├── Help │ │ │ │ ├── AsyncContentPanel.tsx │ │ │ │ ├── HelpProvide.tsx │ │ │ │ ├── ProHelpContentPanel.tsx │ │ │ │ ├── ProHelpDrawer.tsx │ │ │ │ ├── ProHelpModal.tsx │ │ │ │ ├── ProHelpPanel.tsx │ │ │ │ ├── ProHelpPopover.tsx │ │ │ │ ├── RenderContentPanel.tsx │ │ │ │ ├── Search.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── PageContainer │ │ │ │ ├── demos │ │ │ │ │ ├── basic.tsx │ │ │ │ │ ├── fixHeader.tsx │ │ │ │ │ ├── hideBreadMenu.tsx │ │ │ │ │ ├── loading.tsx │ │ │ │ │ └── token.tsx │ │ │ │ ├── index.en-US.md │ │ │ │ ├── index.md │ │ │ │ ├── index.tsx │ │ │ │ └── style │ │ │ │ │ ├── index.ts │ │ │ │ │ └── stylish.ts │ │ │ ├── PageHeader │ │ │ │ ├── demo │ │ │ │ │ ├── actions.en-US.md │ │ │ │ │ ├── actions.md │ │ │ │ │ ├── basic.en-US.md │ │ │ │ │ ├── basic.md │ │ │ │ │ ├── breadcrumb.en-US.md │ │ │ │ │ ├── breadcrumb.md │ │ │ │ │ ├── content.en-US.md │ │ │ │ │ ├── content.md │ │ │ │ │ ├── ghost.en-US.md │ │ │ │ │ ├── ghost.md │ │ │ │ │ ├── responsive.en-US.md │ │ │ │ │ └── responsive.md │ │ │ │ ├── index.en-US.md │ │ │ │ ├── index.md │ │ │ │ ├── index.tsx │ │ │ │ └── style │ │ │ │ │ └── index.ts │ │ │ ├── PageLoading │ │ │ │ └── index.tsx │ │ │ ├── SettingDrawer │ │ │ │ ├── BlockCheckbox.tsx │ │ │ │ ├── LayoutChange.tsx │ │ │ │ ├── RegionalChange.tsx │ │ │ │ ├── ThemeColor.tsx │ │ │ │ ├── icon │ │ │ │ │ ├── group.tsx │ │ │ │ │ └── sub.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── style │ │ │ │ │ └── index.ts │ │ │ ├── SiderMenu │ │ │ │ ├── Arrow.tsx │ │ │ │ ├── BaseMenu.tsx │ │ │ │ ├── SiderMenu.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── style │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── menu.ts │ │ │ │ │ └── stylish.ts │ │ │ ├── TopNavHeader │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── WaterMark │ │ │ │ ├── demos │ │ │ │ │ ├── custom.tsx │ │ │ │ │ ├── frontend.tsx │ │ │ │ │ ├── image.tsx │ │ │ │ │ ├── text.tsx │ │ │ │ │ └── textRows.tsx │ │ │ │ ├── index.en-US.md │ │ │ │ ├── index.md │ │ │ │ └── index.tsx │ │ │ ├── layout.$tab-api.md │ │ │ ├── layout.en-US.$tab-api.md │ │ │ ├── layout.en-US.md │ │ │ └── layout.md │ │ ├── context │ │ │ └── RouteContext.tsx │ │ ├── defaultSettings.ts │ │ ├── demos │ │ │ ├── AlwaysDefaultOpenAllMenu.tsx │ │ │ ├── BreadcrumbsRepeat.tsx │ │ │ ├── DefaultOpenAllMenu.tsx │ │ │ ├── IconFont.tsx │ │ │ ├── MenuGroup.tsx │ │ │ ├── MultipleMenuOnePath.tsx │ │ │ ├── Nested.tsx │ │ │ ├── TopmenuNested.tsx │ │ │ ├── _defaultProps.tsx │ │ │ ├── antd@4MenuIconFormServe.tsx │ │ │ ├── api.tsx │ │ │ ├── appList-group-simple.tsx │ │ │ ├── appList-group.tsx │ │ │ ├── async-load-help.tsx │ │ │ ├── background-context.tsx │ │ │ ├── base.tsx │ │ │ ├── classicMode.tsx │ │ │ ├── collapsedShowTitle.tsx │ │ │ ├── complexMenu.ts │ │ │ ├── config-provider.tsx │ │ │ ├── customMenu.ts │ │ │ ├── customSider.tsx │ │ │ ├── customize-collapsed.tsx │ │ │ ├── customizeMenu.tsx │ │ │ ├── dark.tsx │ │ │ ├── debug-demo.tsx │ │ │ ├── designMenuCss.tsx │ │ │ ├── designSiderMenu.tsx │ │ │ ├── draggableHelp.tsx │ │ │ ├── dynamic-settings.tsx │ │ │ ├── dynamicMenu.tsx │ │ │ ├── error-boundaries.tsx │ │ │ ├── footer-global-tools.tsx │ │ │ ├── footer.tsx │ │ │ ├── ghost.tsx │ │ │ ├── help.tsx │ │ │ ├── hideMenu.tsx │ │ │ ├── immersive-navigation-top.tsx │ │ │ ├── immersive-navigation.tsx │ │ │ ├── menu-group.tsx │ │ │ ├── mixMode.tsx │ │ │ ├── morse_debug.tsx │ │ │ ├── pageSimplify.tsx │ │ │ ├── proHelpModal.tsx │ │ │ ├── searchMenu.tsx │ │ │ ├── siderMode.tsx │ │ │ ├── siteMenu.tsx │ │ │ ├── splitMenus.tsx │ │ │ ├── theme.tsx │ │ │ ├── top-breadcrumb.tsx │ │ │ └── topMode.tsx │ │ ├── getPageTitle.ts │ │ ├── index.tsx │ │ ├── locales │ │ │ ├── en-US.ts │ │ │ ├── en-US │ │ │ │ └── settingDrawer.ts │ │ │ ├── index.ts │ │ │ ├── it-IT.ts │ │ │ ├── it-IT │ │ │ │ └── settingDrawer.ts │ │ │ ├── ko-KR.ts │ │ │ ├── ko-KR │ │ │ │ └── settingDrawer.ts │ │ │ ├── zh-CN.ts │ │ │ ├── zh-CN │ │ │ │ └── settingDrawer.ts │ │ │ ├── zh-TW.ts │ │ │ └── zh-TW │ │ │ │ └── settingDrawer.ts │ │ ├── style │ │ │ └── index.ts │ │ ├── typing.ts │ │ └── utils │ │ │ ├── getBreadcrumbProps.tsx │ │ │ ├── getMenuData.ts │ │ │ ├── pathTools.ts │ │ │ ├── useCurrentMenuLayoutProps.ts │ │ │ └── utils.ts │ └── tsconfig.json ├── list │ ├── .fatherrc.ts │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── Item.tsx │ │ ├── ListView.tsx │ │ ├── components │ │ │ ├── list.en-US.md │ │ │ └── list.md │ │ ├── constants.ts │ │ ├── demos │ │ │ ├── ToolBar.tsx │ │ │ ├── base.tsx │ │ │ ├── card-list.tsx │ │ │ ├── editable.tsx │ │ │ ├── expand.tsx │ │ │ ├── filter.tsx │ │ │ ├── layout.tsx │ │ │ ├── pagination.tsx │ │ │ ├── search.tsx │ │ │ ├── selectedRow.tsx │ │ │ ├── size.tsx │ │ │ ├── special.tsx │ │ │ └── testConfigProvider.tsx │ │ ├── index.tsx │ │ └── style │ │ │ └── index.ts │ └── tsconfig.json ├── provider │ ├── .fatherrc.ts │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── index.tsx │ │ ├── intl.ts │ │ ├── locale │ │ │ ├── ar_EG.tsx │ │ │ ├── ca_ES.tsx │ │ │ ├── cs_CZ.tsx │ │ │ ├── de_DE.tsx │ │ │ ├── en_GB.tsx │ │ │ ├── en_US.tsx │ │ │ ├── es_ES.tsx │ │ │ ├── fa_IR.tsx │ │ │ ├── fr_FR.tsx │ │ │ ├── he_IL.tsx │ │ │ ├── hr_HR.tsx │ │ │ ├── id_ID.tsx │ │ │ ├── it_IT.tsx │ │ │ ├── ja_JP.tsx │ │ │ ├── ko_KR.tsx │ │ │ ├── mn_MN.tsx │ │ │ ├── ms_MY.tsx │ │ │ ├── nl_NL.tsx │ │ │ ├── pl_PL.tsx │ │ │ ├── pt_BR.tsx │ │ │ ├── ro_RO.tsx │ │ │ ├── ru_RU.tsx │ │ │ ├── sk_SK.tsx │ │ │ ├── sr_RS.tsx │ │ │ ├── sv_SE.tsx │ │ │ ├── th_TH.tsx │ │ │ ├── tr_TR.tsx │ │ │ ├── uk_UA.tsx │ │ │ ├── uz_UZ.tsx │ │ │ ├── vi_VN.tsx │ │ │ ├── zh_CN.tsx │ │ │ └── zh_TW.tsx │ │ ├── typing │ │ │ └── layoutToken.ts │ │ ├── useStyle │ │ │ ├── index.ts │ │ │ └── token.ts │ │ └── utils │ │ │ └── merge.ts │ └── tsconfig.json ├── skeleton │ ├── .fatherrc.ts │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── components │ │ │ ├── Descriptions │ │ │ │ └── index.tsx │ │ │ ├── List │ │ │ │ └── index.tsx │ │ │ ├── Result │ │ │ │ └── index.tsx │ │ │ ├── skeleton.en-US.md │ │ │ └── skeleton.md │ │ ├── demos │ │ │ ├── descriptions.tsx │ │ │ ├── list.static.tsx │ │ │ ├── list.tsx │ │ │ └── result.tsx │ │ └── index.tsx │ └── tsconfig.json ├── table │ ├── .fatherrc.ts │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ │ ├── Store │ │ │ └── Provide.tsx │ │ ├── Table.tsx │ │ ├── components │ │ │ ├── Alert │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── ColumnSetting │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── DragSortTable │ │ │ │ ├── demos │ │ │ │ │ ├── drag-sort-table.tsx │ │ │ │ │ └── drag.tsx │ │ │ │ ├── index.en-US.md │ │ │ │ ├── index.md │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── Dropdown │ │ │ │ └── index.tsx │ │ │ ├── EditableTable │ │ │ │ ├── CellEditorTable.tsx │ │ │ │ ├── RowEditorTable.tsx │ │ │ │ ├── demos │ │ │ │ │ ├── basic.tsx │ │ │ │ │ ├── cell-editor-table.tsx │ │ │ │ │ ├── children.tsx │ │ │ │ │ ├── custom.tsx │ │ │ │ │ ├── form-item.tsx │ │ │ │ │ ├── form-linkage.tsx │ │ │ │ │ ├── fuza.tsx │ │ │ │ │ ├── real-time-editing.tsx │ │ │ │ │ └── row-editor-table.tsx │ │ │ │ ├── index.en-US.md │ │ │ │ ├── index.md │ │ │ │ └── index.tsx │ │ │ ├── Form │ │ │ │ ├── FormRender.tsx │ │ │ │ └── index.tsx │ │ │ ├── ListToolBar │ │ │ │ ├── HeaderMenu.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── style.ts │ │ │ ├── ToolBar │ │ │ │ ├── DensityIcon.tsx │ │ │ │ ├── FullscreenIcon.tsx │ │ │ │ └── index.tsx │ │ │ ├── table.$tab-api.md │ │ │ ├── table.en-US.$tab-api.md │ │ │ ├── table.en-US.md │ │ │ └── table.md │ │ ├── demos │ │ │ ├── ListToolBar │ │ │ │ ├── basic.tsx │ │ │ │ ├── menu.tsx │ │ │ │ ├── multipleLine.tsx │ │ │ │ ├── no-title.tsx │ │ │ │ └── tabs.tsx │ │ │ ├── batchOption.tsx │ │ │ ├── card-title.tsx │ │ │ ├── columns-setting-custom-icon.tsx │ │ │ ├── columnsStateMap.tsx │ │ │ ├── config-provider.tsx │ │ │ ├── crud.tsx │ │ │ ├── customization-value-type.tsx │ │ │ ├── dataSource.tsx │ │ │ ├── dateFormatter.tsx │ │ │ ├── dynamic-columns-state.tsx │ │ │ ├── dynamic-settings.tsx │ │ │ ├── edittable-rules.tsx │ │ │ ├── error-boundaries-false.tsx │ │ │ ├── error-boundaries.tsx │ │ │ ├── form.tsx │ │ │ ├── intl.tsx │ │ │ ├── lightfilter.tsx │ │ │ ├── linkage_form.tsx │ │ │ ├── listToolBar.tsx │ │ │ ├── no-option.tsx │ │ │ ├── no-title.tsx │ │ │ ├── normal.tsx │ │ │ ├── open-rules.tsx │ │ │ ├── pollinga.tsx │ │ │ ├── renderTable.tsx │ │ │ ├── rtl_table.tsx │ │ │ ├── search.tsx │ │ │ ├── search_option.tsx │ │ │ ├── single-test.tsx │ │ │ ├── single.tsx │ │ │ ├── split.tsx │ │ │ ├── table-nested.tsx │ │ │ ├── theme.tsx │ │ │ ├── valueType.tsx │ │ │ ├── valueTypeDate.tsx │ │ │ ├── valueTypeNumber.tsx │ │ │ └── valueType_select.tsx │ │ ├── index.tsx │ │ ├── style │ │ │ └── index.ts │ │ ├── typing.ts │ │ ├── useFetchData.tsx │ │ └── utils │ │ │ ├── cellRenderToFromItem.tsx │ │ │ ├── columnRender.tsx │ │ │ ├── columnSort.ts │ │ │ ├── genProColumnToColumn.tsx │ │ │ ├── index.ts │ │ │ └── useDragSort.tsx │ └── tsconfig.json └── utils │ ├── .fatherrc.ts │ ├── CHANGELOG.md │ ├── README.md │ ├── package.json │ ├── src │ ├── compareVersions │ │ ├── coverToNewToken.ts │ │ ├── index.ts │ │ ├── menuOverlayCompatible.tsx │ │ └── openVisibleCompatible.ts │ ├── compatible │ │ └── compatibleBorder.ts │ ├── components │ │ ├── DropdownFooter │ │ │ ├── index.tsx │ │ │ └── style.ts │ │ ├── ErrorBoundary │ │ │ └── index.tsx │ │ ├── FieldLabel │ │ │ ├── index.tsx │ │ │ └── style.ts │ │ ├── FilterDropdown │ │ │ ├── index.tsx │ │ │ └── style.ts │ │ ├── InlineErrorFormItem │ │ │ ├── index.tsx │ │ │ └── style.ts │ │ ├── LabelIconTip │ │ │ ├── index.tsx │ │ │ └── style.ts │ │ └── ProFormContext │ │ │ └── index.tsx │ ├── conversionMomentValue │ │ └── index.ts │ ├── dateArrayFormatter │ │ └── index.tsx │ ├── genCopyable │ │ └── index.tsx │ ├── getFieldPropsOrFormItemProps │ │ └── index.tsx │ ├── hooks │ │ ├── useDebounceFn │ │ │ └── index.ts │ │ ├── useDebounceValue │ │ │ └── index.ts │ │ ├── useDeepCompareEffect │ │ │ └── index.ts │ │ ├── useDeepCompareMemo │ │ │ └── index.ts │ │ ├── useDocumentTitle │ │ │ └── index.ts │ │ ├── useFetchData │ │ │ └── index.tsx │ │ ├── useForceRender │ │ │ └── index.ts │ │ ├── useLatest │ │ │ └── index.ts │ │ ├── usePrevious │ │ │ └── index.ts │ │ ├── useReactiveRef │ │ │ └── index.ts │ │ ├── useRefCallback │ │ │ └── index.ts │ │ └── useRefFunction │ │ │ └── index.ts │ ├── index.tsx │ ├── isBrowser │ │ └── index.ts │ ├── isDeepEqualReact │ │ └── index.ts │ ├── isDropdownValueType │ │ └── index.ts │ ├── isImg │ │ └── index.ts │ ├── isNil │ │ └── index.ts │ ├── isUrl │ │ └── index.ts │ ├── merge │ │ └── index.ts │ ├── nanoid │ │ └── index.ts │ ├── omitBoolean │ │ └── index.ts │ ├── omitUndefined │ │ └── index.ts │ ├── omitUndefinedAndEmptyArr │ │ └── index.ts │ ├── parseValueToMoment │ │ └── index.ts │ ├── pickProFormItemProps │ │ └── index.tsx │ ├── pickProProps │ │ └── index.tsx │ ├── proFieldParsingText │ │ └── index.tsx │ ├── runFunction │ │ └── index.ts │ ├── stringify │ │ └── index.ts │ ├── transformKeySubmitValue │ │ └── index.ts │ ├── typing.ts │ ├── useEditableArray │ │ └── index.tsx │ ├── useEditableMap │ │ └── index.tsx │ ├── useMediaQuery │ │ ├── index.ts │ │ └── query.ts │ └── useMountMergeState │ │ └── index.ts │ └── tsconfig.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── public ├── CNAME ├── favicon.ico ├── icon.png └── sitemap.xml ├── scripts ├── bootstrap.js ├── changelogs.js ├── checkDeps.js ├── checkPublish.js ├── createRelease.js ├── gen_version.js ├── generateSizeLimit.js ├── issue.js ├── preDeploy.js ├── readApi.mjs ├── release.js ├── replaceEs.js ├── replaceLib.js ├── replaceLodash.js ├── syncTNPM.js ├── utils │ ├── exec.js │ ├── getPackages.js │ └── isNextVersion.js └── verifyCommit.js ├── tests ├── __snapshots__ │ └── doc.test.ts.snap ├── card │ ├── __snapshots__ │ │ └── demo.test.ts.snap │ ├── checkcard.test.tsx │ ├── demo.test.ts │ └── index.test.tsx ├── demo.tsx ├── descriptions │ ├── __snapshots__ │ │ ├── demo.test.ts.snap │ │ ├── editor.test.tsx.snap │ │ └── index.test.tsx.snap │ ├── demo.test.ts │ ├── editor.test.tsx │ └── index.test.tsx ├── doc.test.ts ├── field │ ├── __snapshots__ │ │ ├── demo.test.ts.snap │ │ ├── field.test.tsx.snap │ │ └── status.test.tsx.snap │ ├── datePick.test.tsx │ ├── demo.test.ts │ ├── field.test.tsx │ ├── fixtures │ │ ├── demo.tsx │ │ └── treeSelectDemo.tsx │ └── status.test.tsx ├── form │ ├── __snapshots__ │ │ ├── base.test.tsx.snap │ │ ├── demo.test.ts.snap │ │ ├── formList.test.tsx.snap │ │ ├── lightFilter.test.tsx.snap │ │ ├── proFormMoney.test.tsx.snap │ │ ├── schemaForm.test.tsx.snap │ │ └── upload.test.tsx.snap │ ├── base.test.tsx │ ├── demo.test.ts │ ├── dependency.test.tsx │ ├── drawerForm.test.tsx │ ├── drawerFormTimeout.test.tsx │ ├── fieldSet.test.tsx │ ├── filter.react.test.tsx │ ├── formList.test.tsx │ ├── formitem.test.tsx │ ├── formitemrender.test.tsx │ ├── lightFilter.test.tsx │ ├── loginForm.test.tsx │ ├── modalForm.test.tsx │ ├── proFormCaptcha.test.tsx │ ├── proFormMoney.test.tsx │ ├── proFormSegmented.test.tsx │ ├── queryFilter.test.tsx │ ├── schemaForm.test.tsx │ ├── ssr.test.tsx │ ├── stepFormTest.test.tsx │ └── upload.test.tsx ├── layout │ ├── PageHeader.test.tsx │ ├── __snapshots__ │ │ ├── PageHeader.test.tsx.snap │ │ ├── demo.test.ts.snap │ │ ├── footer.test.tsx.snap │ │ ├── help.test.tsx.snap │ │ ├── index.test.tsx.snap │ │ ├── mobile.test.tsx.snap │ │ ├── pageContainer.test.tsx.snap │ │ ├── pageHeaderWarp.test.tsx.snap │ │ ├── settingDrawer.test.tsx.snap │ │ └── waterMark.test.tsx.snap │ ├── defaultProps.tsx │ ├── defaultSettings.ts │ ├── demo.test.ts │ ├── footer.test.tsx │ ├── getPageTitle.test.tsx │ ├── help.test.tsx │ ├── index.test.tsx │ ├── mobile.test.tsx │ ├── pageContainer.test.tsx │ ├── pageHeaderWarp.test.tsx │ ├── settingDrawer.test.tsx │ ├── settings.test.tsx │ └── waterMark.test.tsx ├── list │ ├── __snapshots__ │ │ ├── demo.test.ts.snap │ │ └── index.test.tsx.snap │ ├── demo.test.ts │ └── index.test.tsx ├── no-duplicated.ts ├── provider │ └── index.test.tsx ├── setupTests.ts ├── skeleton │ ├── __snapshots__ │ │ ├── demo.test.ts.snap │ │ └── skeleton.test.tsx.snap │ ├── demo.test.ts │ └── skeleton.test.tsx ├── table │ ├── __snapshots__ │ │ ├── column.test.tsx.snap │ │ ├── demo.test.ts.snap │ │ ├── dragSort.test.tsx.snap │ │ ├── editor-table-two.test.tsx.snap │ │ ├── editor-table.test.tsx.snap │ │ ├── listtoolbar.test.tsx.snap │ │ ├── searchGutter.test.tsx.snap │ │ ├── valueEnum.test.tsx.snap │ │ └── valueType.test.tsx.snap │ ├── column.test.tsx │ ├── columnSetting.test.tsx │ ├── demo.test.ts │ ├── demo.tsx │ ├── dragSort.test.tsx │ ├── dynamic-columns-state.test.tsx │ ├── editor-table-two.test.tsx │ ├── editor-table.test.tsx │ ├── filter.test.tsx │ ├── form.test.tsx │ ├── index.test.tsx │ ├── listtoolbar.test.tsx │ ├── mock.data.json │ ├── pagination.test.tsx │ ├── polling.test.tsx │ ├── protableSpin.test.tsx │ ├── search.test.tsx │ ├── searchGutter.test.tsx │ ├── selectKeys.test.tsx │ ├── valueEnum.test.tsx │ └── valueType.test.tsx ├── tsconfig.duplicate.json ├── util.ts └── utils │ ├── __snapshots__ │ └── index.test.tsx.snap │ └── index.test.tsx ├── tsconfig.json ├── typings.d.ts ├── vercel.json └── vitest.config.ts /.codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: 4 | default: 5 | # Fail the status if coverage drops by >= 0.1% 6 | threshold: 1% 7 | -------------------------------------------------------------------------------- /.dumi/app.tsx: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /.dumi/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "include": ["**/*"] 4 | } 5 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # dependencies 2 | node_modules 3 | # production 4 | dist 5 | /.vscode 6 | lib 7 | es 8 | .umi 9 | .github 10 | scripts 11 | webpack.config.js 12 | server -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [require.resolve('@umijs/fabric/dist/eslint')], 3 | rules: { 4 | '@typescript-eslint/consistent-type-imports': 'off', 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /.fatherrc.base.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'father'; 2 | 3 | export default defineConfig({ 4 | // 以下为 esm 配置项启用时的默认值,有自定义需求时才需配置 5 | esm: { 6 | input: 'src', // 默认编译目录 7 | output: 'es', 8 | extraBabelPlugins: [[require.resolve('./scripts/replaceLib'), {}]], 9 | platform: 'browser', // 默认构建为 Browser 环境的产物 10 | transformer: 'babel', // 默认使用 babel 以提供更好的兼容性 11 | }, 12 | // 以下为 cjs 配置项启用时的默认值,有自定义需求时才需配置 13 | cjs: { 14 | extraBabelPlugins: [ 15 | [require.resolve('./scripts/replaceEs'), {}], 16 | [require.resolve('./scripts/replaceLodash'), {}], 17 | ], 18 | input: 'src', // 默认编译目录 19 | output: 'lib', 20 | platform: 'browser', // 默认构建为 Node.js 环境的产物 21 | transformer: 'babel', // 默认使用 esbuild 以获得更快的构建速度 22 | }, 23 | }); 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: '报告Bug 🐛' 3 | about: 报告 ProComponents 的 bug 4 | title: '🐛[BUG]' 5 | labels: '🐛bug' 6 | assignees: '' 7 | --- 8 | 9 | 提问前先看看: 10 | 11 | https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md 12 | 13 | ### 🐛 bug 描述 14 | 15 | 18 | 19 | ### 📷 复现步骤 20 | 21 | 25 | 26 | ### 🏞 期望结果 27 | 28 | 31 | 32 | ### 💻 复现代码 33 | 34 | 37 | 38 | ### © 版本信息 39 | 40 | - ProComponents 版本: [e.g. 4.0.0] 41 | - umi 版本 42 | - 浏览器环境 43 | - 开发环境 [e.g. mac OS] 44 | 45 | ### 🚑 其他信息 46 | 47 | 50 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: '功能需求 ✨' 3 | about: 对 ProComponents 的需求或建议 4 | title: '👑 [需求]' 5 | labels: '👑 Feature Request' 6 | assignees: '' 7 | --- 8 | 9 | 提问前先看看: 10 | 11 | https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md 12 | 13 | ### 🔩 所属模块或组件 14 | 15 | 18 | 19 | ### 🥰 需求描述 20 | 21 | 24 | 25 | ### ⛰ 功能需求适用场景 26 | 27 | 30 | 31 | ### 🧐 解决方案 32 | 33 | 36 | 37 | ### 🚑 其他信息 38 | 39 | 42 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: '疑问或需要帮助 ❓' 3 | about: 对 ProComponents 使用的疑问或需要帮助 4 | title: '🧐[问题]' 5 | labels: '🧐question' 6 | assignees: '' 7 | --- 8 | 9 | 提问前先看看: 10 | 11 | https://github.com/ryanhanwu/How-To-Ask-Questions-The-Smart-Way/blob/main/README-zh_CN.md 12 | 13 | ### 🧐 问题描述 14 | 15 | 18 | 19 | ### 💻 示例代码 20 | 21 | 24 | 25 | ### 🚑 其他信息 26 | 27 | 30 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | if: github.repository == 'ant-design/pro-components' 8 | runs-on: ${{ matrix.os }} 9 | strategy: 10 | matrix: 11 | node-version: [16.x] 12 | os: [ubuntu-latest] 13 | fail-fast: false 14 | steps: 15 | - uses: actions/checkout@v2 16 | - uses: actions/setup-node@v3 17 | with: 18 | node-version: 16 19 | - name: Install pnpm 20 | uses: pnpm/action-setup@v2 21 | with: 22 | version: 8.12.1 23 | - run: pnpm install 24 | - run: pnpm run build 25 | env: 26 | PRO_COMPONENTS_CI: CI 27 | - run: pnpm run lint 28 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: 'CodeQL' 2 | 3 | on: 4 | push: 5 | branches: ['master'] 6 | pull_request: 7 | branches: ['master'] 8 | schedule: 9 | - cron: '55 1 * * 1' 10 | 11 | jobs: 12 | analyze: 13 | name: Analyze 14 | runs-on: ubuntu-latest 15 | permissions: 16 | actions: read 17 | contents: read 18 | security-events: write 19 | 20 | strategy: 21 | fail-fast: false 22 | matrix: 23 | language: [javascript] 24 | 25 | steps: 26 | - name: Checkout 27 | uses: actions/checkout@v3 28 | 29 | - name: Initialize CodeQL 30 | uses: github/codeql-action/init@v2 31 | with: 32 | languages: ${{ matrix.language }} 33 | queries: +security-and-quality 34 | 35 | - name: Autobuild 36 | uses: github/codeql-action/autobuild@v2 37 | 38 | - name: Perform CodeQL Analysis 39 | uses: github/codeql-action/analyze@v2 40 | with: 41 | category: '/language:${{ matrix.language }}' 42 | -------------------------------------------------------------------------------- /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | name: coverage CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | if: github.repository == 'ant-design/pro-components' 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v3 11 | with: 12 | fetch-depth: 1 13 | - uses: actions/setup-node@v3 14 | with: 15 | node-version: 20.x 16 | - name: Install pnpm 17 | uses: pnpm/action-setup@v2 18 | with: 19 | version: 8.12.1 20 | 21 | - run: pnpm install 22 | if: | 23 | steps.cache-pnpm-cache.outputs.cache-hit != 'true' || 24 | steps.cache-node-modules.outputs.cache-hit != 'true' 25 | - run: pnpm run test:coverage 26 | env: 27 | CI: true 28 | PROGRESS: none 29 | NODE_ENV: test 30 | NODE_OPTIONS: --max_old_space_size=4096 31 | - run: bash <(curl -s https://codecov.io/bash) 32 | -------------------------------------------------------------------------------- /.github/workflows/issue-open-check.yml: -------------------------------------------------------------------------------- 1 | name: Issue Open Check 2 | 3 | on: 4 | issues: 5 | types: [opened, edited] 6 | 7 | jobs: 8 | check-issue: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions-cool/issues-helper@v2.2.0 12 | id: check 13 | with: 14 | actions: 'check-issue' 15 | issue-number: ${{ github.event.issue.number }} 16 | title-excludes: '🐛[BUG], 👑 [需求], 🧐[问题]' 17 | 18 | - if: steps.check.outputs.check-result == 'false' 19 | uses: actions-cool/issues-helper@v2.2.0 20 | with: 21 | actions: 'create-comment, close-issue' 22 | issue-number: ${{ github.event.issue.number }} 23 | body: | 24 | 当前 Issue 未检测到标题,请规范填写,谢谢! 25 | 26 | The title of the current issue is not detected, please fill in according to the specifications, thank you! 27 | 28 | - if: steps.check.outputs.check-result == 'true' 29 | uses: actions-cool/issues-similarity-analysis@v1.1.0 30 | with: 31 | filter-threshold: 0.6 32 | title-excludes: '🐛[BUG], 👑 [需求], 🧐[问题]' 33 | comment-title: '### 以下的 Issues 可能会帮助到你 / The following issues may help you' 34 | show-footer: false 35 | -------------------------------------------------------------------------------- /.github/workflows/pkg.pr.new.yml: -------------------------------------------------------------------------------- 1 | name: Publish Any Commit 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | types: [opened, synchronize, reopened] 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | if: github.repository == 'ant-design/pro-components' 14 | 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v4 18 | 19 | - uses: pnpm/action-setup@v4 20 | name: Install pnpm 21 | with: 22 | run_install: false 23 | 24 | - name: Install Node.js 25 | uses: actions/setup-node@v4 26 | with: 27 | node-version: 20 28 | cache: 'pnpm' 29 | 30 | - name: Install dependencies 31 | run: pnpm install 32 | 33 | - name: Build 34 | run: pnpm build 35 | 36 | # https://github.com/stackblitz-labs/pkg.pr.new#readme 37 | - run: pnpx pkg-pr-new publish './packages/*' --no-template --compact 38 | -------------------------------------------------------------------------------- /.github/workflows/rebase.yml: -------------------------------------------------------------------------------- 1 | on: 2 | issue_comment: 3 | types: [created] 4 | name: Automatic Rebase 5 | jobs: 6 | rebase: 7 | name: Rebase 8 | if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/rebase') 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@master 12 | with: 13 | fetch-depth: 0 14 | - name: Automatic Rebase 15 | uses: cirrus-actions/rebase@1.3 16 | env: 17 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | **/node_modules 5 | # roadhog-api-doc ignore 6 | /src/utils/request-temp.js 7 | _roadhog-api-doc 8 | 9 | # production 10 | **/dist 11 | /.vscode 12 | **/**/lib/** 13 | **/**/es/** 14 | # misc 15 | .DS_Store 16 | npm-debug.log* 17 | yarn-error.log 18 | /coverage 19 | .idea 20 | package-lock.json 21 | *bak 22 | .vscode 23 | 24 | # visual studio code 25 | .history 26 | *.log 27 | 28 | functions/mock 29 | .temp/** 30 | 31 | # umi 32 | .umi 33 | .umi-production 34 | 35 | # screenshot 36 | screenshot 37 | .firebase 38 | .eslintcache 39 | .changelogs 40 | .changelog.md 41 | packages/components/src/version.ts 42 | .dumi/tmp 43 | .dumi/tmp-production 44 | server -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # .npmrc 2 | node-options=--max_old_space_size=8192 3 | public-hoist-pattern[]=@types* 4 | auto-install-peers=false -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | **/*.svg 2 | .umi 3 | .umi-production 4 | **/dist 5 | **/lib 6 | **/es 7 | **\__snapshots__\** 8 | pnpm-lock.yaml 9 | server -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | const fabric = require('@umijs/fabric'); 2 | 3 | module.exports = { 4 | ...fabric.prettier, 5 | printWidth: 80, 6 | plugins: [require.resolve('prettier-plugin-organize-imports')], 7 | }; 8 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) Copyright © 2023 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /docs/components/schema.$tab-api.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: DEMO 3 | order: 0 4 | --- 5 | 6 | ## 代码演示 7 | 8 | 9 | -------------------------------------------------------------------------------- /docs/components/valueEnum-map.tsx: -------------------------------------------------------------------------------- 1 | import { ProTable } from '@ant-design/pro-components'; 2 | 3 | export default function () { 4 | return ( 5 | { 7 | console.log(params); 8 | return Promise.resolve([]); 9 | }} 10 | columns={[ 11 | { 12 | dataIndex: 'status1', 13 | title: '状态(number)', 14 | // 由于js的object数字key会重新排序,不会按书写顺序,因此下拉选项会是【不通过】【通过】 15 | valueEnum: { 16 | 1: { 17 | text: '通过', 18 | }, 19 | 0: { 20 | text: '不通过', 21 | }, 22 | }, 23 | }, 24 | { 25 | dataIndex: 'status2', 26 | title: '状态(number)', 27 | // 使用Map来保证选项的顺序 28 | valueEnum: new Map([ 29 | [1, '通过'], 30 | [0, '不通过'], 31 | ]), 32 | }, 33 | { 34 | dataIndex: 'status3', 35 | title: '状态(boolean)', 36 | // 使用Map来完成boolen类型的key 37 | valueEnum: new Map([ 38 | [true, '通过'], 39 | [false, '不通过'], 40 | ]), 41 | }, 42 | ]} 43 | /> 44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /docs/playground/index.en-US.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: CRUD 3 | nav: 4 | title: Playground 5 | path: /playground 6 | --- 7 | 8 | # CRUD 9 | 10 | ProTable,ProDescriptions,ProForm 都是基于 ProField 来进行封装。ProTable 和 ProDescriptions 根据 valueType 来渲染不同的 ProField,Form 则是通过不同的 FormField 来实现封装。 11 | 12 | 使用同样的底层实现为 ProTable,ProDescriptions,ProForm 打通带来了便利。ProForm 可以很方便的实现只读模式,ProTable 可以快速实现查询表单和可编辑表格。ProDescriptions 可以实现节点编辑,以下有个例子可以切换三个组件。 13 | 14 | 15 | -------------------------------------------------------------------------------- /docs/playground/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: CRUD 3 | nav: 4 | title: Playground 5 | path: /playground 6 | --- 7 | 8 | # CRUD 9 | 10 | ProTable,ProDescriptions,ProForm 都是基于 ProField 来进行封装。ProTable 和 ProDescriptions 根据 valueType 来渲染不同的 ProField,Form 则是通过不同的 FormField 来实现封装。 11 | 12 | 使用同样的底层实现为 ProTable,ProDescriptions,ProForm 打通带来了便利。ProForm 可以很方便的实现只读模式,ProTable 可以快速实现查询表单和可编辑表格。ProDescriptions 可以实现节点编辑,以下有个例子可以切换三个组件。 13 | 14 | 15 | -------------------------------------------------------------------------------- /docs/playground/pro-descriptions.en-US.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ProDescriptions 3 | nav: 4 | title: Playground 5 | path: /playground 6 | --- 7 | 8 | # ProDescriptions Playground 9 | 10 | 11 | -------------------------------------------------------------------------------- /docs/playground/pro-descriptions.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ProDescriptions 3 | nav: 4 | title: Playground 5 | path: /playground 6 | --- 7 | 8 | # ProDescriptions Playground 9 | 10 | 11 | -------------------------------------------------------------------------------- /docs/playground/pro-form.en-US.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ProForm 3 | nav: 4 | title: Playground 5 | path: /playground 6 | --- 7 | 8 | # Form Playground 9 | 10 | ## Form 的 layout 切换 11 | 12 | ProForm 的主要功能是预设了很多 layout,如果需要切换只需要改变外面包裹的 Layout 即可,以下是个 demo。 13 | 14 | 15 | 16 | ## FormList 17 | 18 | 19 | -------------------------------------------------------------------------------- /docs/playground/pro-form.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ProForm 3 | atomId: ProForm 4 | nav: 5 | title: Playground 6 | path: /playground 7 | --- 8 | 9 | # Form Playground 10 | 11 | ## Form 的 layout 切换 12 | 13 | ProForm 的主要功能是预设了很多 layout,如果需要切换只需要改变外面包裹的 Layout 即可,以下是个 demo。 14 | 15 | 16 | 17 | ## FormList 18 | 19 | 20 | -------------------------------------------------------------------------------- /docs/playground/pro-layout.en-US.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ProLayout 3 | nav: 4 | title: Playground 5 | path: /playground 6 | --- 7 | 8 | # Layout Playground 9 | 10 | ## Layout 自定义 11 | 12 | 13 | 14 | ## 水印自定义 15 | 16 | 17 | -------------------------------------------------------------------------------- /docs/playground/pro-layout.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ProLayout 3 | atomId: ProLayout 4 | nav: 5 | title: Playground 6 | path: /playground 7 | --- 8 | 9 | # Layout Playground 10 | 11 | ## Layout 自定义 12 | 13 | 14 | 15 | ## 水印自定义 16 | 17 | 18 | -------------------------------------------------------------------------------- /docs/playground/pro-table.en-US.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ProTable 3 | atomId: ProTable 4 | nav: 5 | title: Playground 6 | path: /playground 7 | --- 8 | 9 | # ProTable Playground 10 | 11 | 12 | -------------------------------------------------------------------------------- /docs/playground/pro-table.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ProTable 3 | atomId: ProTable 4 | nav: 5 | title: Playground 6 | path: /playground 7 | --- 8 | 9 | # ProTable Playground 10 | 11 | 12 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "independent", 3 | "npmClient": "pnpm", 4 | "useWorkspaces": true, 5 | "changelog": { 6 | "repo": "ant-design/pro-components", 7 | "cacheDir": ".changelog" 8 | }, 9 | "ignoreChanges": [ 10 | "**/*.md", 11 | "**/*.test.ts", 12 | "**/*.e2e.ts", 13 | "**/demos/**", 14 | "**/fixtures/**", 15 | "**/dist/**", 16 | "**/lib/**", 17 | "**/es/**", 18 | "**/test/**" 19 | ], 20 | "packages": ["packages/*"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/card/.fatherrc.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'father'; 2 | 3 | export default defineConfig({ 4 | extends: '../../.fatherrc.base.ts', 5 | }); 6 | -------------------------------------------------------------------------------- /packages/card/README.md: -------------------------------------------------------------------------------- 1 | # @ant-design/pro-card 2 | 3 | > @ant-design/pro-card. 4 | 5 | See our website [@ant-design/pro-card](https://procomponent.ant.design/) for more information. 6 | 7 | ## Install 8 | 9 | Using npm: 10 | 11 | ```bash 12 | $ npm install --save @ant-design/pro-card 13 | ``` 14 | 15 | or using yarn: 16 | 17 | ```bash 18 | $ yarn add @ant-design/pro-card 19 | ``` 20 | -------------------------------------------------------------------------------- /packages/card/src/ProCard.tsx: -------------------------------------------------------------------------------- 1 | import type { PropsWithChildren } from 'react'; 2 | import Card from './components/Card'; 3 | import Divider from './components/Divider'; 4 | import TabPane from './components/TabPane'; 5 | import type { CardProps, CardType } from './typing'; 6 | 7 | export type ProCardProps = CardProps; 8 | 9 | export type ProCardType = CardType & { 10 | isProCard: boolean; 11 | Divider: typeof Divider; 12 | TabPane: typeof TabPane; 13 | Group: typeof Group; 14 | }; 15 | 16 | const Group = (props: PropsWithChildren) => ( 17 | 18 | ); 19 | 20 | // 当前不对底层 Card 做封装,仅挂载子组件,直接导出 21 | // @ts-ignore 22 | const ProCard: ProCardType = Card; 23 | 24 | ProCard.isProCard = true; 25 | ProCard.Divider = Divider; 26 | ProCard.TabPane = TabPane; 27 | ProCard.Group = Group; 28 | 29 | export default ProCard; 30 | -------------------------------------------------------------------------------- /packages/card/src/components/Actions/index.tsx: -------------------------------------------------------------------------------- 1 | import classNames from 'classnames'; 2 | import React from 'react'; 3 | import useStyle from './style'; 4 | 5 | export type ProCardActionsProps = { 6 | /** 7 | * 自定义前缀 8 | * 9 | * @ignore 10 | */ 11 | prefixCls?: string; 12 | /** 操作按钮 */ 13 | actions?: React.ReactNode[] | React.ReactNode; 14 | }; 15 | 16 | const ProCardActions: React.FC = (props) => { 17 | const { actions, prefixCls } = props; 18 | const { wrapSSR, hashId } = useStyle(prefixCls); 19 | if (Array.isArray(actions) && actions?.length) { 20 | return wrapSSR( 21 |
    22 | {actions.map((action, index) => ( 23 | // eslint-disable-next-line react/no-array-index-key 24 |
  • 29 | {action} 30 |
  • 31 | ))} 32 |
, 33 | ); 34 | } 35 | return wrapSSR( 36 |
    {actions}
, 37 | ); 38 | }; 39 | 40 | export default ProCardActions; 41 | -------------------------------------------------------------------------------- /packages/card/src/components/CheckCard/demos/avatar.tsx: -------------------------------------------------------------------------------- 1 | import { UserOutlined } from '@ant-design/icons'; 2 | import { CheckCard } from '@ant-design/pro-components'; 3 | import { Avatar } from 'antd'; 4 | 5 | export default () => ( 6 | } 12 | size="large" 13 | /> 14 | } 15 | /> 16 | ); 17 | -------------------------------------------------------------------------------- /packages/card/src/components/CheckCard/demos/basic.tsx: -------------------------------------------------------------------------------- 1 | /** Title: 基本使用 */ 2 | 3 | import { CheckCard } from '@ant-design/pro-components'; 4 | 5 | export default () => ( 6 | { 11 | console.log('checked', checked); 12 | }} 13 | defaultChecked 14 | onClick={() => { 15 | console.log('clicked'); 16 | }} 17 | /> 18 | ); 19 | -------------------------------------------------------------------------------- /packages/card/src/components/CheckCard/demos/compose.tsx: -------------------------------------------------------------------------------- 1 | import { CheckCard } from '@ant-design/pro-components'; 2 | 3 | export default () => ( 4 | <> 5 |

只有图片时

6 | 7 | 8 |

只有图片和描述时

9 | 13 |

只有标题和描述时

14 | 18 |

只有标题和图片

19 | 23 |

只有标题

24 | 25 |

只有描述时

26 | 27 | 28 | ); 29 | -------------------------------------------------------------------------------- /packages/card/src/components/CheckCard/demos/custom.tsx: -------------------------------------------------------------------------------- 1 | import { CheckCard } from '@ant-design/pro-components'; 2 | 3 | export default () => ( 4 | 9 | ); 10 | -------------------------------------------------------------------------------- /packages/card/src/components/CheckCard/demos/defaultChecked.tsx: -------------------------------------------------------------------------------- 1 | import { CheckCard } from '@ant-design/pro-components'; 2 | 3 | export default () => ( 4 | { 9 | console.log('checked', checked); 10 | }} 11 | /> 12 | ); 13 | -------------------------------------------------------------------------------- /packages/card/src/components/CheckCard/demos/description.tsx: -------------------------------------------------------------------------------- 1 | import { CheckCard } from '@ant-design/pro-components'; 2 | import { Typography } from 'antd'; 3 | 4 | const { Paragraph } = Typography; 5 | 6 | export default () => ( 7 | <> 8 | 13 | 选择一个由流程编排提供的典型用户案例,可以从中学习到流程编排很多设计理念。 14 | { 17 | e.stopPropagation(); 18 | }} 19 | > 20 | 查看详情 21 | 22 | 23 | } 24 | /> 25 | 30 | 选择一个由流程编排提供的典型用户案例,可以从中学习到流程编排很多设计理念。 31 | 32 | } 33 | /> 34 | 35 | ); 36 | -------------------------------------------------------------------------------- /packages/card/src/components/CheckCard/demos/disabled.tsx: -------------------------------------------------------------------------------- 1 | import { CheckCard } from '@ant-design/pro-components'; 2 | 3 | export default () => ( 4 | <> 5 |
6 |

部分不可用

7 | 12 | 18 | 25 |
26 |
27 |

整体不可用

28 | 29 | 30 | 31 | 32 |
33 | 34 | ); 35 | -------------------------------------------------------------------------------- /packages/card/src/components/CheckCard/demos/extra.tsx: -------------------------------------------------------------------------------- 1 | import { EllipsisOutlined } from '@ant-design/icons'; 2 | import { CheckCard } from '@ant-design/pro-components'; 3 | import { Dropdown, message } from 'antd'; 4 | 5 | export default () => ( 6 | { 15 | domEvent.stopPropagation(); 16 | message.info('menu click'); 17 | }, 18 | items: [ 19 | { 20 | label: '菜单', 21 | key: '1', 22 | }, 23 | { 24 | label: '列表', 25 | key: '2', 26 | }, 27 | { 28 | label: '表单', 29 | key: '3', 30 | }, 31 | ], 32 | }} 33 | > 34 | e.stopPropagation()} 37 | /> 38 | 39 | } 40 | /> 41 | ); 42 | -------------------------------------------------------------------------------- /packages/card/src/components/CheckCard/demos/grid.tsx: -------------------------------------------------------------------------------- 1 | import { CheckCard } from '@ant-design/pro-components'; 2 | import { Col, Row } from 'antd'; 3 | 4 | export default () => ( 5 | 6 | 7 | 8 | 13 | 14 | 15 | 20 | 21 | 22 | 27 | 28 | 29 | 30 | ); 31 | -------------------------------------------------------------------------------- /packages/card/src/components/CheckCard/demos/image.tsx: -------------------------------------------------------------------------------- 1 | import { CheckCard } from '@ant-design/pro-components'; 2 | 3 | export default () => ( 4 | <> 5 | 12 | } 13 | /> 14 | 19 | 20 | ); 21 | -------------------------------------------------------------------------------- /packages/card/src/components/CheckCard/demos/loading.tsx: -------------------------------------------------------------------------------- 1 | import { CheckCard } from '@ant-design/pro-components'; 2 | 3 | export default () => ; 4 | -------------------------------------------------------------------------------- /packages/card/src/components/CheckCard/demos/single.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * title: 单选模式 3 | */ 4 | 5 | import { CheckCard } from '@ant-design/pro-components'; 6 | 7 | export default () => ( 8 | { 10 | console.log('value', value); 11 | }} 12 | defaultValue="A" 13 | > 14 | 15 | 16 | 22 | 23 | ); 24 | -------------------------------------------------------------------------------- /packages/card/src/components/CheckCard/demos/size.tsx: -------------------------------------------------------------------------------- 1 | import { CheckCard } from '@ant-design/pro-components'; 2 | import { Radio } from 'antd'; 3 | import { useState } from 'react'; 4 | 5 | export default () => { 6 | const [size, setSize] = useState('default' as 'default'); 7 | return ( 8 | <> 9 |
10 | setSize(e.target.value)}> 11 | Large 12 | Default 13 | Small 14 | 15 |
16 | 21 | 22 | ); 23 | }; 24 | -------------------------------------------------------------------------------- /packages/card/src/components/CheckCard/demos/title.tsx: -------------------------------------------------------------------------------- 1 | import { AppstoreOutlined } from '@ant-design/icons'; 2 | import { CheckCard } from '@ant-design/pro-components'; 3 | import { Tag } from 'antd'; 4 | 5 | export default () => ( 6 | <> 7 | 10 | 11 | 示例 12 | blue 13 | 14 | } 15 | description="选择一个由流程编排提供的典型用户案例,可以从中学习到流程编排很多设计理念" 16 | /> 17 | 21 | 22 | ); 23 | -------------------------------------------------------------------------------- /packages/card/src/components/Divider/index.tsx: -------------------------------------------------------------------------------- 1 | import { ConfigProvider } from 'antd'; 2 | 3 | import classNames from 'classnames'; 4 | import React, { useContext } from 'react'; 5 | import useStyle from './style'; 6 | export type ProCardDividerProps = { 7 | /** 8 | * 样式 9 | * 10 | * @ignore 11 | */ 12 | style?: React.CSSProperties; 13 | /** 14 | * ClassName 15 | * 16 | * @ignore 17 | */ 18 | className?: string; 19 | /** 20 | * 布局类型 21 | * 22 | * @default vertical 23 | */ 24 | type?: 'horizontal' | 'vertical'; 25 | }; 26 | 27 | const ProCardDivider: React.FC = (props) => { 28 | const { getPrefixCls } = useContext(ConfigProvider.ConfigContext); 29 | const proCardPrefixCls = getPrefixCls('pro-card'); 30 | const prefixCls = `${proCardPrefixCls}-divider`; 31 | const { wrapSSR, hashId } = useStyle(proCardPrefixCls); 32 | 33 | const { className, style = {}, type } = props; 34 | 35 | const classString = classNames(prefixCls, className, hashId, { 36 | [`${prefixCls}-${type}`]: type, 37 | }); 38 | 39 | return wrapSSR(
); 40 | }; 41 | 42 | export default ProCardDivider; 43 | -------------------------------------------------------------------------------- /packages/card/src/components/Operation/index.tsx: -------------------------------------------------------------------------------- 1 | import { ConfigProvider } from 'antd'; 2 | import classNames from 'classnames'; 3 | import React, { useContext } from 'react'; 4 | import { useStyle } from './style'; 5 | 6 | export interface ProCardOperationProps { 7 | /** 8 | * 样式 9 | * 10 | * @ignore 11 | */ 12 | style?: React.CSSProperties; 13 | /** 14 | * ClassName 15 | * 16 | * @ignore 17 | */ 18 | className?: string; 19 | 20 | children?: any; 21 | } 22 | 23 | const ProCardOperation: React.FC = (props) => { 24 | const { className, style = {}, children } = props; 25 | 26 | const { getPrefixCls } = useContext(ConfigProvider.ConfigContext); 27 | const prefixCls = getPrefixCls('pro-card-operation'); 28 | const { wrapSSR, hashId } = useStyle(prefixCls); 29 | const classString = classNames(prefixCls, className, hashId); 30 | 31 | return wrapSSR( 32 |
33 | {children} 34 |
, 35 | ); 36 | }; 37 | 38 | export default ProCardOperation; 39 | -------------------------------------------------------------------------------- /packages/card/src/components/Operation/style.ts: -------------------------------------------------------------------------------- 1 | import type { GenerateStyle, ProAliasToken } from '@ant-design/pro-provider'; 2 | import { useStyle as useAntdStyle } from '@ant-design/pro-provider'; 3 | 4 | export interface ProToken extends ProAliasToken { 5 | componentCls: string; 6 | } 7 | 8 | const genProStyle: GenerateStyle = (token) => { 9 | return { 10 | [token.componentCls]: { 11 | display: 'flex', 12 | flexDirection: 'column', 13 | justifyContent: 'flex-end', 14 | marginBlock: token.marginLG, 15 | marginInline: 0, 16 | color: token.colorText, 17 | fontWeight: '500', 18 | fontSize: '20px', 19 | lineHeight: '38px', 20 | }, 21 | }; 22 | }; 23 | 24 | export function useStyle(prefixCls: string) { 25 | return useAntdStyle('ProCardOperation', (token) => { 26 | const proToken: ProToken = { 27 | ...token, 28 | componentCls: `.${prefixCls}`, 29 | }; 30 | 31 | return [genProStyle(proToken)]; 32 | }); 33 | } 34 | -------------------------------------------------------------------------------- /packages/card/src/components/StatisticCard/demos/basic.tsx: -------------------------------------------------------------------------------- 1 | import { EllipsisOutlined, RightOutlined } from '@ant-design/icons'; 2 | import { StatisticCard } from '@ant-design/pro-components'; 3 | import { Space, theme } from 'antd'; 4 | 5 | const { Statistic } = StatisticCard; 6 | 7 | export default () => { 8 | const { token } = theme.useToken(); 9 | return ( 10 | 13 | Department One 14 | 15 | 16 | } 17 | extra={} 18 | statistic={{ 19 | value: 1102893, 20 | prefix: '¥', 21 | description: ( 22 | 23 | 24 | 25 | 26 | ), 27 | }} 28 | chart={ 29 | <> 30 | chart 35 | 36 | } 37 | style={{ width: 268 }} 38 | /> 39 | ); 40 | }; 41 | -------------------------------------------------------------------------------- /packages/card/src/components/StatisticCard/demos/chart.tsx: -------------------------------------------------------------------------------- 1 | import { EllipsisOutlined } from '@ant-design/icons'; 2 | import { StatisticCard } from '@ant-design/pro-components'; 3 | 4 | export default () => { 5 | return ( 6 | } 11 | chart={ 12 | Bar Chart 17 | } 18 | /> 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/card/src/components/StatisticCard/demos/fomula.tsx: -------------------------------------------------------------------------------- 1 | import { StatisticCard } from '@ant-design/pro-components'; 2 | 3 | const { Operation } = StatisticCard; 4 | 5 | export default () => { 6 | return ( 7 | 8 | 14 | = 15 | 21 | + 22 | 28 | + 29 | 35 | 36 | ); 37 | }; 38 | -------------------------------------------------------------------------------- /packages/card/src/components/StatisticCard/demos/footer.tsx: -------------------------------------------------------------------------------- 1 | import { EllipsisOutlined } from '@ant-design/icons'; 2 | import { StatisticCard } from '@ant-design/pro-components'; 3 | 4 | const { Statistic } = StatisticCard; 5 | 6 | export default () => { 7 | return ( 8 | } 11 | statistic={{ 12 | value: 86.2, 13 | suffix: '分', 14 | description: , 15 | }} 16 | chart={ 17 | 进度条 22 | } 23 | footer={ 24 | <> 25 | 31 | 37 | 38 | } 39 | style={{ width: 250 }} 40 | /> 41 | ); 42 | }; 43 | -------------------------------------------------------------------------------- /packages/card/src/components/StatisticCard/demos/horizontal-left.tsx: -------------------------------------------------------------------------------- 1 | import { StatisticCard } from '@ant-design/pro-components'; 2 | 3 | const { Statistic } = StatisticCard; 4 | 5 | export default () => { 6 | return ( 7 | 16 | 17 | 18 | 19 | ), 20 | }} 21 | style={{ maxWidth: 584 }} 22 | chart={ 23 | Line Chart 28 | } 29 | /> 30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /packages/card/src/components/StatisticCard/demos/horizontal.tsx: -------------------------------------------------------------------------------- 1 | import { StatisticCard } from '@ant-design/pro-components'; 2 | 3 | const { Statistic } = StatisticCard; 4 | 5 | export default () => { 6 | return ( 7 | 16 | 17 | 18 | 19 | ), 20 | }} 21 | style={{ width: 584 }} 22 | chart={ 23 | Line Chart 28 | } 29 | /> 30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /packages/card/src/components/StatisticCard/demos/status.tsx: -------------------------------------------------------------------------------- 1 | import { StatisticCard } from '@ant-design/pro-components'; 2 | 3 | const { Divider } = StatisticCard; 4 | 5 | export default () => { 6 | return ( 7 | 8 | 15 | 16 | 23 | 30 | 37 | 44 | 45 | ); 46 | }; 47 | -------------------------------------------------------------------------------- /packages/card/src/components/StatisticCard/demos/trend.tsx: -------------------------------------------------------------------------------- 1 | import { StatisticCard } from '@ant-design/pro-components'; 2 | 3 | const { Statistic } = StatisticCard; 4 | 5 | export default () => { 6 | return ( 7 | <> 8 | 9 | 10 | 11 | 12 | 13 | 14 | ); 15 | }; 16 | -------------------------------------------------------------------------------- /packages/card/src/demos/bordered.tsx: -------------------------------------------------------------------------------- 1 | import { ProCard } from '@ant-design/pro-components'; 2 | 3 | export default () => { 4 | return ( 5 | 12 | Content 13 | 14 | ); 15 | }; 16 | -------------------------------------------------------------------------------- /packages/card/src/demos/group.tsx: -------------------------------------------------------------------------------- 1 | import { ProCard } from '@ant-design/pro-components'; 2 | 3 | export default () => { 4 | return ( 5 | <> 6 | 7 | 8 | Card Content 9 | 10 | 11 | Card Content 12 | 13 | 14 | Card Content 15 | 16 | 17 | 18 | ); 19 | }; 20 | -------------------------------------------------------------------------------- /packages/card/src/demos/gutter.tsx: -------------------------------------------------------------------------------- 1 | import { ProCard } from '@ant-design/pro-components'; 2 | 3 | export default () => { 4 | return ( 5 | <> 6 | 7 | 8 | 300px 9 | 10 | Auto 11 | 12 | 13 | 17 | Responsive 18 | Responsive 19 | Responsive 20 | 21 | 22 | 23 | Auto 24 | Auto 25 | Auto 26 | 27 | 28 | ); 29 | }; 30 | -------------------------------------------------------------------------------- /packages/card/src/demos/headerBordered.tsx: -------------------------------------------------------------------------------- 1 | import { ProCard } from '@ant-design/pro-components'; 2 | 3 | export default () => { 4 | return ( 5 | 12 | Content 13 | 14 | ); 15 | }; 16 | -------------------------------------------------------------------------------- /packages/card/src/demos/headless.tsx: -------------------------------------------------------------------------------- 1 | import { ProCard } from '@ant-design/pro-components'; 2 | 3 | export default () => { 4 | return Content; 5 | }; 6 | -------------------------------------------------------------------------------- /packages/card/src/demos/hoverable.tsx: -------------------------------------------------------------------------------- 1 | import { ProCard } from '@ant-design/pro-components'; 2 | 3 | export default () => { 4 | return ( 5 | <> 6 | 7 | Content 8 | 9 | 10 | ); 11 | }; 12 | -------------------------------------------------------------------------------- /packages/card/src/demos/inner.tsx: -------------------------------------------------------------------------------- 1 | import { ProCard } from '@ant-design/pro-components'; 2 | 3 | export default () => { 4 | return ( 5 | <> 6 | 12 | 13 | Inner Card Content 14 | 15 | 16 | Inner Card Content 17 | 18 | 19 | 20 | 28 | 29 | Inner Card Content 30 | 31 | 32 | Inner Card Content 33 | 34 | 35 | 36 | ); 37 | }; 38 | -------------------------------------------------------------------------------- /packages/card/src/demos/layout.tsx: -------------------------------------------------------------------------------- 1 | import { ProCard } from '@ant-design/pro-components'; 2 | 3 | export default () => { 4 | return ( 5 | <> 6 | 13 |
123
14 |
456
15 |
16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/card/src/demos/loading.tsx: -------------------------------------------------------------------------------- 1 | import { ProCard } from '@ant-design/pro-components'; 2 | 3 | export default () => { 4 | return ( 5 | <> 6 | 7 | Content 8 | 9 | 10 | 15 | Content 16 | 17 | 18 | Loading
} 22 | style={{ maxWidth: 300, marginBlockStart: 16 }} 23 | > 24 | Content 25 | 26 | 27 | ); 28 | }; 29 | -------------------------------------------------------------------------------- /packages/card/src/demos/multipleLine.tsx: -------------------------------------------------------------------------------- 1 | import { ProCard } from '@ant-design/pro-components'; 2 | 3 | export default () => { 4 | return ( 5 | <> 6 | 12 | 17 | Col 18 | 19 | 24 | Col 25 | 26 | 31 | Col 32 | 33 | 38 | Col 39 | 40 | 41 | 42 | ); 43 | }; 44 | -------------------------------------------------------------------------------- /packages/card/src/demos/split2.tsx: -------------------------------------------------------------------------------- 1 | import { ProCard } from '@ant-design/pro-components'; 2 | import RcResizeObserver from 'rc-resize-observer'; 3 | import { useState } from 'react'; 4 | 5 | export default () => { 6 | const [responsive, setResponsive] = useState(false); 7 | return ( 8 | { 11 | setResponsive(offset.width < 596); 12 | }} 13 | > 14 | 21 | 22 |
Left Content
23 |
24 | 25 |
Right Content
26 |
27 |
28 |
29 | ); 30 | }; 31 | -------------------------------------------------------------------------------- /packages/card/src/demos/split23.tsx: -------------------------------------------------------------------------------- 1 | import { ProCard } from '@ant-design/pro-components'; 2 | 3 | export default () => { 4 | return ( 5 | 6 | 7 | Left Content 8 | 9 | 10 |
Right Content
11 |
12 |
13 | ); 14 | }; 15 | -------------------------------------------------------------------------------- /packages/card/src/demos/tabs-card.tsx: -------------------------------------------------------------------------------- 1 | import { ProCard } from '@ant-design/pro-components'; 2 | 3 | export default () => { 4 | return ( 5 | 10 | 11 | Content One 12 | 13 | 14 | Content Two 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/card/src/index.tsx: -------------------------------------------------------------------------------- 1 | import type { 2 | CheckCardGroupProps, 3 | CheckCardProps, 4 | } from './components/CheckCard'; 5 | import CheckCard from './components/CheckCard'; 6 | import type { StatisticProps } from './components/Statistic'; 7 | import Statistic from './components/Statistic'; 8 | import type { 9 | StatisticCardProps, 10 | StatisticsCardProps, 11 | } from './components/StatisticCard'; 12 | import StatisticCard from './components/StatisticCard'; 13 | import type { ProCardProps } from './ProCard'; 14 | import ProCard from './ProCard'; 15 | import type { ProCardTabsProps } from './typing'; 16 | 17 | import 'antd/lib/card/style'; 18 | 19 | export { CheckCard, ProCard, Statistic, StatisticCard }; 20 | export type { 21 | CheckCardGroupProps, 22 | CheckCardProps, 23 | ProCardProps, 24 | ProCardTabsProps, 25 | StatisticCardProps, 26 | StatisticProps, 27 | StatisticsCardProps, 28 | }; 29 | 30 | export default ProCard; 31 | -------------------------------------------------------------------------------- /packages/card/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./", 4 | "target": "esnext", 5 | "module": "ESNext", 6 | "moduleResolution": "node", 7 | "jsx": "react-jsx", 8 | "esModuleInterop": true, 9 | "experimentalDecorators": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "declaration": true, 12 | "skipLibCheck": true, 13 | "resolveJsonModule": true, 14 | "paths": { 15 | "@ant-design/pro-components": ["../../packages/components/src/index.tsx"], 16 | "@ant-design/pro-provider": ["../../packages/provider/src/index.tsx"], 17 | "@ant-design/pro-utils": ["../../packages/utils/src/index.tsx"] 18 | } 19 | }, 20 | "include": ["./src"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/components/.fatherrc.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'father'; 2 | 3 | export default defineConfig({ 4 | extends: '../../.fatherrc.base.ts', 5 | umd: { 6 | name: 'ProComponents', 7 | output: 'dist', 8 | externals: { 9 | react: 'React', 10 | 'react-dom': 'ReactDOM', 11 | '^/antd/.*': 'antd', 12 | '^/dayjs/.*': 'dayjs', 13 | }, 14 | }, 15 | }); 16 | -------------------------------------------------------------------------------- /packages/components/README.md: -------------------------------------------------------------------------------- 1 | # @ant-design/pro-components 2 | 3 | > @ant-design/pro-components. 4 | 5 | See our website [@ant-design/pro-components](https://procomponent.ant.design/) for more information. 6 | 7 | ## Install 8 | 9 | Using npm: 10 | 11 | ```bash 12 | $ npm install --save @ant-design/pro-components 13 | ``` 14 | 15 | or using yarn: 16 | 17 | ```bash 18 | $ yarn add @ant-design/pro-components 19 | ``` 20 | -------------------------------------------------------------------------------- /packages/components/src/index.tsx: -------------------------------------------------------------------------------- 1 | export * from '@ant-design/pro-card'; 2 | export * from '@ant-design/pro-descriptions'; 3 | export * from '@ant-design/pro-field'; 4 | export * from '@ant-design/pro-form'; 5 | export * from '@ant-design/pro-layout'; 6 | export * from '@ant-design/pro-list'; 7 | export * from '@ant-design/pro-provider'; 8 | export * from '@ant-design/pro-skeleton'; 9 | export * from '@ant-design/pro-table'; 10 | export * from '@ant-design/pro-utils'; 11 | // @ts-ignore 12 | export * from './version'; 13 | -------------------------------------------------------------------------------- /packages/components/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./", 4 | "target": "esnext", 5 | "module": "ESNext", 6 | "moduleResolution": "node", 7 | "jsx": "react-jsx", 8 | "esModuleInterop": true, 9 | "experimentalDecorators": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "noImplicitReturns": true, 13 | "declaration": true, 14 | "skipLibCheck": true, 15 | "resolveJsonModule": true, 16 | "paths": { 17 | "@ant-design/pro-layout": ["../../packages/layout/src/index.tsx"], 18 | "@ant-design/pro-form": ["../../packages/form/src/index.tsx"], 19 | "@ant-design/pro-table": ["../../packages/table/src/index.tsx"], 20 | "@ant-design/pro-field": ["../../packages/field/src/index.tsx"], 21 | "@ant-design/pro-skeleton": ["../../packages/skeleton/src/index.tsx"], 22 | "@ant-design/pro-list": ["../../packages/list/src/index.tsx"], 23 | "@ant-design/pro-provider": ["../../packages/provider/src/index.tsx"], 24 | "@ant-design/pro-descriptions": [ 25 | "../../packages/descriptions/src/index.tsx" 26 | ], 27 | "@ant-design/pro-utils": ["../../packages/utils/src/index.tsx"], 28 | "@ant-design/pro-card": ["../../packages/card/src/index.tsx"] 29 | } 30 | }, 31 | "include": ["./src"] 32 | } 33 | -------------------------------------------------------------------------------- /packages/descriptions/.fatherrc.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'father'; 2 | 3 | export default defineConfig({ 4 | extends: '../../.fatherrc.base.ts', 5 | }); 6 | -------------------------------------------------------------------------------- /packages/descriptions/src/demos/base.demo-test.tsx: -------------------------------------------------------------------------------- 1 | import { ProDescriptions } from '@ant-design/pro-components'; 2 | import { Button } from 'antd'; 3 | 4 | export default () => { 5 | return ( 6 | <> 7 | 8 | 11 | 12 | ({ 17 | data: [{ id: 1, money: 12345 }], 18 | success: true, 19 | })} 20 | columns={[ 21 | { 22 | title: () => '文本 2', 23 | key: 'text', 24 | dataIndex: 'id', 25 | }, 26 | { 27 | title: 'money', 28 | key: 'money', 29 | dataIndex: 'money', 30 | valueType: { type: 'money', showSymbol: false }, 31 | }, 32 | ]} 33 | /> 34 | 35 | ); 36 | }; 37 | -------------------------------------------------------------------------------- /packages/descriptions/src/demos/request.tsx: -------------------------------------------------------------------------------- 1 | import type { ProDescriptionsActionType } from '@ant-design/pro-components'; 2 | import { ProDescriptions } from '@ant-design/pro-components'; 3 | import { Button } from 'antd'; 4 | import { useRef } from 'react'; 5 | 6 | export default () => { 7 | const actionRef = useRef(); 8 | return ( 9 | { 13 | return Promise.resolve({ 14 | success: true, 15 | data: { id: '这是一段文本', date: '20200730', money: '12121' }, 16 | }); 17 | }} 18 | extra={} 19 | > 20 | 21 | 22 | 23 | 24 | 33 | 34 | 35 | 36 | ); 37 | }; 38 | -------------------------------------------------------------------------------- /packages/descriptions/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./", 4 | "target": "esnext", 5 | "module": "ESNext", 6 | "moduleResolution": "node", 7 | "jsx": "react-jsx", 8 | "esModuleInterop": true, 9 | "experimentalDecorators": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "noImplicitReturns": true, 13 | "declaration": true, 14 | "skipLibCheck": true, 15 | "resolveJsonModule": true, 16 | "paths": { 17 | "@ant-design/pro-form": ["../../packages/form/src/index.tsx"], 18 | "@ant-design/pro-table": ["../../packages/table/src/index.tsx"], 19 | "@ant-design/pro-field": ["../../packages/field/src/index.tsx"], 20 | "@ant-design/pro-provider": ["../../packages/provider/src/index.tsx"], 21 | "@ant-design/pro-skeleton": ["../../packages/skeleton/src/index.tsx"], 22 | "@ant-design/pro-utils": ["../../packages/utils/src/index.tsx"] 23 | } 24 | }, 25 | "include": ["./src"] 26 | } 27 | -------------------------------------------------------------------------------- /packages/field/.fatherrc.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'father'; 2 | 3 | export default defineConfig({ 4 | extends: '../../.fatherrc.base.ts', 5 | }); 6 | -------------------------------------------------------------------------------- /packages/field/README.md: -------------------------------------------------------------------------------- 1 | # @ant-design/pro-field 2 | 3 | See our website [@ant-design/pro-field](https://procomponent.ant.design/) for more information. 4 | 5 | ## Install 6 | 7 | Using npm: 8 | 9 | ```bash 10 | $ npm install --save @ant-design/pro-field 11 | ``` 12 | 13 | or using yarn: 14 | 15 | ```bash 16 | $ yarn add @ant-design/pro-field 17 | ``` 18 | -------------------------------------------------------------------------------- /packages/field/src/components/Percent/util.ts: -------------------------------------------------------------------------------- 1 | /** 获取展示符号 */ 2 | export function getSymbolByRealValue(realValue: number) { 3 | if (realValue === 0) { 4 | return null; 5 | } 6 | if (realValue > 0) { 7 | return '+'; 8 | } 9 | return '-'; 10 | } 11 | 12 | /** 获取颜色 */ 13 | export function getColorByRealValue(realValue: number /** ,color: string */) { 14 | if (realValue === 0) { 15 | return '#595959'; 16 | } 17 | return realValue > 0 ? '#ff4d4f' : '#52c41a'; 18 | } 19 | 20 | /** 获取到最后展示的数字 */ 21 | export function getRealTextWithPrecision( 22 | realValue: number, 23 | precision: number = 2, 24 | ) { 25 | return precision >= 0 ? realValue?.toFixed(precision) : realValue; 26 | } 27 | 28 | /** 29 | * 转化为数字 30 | * @copy from https://github.com/toss/es-toolkit/blob/32a183828c244d675f46810935e45dfefec81a54/src/compat/util/toNumber.ts#L19 31 | */ 32 | export function toNumber(value: any): number { 33 | if (typeof value === 'symbol' || value instanceof Symbol) { 34 | return NaN; 35 | } 36 | 37 | return Number(value); 38 | } 39 | -------------------------------------------------------------------------------- /packages/field/src/components/Rate/index.tsx: -------------------------------------------------------------------------------- 1 | import { Rate } from 'antd'; 2 | import React from 'react'; 3 | import type { ProFieldFC } from '../../index'; 4 | 5 | // 兼容代码----------- 6 | import 'antd/lib/rate/style'; 7 | //------------ 8 | 9 | /** 10 | * 评分组件 11 | * 12 | * @param 13 | */ 14 | const FieldRate: ProFieldFC<{ 15 | text: string; 16 | }> = ({ text, mode, render, renderFormItem, fieldProps }, ref) => { 17 | if (mode === 'read') { 18 | const dom = ( 19 | 20 | ); 21 | if (render) { 22 | return render(text, { mode, ...fieldProps }, <>{dom}); 23 | } 24 | return dom; 25 | } 26 | if (mode === 'edit' || mode === 'update') { 27 | const dom = ; 28 | if (renderFormItem) { 29 | return renderFormItem(text, { mode, ...fieldProps }, dom); 30 | } 31 | return dom; 32 | } 33 | return null; 34 | }; 35 | 36 | export default React.forwardRef(FieldRate); 37 | -------------------------------------------------------------------------------- /packages/field/src/components/Slider/index.tsx: -------------------------------------------------------------------------------- 1 | import { Slider } from 'antd'; 2 | import React from 'react'; 3 | import type { ProFieldFC } from '../../index'; 4 | 5 | // 兼容代码----------- 6 | import 'antd/lib/slider/style'; 7 | //------------ 8 | /** 9 | * 评分组件 10 | * 11 | * @param 12 | */ 13 | const FieldSlider: ProFieldFC<{ 14 | text: string; 15 | }> = ({ text, mode, render, renderFormItem, fieldProps }, ref) => { 16 | if (mode === 'read') { 17 | const dom = text; 18 | if (render) { 19 | return render(text, { mode, ...fieldProps }, <>{dom}); 20 | } 21 | return <>{dom}; 22 | } 23 | if (mode === 'edit' || mode === 'update') { 24 | const dom = ( 25 | 33 | ); 34 | if (renderFormItem) { 35 | return renderFormItem(text, { mode, ...fieldProps }, dom); 36 | } 37 | return dom; 38 | } 39 | return null; 40 | }; 41 | 42 | export default React.forwardRef(FieldSlider); 43 | -------------------------------------------------------------------------------- /packages/field/src/components/field.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ProField - 原子组件 3 | --- 4 | 5 | # ProField 6 | 7 | > 该组件为内部组件,请勿直接使用。 8 | 9 | 原子信息组件,统一 ProForm、ProTable、ProList、Filter 等组件里面的字段定义。 10 | 11 | ## DEMO 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | ## API 26 | 27 | ```typescript | pure 28 | import Field from '@ant-design/pro-field'; 29 | 30 | return ; 31 | ``` 32 | 33 | ### 参数 34 | 35 | | 参数 | 说明 | 类型 | 默认值 | 36 | | --- | --- | --- | --- | 37 | | text | 需要格式化的值 | any | - | 38 | | valueType | 格式化的类型 | ValueType | - | 39 | | mode | 组件的模式 | - | - | 40 | | plain | 精简模式 | - | - | 41 | | renderFormItem | 自定义 `mode=update \| edit` 下的 dom 表现,一般用于渲染编辑框 | - | - | 42 | | render | 自定义 `mode=read` 下的 dom 表现,只是单纯的表现形式 | - | - | 43 | -------------------------------------------------------------------------------- /packages/field/src/demos/search-value-autoClearSearchValue.tsx: -------------------------------------------------------------------------------- 1 | import { ProFormSelect } from '@ant-design/pro-components'; 2 | 3 | export default function App() { 4 | return ( 5 |
6 | 39 |
40 | ); 41 | } 42 | -------------------------------------------------------------------------------- /packages/field/src/demos/select-request.tsx: -------------------------------------------------------------------------------- 1 | import { ProForm, ProFormSelect } from '@ant-design/pro-components'; 2 | 3 | function App() { 4 | return ( 5 |
6 | 7 | { 11 | console.log('请求1'); 12 | return [{ label: '选项1', value: '1' }]; 13 | }} 14 | /> 15 | 16 | 17 | { 21 | console.log('请求2'); 22 | return [{ label: '选项2', value: '2' }]; 23 | }} 24 | /> 25 | 26 |
27 | ); 28 | } 29 | 30 | export default App; 31 | -------------------------------------------------------------------------------- /packages/field/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./", 4 | "target": "esnext", 5 | "module": "ESNext", 6 | "moduleResolution": "node", 7 | "jsx": "react-jsx", 8 | "esModuleInterop": true, 9 | "experimentalDecorators": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "noImplicitReturns": true, 13 | "declaration": true, 14 | "skipLibCheck": true, 15 | "resolveJsonModule": true, 16 | "paths": { 17 | "@ant-design/pro-provider": ["../../packages/provider/src/index.tsx"], 18 | "@ant-design/pro-utils": ["../../packages/utils/src/index.tsx"] 19 | } 20 | }, 21 | "include": ["./src"] 22 | } 23 | -------------------------------------------------------------------------------- /packages/form/.fatherrc.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'father'; 2 | 3 | export default defineConfig({ 4 | extends: '../../.fatherrc.base.ts', 5 | }); 6 | -------------------------------------------------------------------------------- /packages/form/README.md: -------------------------------------------------------------------------------- 1 | # @ant-design/pro-form 2 | 3 | ## Install 4 | 5 | Using npm: 6 | 7 | ```bash 8 | $ npm install --save @ant-design/pro-form 9 | ``` 10 | 11 | or using yarn: 12 | 13 | ```bash 14 | $ yarn add @ant-design/pro-form 15 | ``` 16 | -------------------------------------------------------------------------------- /packages/form/src/BaseForm/EditOrReadOnlyContext.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export const EditOrReadOnlyContext = React.createContext<{ 4 | mode: 'edit' | 'read' | 'update'; 5 | }>({ 6 | mode: 'edit', 7 | }); 8 | -------------------------------------------------------------------------------- /packages/form/src/BaseForm/LightWrapper/style.ts: -------------------------------------------------------------------------------- 1 | import type { GenerateStyle, ProAliasToken } from '@ant-design/pro-provider'; 2 | import { useStyle as useAntdStyle } from '@ant-design/pro-provider'; 3 | 4 | export interface ProToken extends ProAliasToken { 5 | componentCls: string; 6 | } 7 | 8 | const genProStyle: GenerateStyle = (token) => { 9 | return { 10 | [`${token.componentCls}-collapse-label`]: { 11 | paddingInline: 1, 12 | paddingBlock: 1, 13 | }, 14 | [`${token.componentCls}-container`]: { 15 | [`${token.antCls}-form-item`]: { 16 | marginBlockEnd: 0, 17 | }, 18 | }, 19 | }; 20 | }; 21 | 22 | export function useStyle(prefixCls: string) { 23 | return useAntdStyle('LightWrapper', (token) => { 24 | const proToken: ProToken = { 25 | ...token, 26 | componentCls: `.${prefixCls}`, 27 | }; 28 | 29 | return [genProStyle(proToken)]; 30 | }); 31 | } 32 | -------------------------------------------------------------------------------- /packages/form/src/BaseForm/index.ts: -------------------------------------------------------------------------------- 1 | export * from './BaseForm'; 2 | export * from './createField'; 3 | export * from './LightWrapper'; 4 | -------------------------------------------------------------------------------- /packages/form/src/FieldContext.tsx: -------------------------------------------------------------------------------- 1 | import type { 2 | ProFieldProps, 3 | ProFieldValueType, 4 | SearchTransformKeyFn, 5 | } from '@ant-design/pro-utils'; 6 | import type { FormItemProps } from 'antd'; 7 | import type { NamePath } from 'antd/lib/form/interface'; 8 | import React from 'react'; 9 | import type { CommonFormProps } from './BaseForm'; 10 | import type { FieldProps, ProFormGroupProps } from './typing'; 11 | 12 | export type FiledContextProps = { 13 | fieldProps?: FieldProps; 14 | proFieldProps?: ProFieldProps; 15 | formItemProps?: FormItemProps; 16 | groupProps?: ProFormGroupProps; 17 | setFieldValueType?: ( 18 | name: NamePath, 19 | obj: { 20 | valueType?: ProFieldValueType; 21 | dateFormat?: string; 22 | /** 数据转化的地方 */ 23 | transform?: SearchTransformKeyFn; 24 | }, 25 | ) => void; 26 | /** Form 组件的类型 */ 27 | formComponentType?: string; 28 | /** 获取表单实例计数器 */ 29 | formKey?: string; 30 | 31 | /** 表单的 getPopupContainer 控制 */ 32 | getPopupContainer?: (e: HTMLElement) => ParentNode; 33 | } & Pick; 34 | 35 | const FieldContext = React.createContext({}); 36 | 37 | export { FieldContext }; 38 | 39 | export default FieldContext; 40 | -------------------------------------------------------------------------------- /packages/form/src/components/Cascader/index.tsx: -------------------------------------------------------------------------------- 1 | import type { CascaderProps } from 'antd'; 2 | import React, { useContext } from 'react'; 3 | import FieldContext from '../../FieldContext'; 4 | import type { 5 | ProFormFieldItemProps, 6 | ProFormFieldRemoteProps, 7 | } from '../../typing'; 8 | import ProField from '../Field'; 9 | /** 10 | * 级联选择框 11 | * 12 | * @param 13 | */ 14 | const ProFormCascader: React.ForwardRefRenderFunction< 15 | any, 16 | ProFormFieldItemProps> & ProFormFieldRemoteProps 17 | > = ({ fieldProps, request, params, proFieldProps, ...rest }, ref) => { 18 | const context = useContext(FieldContext); 19 | return ( 20 | 33 | ); 34 | }; 35 | 36 | export default React.forwardRef(ProFormCascader); 37 | -------------------------------------------------------------------------------- /packages/form/src/components/ColorPicker/index.tsx: -------------------------------------------------------------------------------- 1 | import type { SketchPickerProps } from '@chenshuai2144/sketch-color'; 2 | import type { PopoverProps } from 'antd'; 3 | import React from 'react'; 4 | import type { ProFormFieldItemProps } from '../../typing'; 5 | import ProFromField from '../Field'; 6 | 7 | type ColorPickerProps = SketchPickerProps & { 8 | value?: string; 9 | onChange?: (color: string) => void; 10 | }; 11 | 12 | export type ProFormColorPickerProps = 13 | ProFormFieldItemProps & { 14 | popoverProps?: PopoverProps; 15 | colors?: string[]; 16 | old?: boolean; 17 | }; 18 | /** 19 | * 数组选择组件 20 | * 21 | * @param 22 | */ 23 | const ProFormColorPicker: React.ForwardRefRenderFunction< 24 | any, 25 | ProFormColorPickerProps 26 | > = ({ fieldProps, popoverProps, proFieldProps, colors, ...rest }, ref) => { 27 | return ( 28 | 44 | ); 45 | }; 46 | 47 | export default React.forwardRef(ProFormColorPicker); 48 | -------------------------------------------------------------------------------- /packages/form/src/components/DateMonthRangePicker/index.tsx: -------------------------------------------------------------------------------- 1 | import { dateArrayFormatter } from '@ant-design/pro-utils'; 2 | import type { RangePickerProps } from 'antd/lib/date-picker'; 3 | import React, { useContext } from 'react'; 4 | import FieldContext from '../../FieldContext'; 5 | import type { ProFormFieldItemProps } from '../../typing'; 6 | import ProField from '../Field'; 7 | 8 | const valueType = 'dateMonthRange' as const; 9 | 10 | /** 11 | * 月份区间选择组件 12 | * 13 | * @param 14 | */ 15 | const DateMonthRangePicker: React.FC> = 16 | React.forwardRef(({ fieldProps, proFieldProps, ...rest }, ref) => { 17 | const context = useContext(FieldContext); 18 | return ( 19 | 31 | dateArrayFormatter(value, fieldProps?.format || 'YYYY-MM'), 32 | }} 33 | {...rest} 34 | /> 35 | ); 36 | }); 37 | 38 | export default DateMonthRangePicker; 39 | -------------------------------------------------------------------------------- /packages/form/src/components/DatePicker/DatePicker.tsx: -------------------------------------------------------------------------------- 1 | import type { DatePickerProps } from 'antd'; 2 | import React, { useContext } from 'react'; 3 | import FieldContext from '../../FieldContext'; 4 | import type { ProFormFieldItemProps } from '../../typing'; 5 | import ProFormField from '../Field'; 6 | 7 | const valueType = 'date' as const; 8 | /** 9 | * 日期选择组件 10 | * 11 | * @param 12 | */ 13 | const ProFormDatePicker: React.FC> = 14 | React.forwardRef(({ proFieldProps, fieldProps, ...rest }, ref) => { 15 | const context = useContext(FieldContext); 16 | 17 | return ( 18 | 32 | ); 33 | }); 34 | 35 | export default ProFormDatePicker; 36 | -------------------------------------------------------------------------------- /packages/form/src/components/DatePicker/MonthPicker.tsx: -------------------------------------------------------------------------------- 1 | import type { MonthPickerProps } from 'antd/lib/date-picker'; 2 | import React, { useContext } from 'react'; 3 | import FieldContext from '../../FieldContext'; 4 | import type { ProFormFieldItemProps } from '../../typing'; 5 | import ProField from '../Field'; 6 | 7 | const valueType = 'dateMonth' as const; 8 | /** 9 | * 周选择组件 10 | * 11 | * @param 12 | */ 13 | const ProFormDatePickerMonth: React.FC< 14 | ProFormFieldItemProps 15 | > = React.forwardRef(({ proFieldProps, fieldProps, ...rest }, ref) => { 16 | const context = useContext(FieldContext); 17 | return ( 18 | 32 | ); 33 | }); 34 | 35 | export default ProFormDatePickerMonth; 36 | -------------------------------------------------------------------------------- /packages/form/src/components/DatePicker/QuarterPicker.tsx: -------------------------------------------------------------------------------- 1 | import type { DatePickerProps } from 'antd'; 2 | import React, { useContext } from 'react'; 3 | import FieldContext from '../../FieldContext'; 4 | import type { ProFormFieldItemProps } from '../../typing'; 5 | import ProField from '../Field'; 6 | 7 | const valueType = 'dateQuarter' as const; 8 | /** 9 | * 周选择组件 10 | * 11 | * @param 12 | */ 13 | const ProFormDatePickerQuarter: React.FC< 14 | ProFormFieldItemProps 15 | > = React.forwardRef(({ fieldProps, ...rest }, ref: any) => { 16 | const context = useContext(FieldContext); 17 | 18 | return ( 19 | 32 | ); 33 | }); 34 | 35 | export default ProFormDatePickerQuarter; 36 | -------------------------------------------------------------------------------- /packages/form/src/components/DatePicker/WeekPicker.tsx: -------------------------------------------------------------------------------- 1 | import type { WeekPickerProps } from 'antd/lib/date-picker'; 2 | import React, { useContext } from 'react'; 3 | import FieldContext from '../../FieldContext'; 4 | import type { ProFormFieldItemProps } from '../../typing'; 5 | import ProField from '../Field'; 6 | 7 | const valueType = 'dateWeek' as const; 8 | /** 9 | * 周选择组件 10 | * 11 | * @param 12 | */ 13 | const ProFormDatePickerWeek: React.FC> = 14 | React.forwardRef(({ proFieldProps, fieldProps, ...rest }, ref: any) => { 15 | const context = useContext(FieldContext); 16 | 17 | return ( 18 | 32 | ); 33 | }); 34 | 35 | export default ProFormDatePickerWeek; 36 | -------------------------------------------------------------------------------- /packages/form/src/components/DatePicker/YearPicker.tsx: -------------------------------------------------------------------------------- 1 | import type { DatePickerProps } from 'antd'; 2 | import React, { useContext } from 'react'; 3 | import FieldContext from '../../FieldContext'; 4 | import type { ProFormFieldItemProps } from '../../typing'; 5 | import ProFormField from '../Field'; 6 | 7 | const valueType = 'dateYear' as const; 8 | /** 9 | * 周选择组件 10 | * 11 | * @param 12 | */ 13 | const ProFormDatePickerYear: React.FC> = 14 | React.forwardRef(({ proFieldProps, fieldProps, ...rest }, ref: any) => { 15 | const context = useContext(FieldContext); 16 | 17 | return ( 18 | 32 | ); 33 | }); 34 | 35 | export default ProFormDatePickerYear; 36 | -------------------------------------------------------------------------------- /packages/form/src/components/DatePicker/index.tsx: -------------------------------------------------------------------------------- 1 | import ProFormDatePicker from './DatePicker'; 2 | import ProFormDatePickerMonth from './MonthPicker'; 3 | import ProFormDatePickerQuarter from './QuarterPicker'; 4 | import ProFormDatePickerWeek from './WeekPicker'; 5 | import ProFormDatePickerYear from './YearPicker'; 6 | 7 | const ExportComponent = ProFormDatePicker as typeof ProFormDatePicker & { 8 | Week: typeof ProFormDatePickerWeek; 9 | Month: typeof ProFormDatePickerMonth; 10 | Quarter: typeof ProFormDatePickerQuarter; 11 | Year: typeof ProFormDatePickerYear; 12 | }; 13 | 14 | ExportComponent.Week = ProFormDatePickerWeek; 15 | ExportComponent.Month = ProFormDatePickerMonth; 16 | ExportComponent.Quarter = ProFormDatePickerQuarter; 17 | ExportComponent.Year = ProFormDatePickerYear; 18 | // @ts-ignore 19 | // eslint-disable-next-line no-param-reassign 20 | ExportComponent.displayName = 'ProFormComponent'; 21 | 22 | export default ExportComponent; 23 | -------------------------------------------------------------------------------- /packages/form/src/components/DateQuarterRangePicker/index.tsx: -------------------------------------------------------------------------------- 1 | import { dateArrayFormatter } from '@ant-design/pro-utils'; 2 | import type { RangePickerProps } from 'antd/lib/date-picker'; 3 | import React, { useContext } from 'react'; 4 | import FieldContext from '../../FieldContext'; 5 | import type { ProFormFieldItemProps } from '../../typing'; 6 | import ProField from '../Field'; 7 | 8 | const valueType = 'dateQuarterRange' as const; 9 | 10 | /** 11 | * 季度份区间选择组件 12 | * 13 | * @param 14 | */ 15 | const DateQuarterRangePicker: React.FC< 16 | ProFormFieldItemProps 17 | > = React.forwardRef(({ fieldProps, proFieldProps, ...rest }, ref) => { 18 | const context = useContext(FieldContext); 19 | return ( 20 | 32 | dateArrayFormatter(value, fieldProps?.format || 'YYYY-W'), 33 | }} 34 | {...rest} 35 | /> 36 | ); 37 | }); 38 | 39 | export default DateQuarterRangePicker; 40 | -------------------------------------------------------------------------------- /packages/form/src/components/DateRangePicker/index.tsx: -------------------------------------------------------------------------------- 1 | import { dateArrayFormatter } from '@ant-design/pro-utils'; 2 | import type { RangePickerProps } from 'antd/lib/date-picker'; 3 | import React, { useContext } from 'react'; 4 | import FieldContext from '../../FieldContext'; 5 | import type { ProFormFieldItemProps } from '../../typing'; 6 | import ProField from '../Field'; 7 | 8 | const valueType = 'dateRange' as const; 9 | 10 | /** 11 | * 日期区间选择组件 12 | * 13 | * @param 14 | */ 15 | const ProFormDateRangePicker: React.FC< 16 | ProFormFieldItemProps 17 | > = React.forwardRef(({ fieldProps, proFieldProps, ...rest }, ref) => { 18 | const context = useContext(FieldContext); 19 | return ( 20 | 32 | dateArrayFormatter(value, fieldProps?.format || 'YYYY-MM-DD'), 33 | }} 34 | {...rest} 35 | /> 36 | ); 37 | }); 38 | 39 | export default ProFormDateRangePicker; 40 | -------------------------------------------------------------------------------- /packages/form/src/components/DateTimePicker/index.tsx: -------------------------------------------------------------------------------- 1 | import type { DatePickerProps } from 'antd'; 2 | import React, { useContext } from 'react'; 3 | import FieldContext from '../../FieldContext'; 4 | import type { ProFormFieldItemProps } from '../../typing'; 5 | import ProField from '../Field'; 6 | 7 | const valueType = 'dateTime' as const; 8 | 9 | /** 10 | * 时间日期选择组件 11 | * 12 | * @param 13 | */ 14 | const ProFormDateTimePicker: React.FC> = 15 | React.forwardRef(({ fieldProps, proFieldProps, ...rest }, ref) => { 16 | const context = useContext(FieldContext); 17 | 18 | return ( 19 | 33 | ); 34 | }); 35 | 36 | export default ProFormDateTimePicker; 37 | -------------------------------------------------------------------------------- /packages/form/src/components/DateTimeRangePicker/index.tsx: -------------------------------------------------------------------------------- 1 | import { dateArrayFormatter } from '@ant-design/pro-utils'; 2 | import { RangePickerProps } from 'antd/es/date-picker'; 3 | import React, { useContext } from 'react'; 4 | import FieldContext from '../../FieldContext'; 5 | import type { ProFormFieldItemProps } from '../../typing'; 6 | import ProField from '../Field'; 7 | 8 | const valueType = 'dateTimeRange' as const; 9 | 10 | /** 11 | * 日期时间区间选择组件 12 | * 13 | * @param 14 | */ 15 | const ProFormDateTimeRangePicker: React.FC< 16 | ProFormFieldItemProps 17 | > = React.forwardRef(({ fieldProps, proFieldProps, ...rest }, ref) => { 18 | const context = useContext(FieldContext); 19 | return ( 20 | 32 | dateArrayFormatter(value, 'YYYY-MM-DD HH:mm:ss'), 33 | }} 34 | {...rest} 35 | /> 36 | ); 37 | }); 38 | 39 | export default ProFormDateTimeRangePicker; 40 | -------------------------------------------------------------------------------- /packages/form/src/components/DateWeekRangePicker/index.tsx: -------------------------------------------------------------------------------- 1 | import { dateArrayFormatter } from '@ant-design/pro-utils'; 2 | import type { RangePickerProps } from 'antd/lib/date-picker'; 3 | import React, { useContext } from 'react'; 4 | import FieldContext from '../../FieldContext'; 5 | import type { ProFormFieldItemProps } from '../../typing'; 6 | import ProField from '../Field'; 7 | 8 | const valueType = 'dateWeekRange' as const; 9 | 10 | /** 11 | * 周区间选择组件 12 | * 13 | * @param 14 | */ 15 | const DateWeekRangePicker: React.FC> = 16 | React.forwardRef(({ fieldProps, proFieldProps, ...rest }, ref) => { 17 | const context = useContext(FieldContext); 18 | return ( 19 | 31 | dateArrayFormatter(value, fieldProps?.format || 'YYYY-MM-DD'), 32 | }} 33 | {...rest} 34 | /> 35 | ); 36 | }); 37 | 38 | export default DateWeekRangePicker; 39 | -------------------------------------------------------------------------------- /packages/form/src/components/DateYearRangePicker/index.tsx: -------------------------------------------------------------------------------- 1 | import { dateArrayFormatter } from '@ant-design/pro-utils'; 2 | import type { RangePickerProps } from 'antd/lib/date-picker'; 3 | import React, { useContext } from 'react'; 4 | import FieldContext from '../../FieldContext'; 5 | import type { ProFormFieldItemProps } from '../../typing'; 6 | import ProField from '../Field'; 7 | 8 | const valueType = 'dateYearRange' as const; 9 | 10 | /** 11 | * 季度份区间选择组件 12 | * 13 | * @param 14 | */ 15 | const DateYearRangePicker: React.FC> = 16 | React.forwardRef(({ fieldProps, proFieldProps, ...rest }, ref) => { 17 | const context = useContext(FieldContext); 18 | return ( 19 | 31 | dateArrayFormatter(value, fieldProps?.format || 'YYYY'), 32 | }} 33 | {...rest} 34 | /> 35 | ); 36 | }); 37 | 38 | export default DateYearRangePicker; 39 | -------------------------------------------------------------------------------- /packages/form/src/components/Digit/index.tsx: -------------------------------------------------------------------------------- 1 | import type { InputNumberProps } from 'antd'; 2 | import React from 'react'; 3 | import type { ProFormFieldItemProps } from '../../typing'; 4 | import ProFormField from '../Field'; 5 | 6 | export type ProFormDigitProps = ProFormFieldItemProps< 7 | InputNumberProps 8 | > & { 9 | min?: InputNumberProps['min']; 10 | max?: InputNumberProps['max']; 11 | }; 12 | /** 13 | * 数组选择组件 14 | * 15 | * @param 16 | */ 17 | const ProFormDigit: React.ForwardRefRenderFunction = ( 18 | { fieldProps, min, proFieldProps, max, ...rest }, 19 | ref, 20 | ) => { 21 | return ( 22 | 38 | ); 39 | }; 40 | 41 | const ForwardRefProFormDigit = React.forwardRef(ProFormDigit); 42 | 43 | export default ForwardRefProFormDigit; 44 | -------------------------------------------------------------------------------- /packages/form/src/components/DigitRange/index.tsx: -------------------------------------------------------------------------------- 1 | import type { InputNumberProps } from 'antd'; 2 | import React from 'react'; 3 | import type { ProFormFieldItemProps } from '../../typing'; 4 | import ProFormField from '../Field'; 5 | 6 | export type Value = string | number | undefined; 7 | 8 | export type ValuePair = Value[]; 9 | 10 | export type RangeInputNumberProps = Omit< 11 | InputNumberProps, 12 | 'value' | 'defaultValue' | 'onChange' | 'placeholder' 13 | > & { 14 | value?: ValuePair; 15 | defaultValue?: ValuePair; 16 | onChange?: (value?: ValuePair) => void; 17 | }; 18 | 19 | export type ProFormDigitRangeProps = 20 | ProFormFieldItemProps & { 21 | separator?: string; 22 | separatorWidth?: number; 23 | }; 24 | /** 25 | * 数字范围选择组件 26 | * 27 | * @param 28 | */ 29 | const ProFormDigit: React.ForwardRefRenderFunction< 30 | any, 31 | ProFormDigitRangeProps 32 | > = ({ fieldProps, proFieldProps, ...rest }, ref) => { 33 | return ( 34 | 48 | ); 49 | }; 50 | 51 | export default React.forwardRef(ProFormDigit); 52 | -------------------------------------------------------------------------------- /packages/form/src/components/FieldSet/demos/upload.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | ProForm, 3 | ProFormUploadButton, 4 | ProFormUploadDragger, 5 | } from '@ant-design/pro-components'; 6 | 7 | export default () => { 8 | return ( 9 | 10 | 21 | 32 | 33 | 34 | ); 35 | }; 36 | -------------------------------------------------------------------------------- /packages/form/src/components/Money/index.tsx: -------------------------------------------------------------------------------- 1 | import type { ProFieldMoneyProps } from '@ant-design/pro-field'; 2 | import type { InputNumberProps } from 'antd'; 3 | import React from 'react'; 4 | import type { ProFormFieldItemProps } from '../../typing'; 5 | import ProFormField from '../Field'; 6 | 7 | export type ProFormMoneyProps = ProFormFieldItemProps< 8 | Omit & InputNumberProps 9 | > & { 10 | customSymbol?: string; // 自定义货币符号 11 | locale?: string; // 单独设置国际化,设置之后优先级高于全局国际化 12 | min?: InputNumberProps['min']; 13 | max?: InputNumberProps['min']; 14 | }; 15 | /** 16 | * 金额输入框 17 | * 18 | * @param 19 | */ 20 | const ProFormMoney: React.ForwardRefRenderFunction = ( 21 | { fieldProps, proFieldProps, locale, min, max, ...rest }, 22 | ref, 23 | ) => { 24 | return ( 25 | 44 | ); 45 | }; 46 | 47 | export default React.forwardRef(ProFormMoney); 48 | -------------------------------------------------------------------------------- /packages/form/src/components/QueryFilter/demos/light-filter-collapse.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | LightFilter, 3 | ProFormDateTimePicker, 4 | ProFormSelect, 5 | } from '@ant-design/pro-components'; 6 | 7 | export default () => { 8 | return ( 9 | console.log(values)} 15 | > 16 | 25 | 26 | 27 | ); 28 | }; 29 | -------------------------------------------------------------------------------- /packages/form/src/components/QueryFilter/demos/query-filter-collapsed.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | ProFormDatePicker, 3 | ProFormText, 4 | QueryFilter, 5 | } from '@ant-design/pro-components'; 6 | 7 | export default () => { 8 | return ( 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/form/src/components/QueryFilter/demos/query-filter-defaultColsNumber.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | ProFormDatePicker, 3 | ProFormText, 4 | QueryFilter, 5 | } from '@ant-design/pro-components'; 6 | 7 | export default () => { 8 | return ( 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/form/src/components/QueryFilter/demos/query-filter-defaultFormItemsNumber.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | ProFormDatePicker, 3 | ProFormText, 4 | QueryFilter, 5 | } from '@ant-design/pro-components'; 6 | 7 | export default () => { 8 | return ( 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | ); 18 | }; 19 | -------------------------------------------------------------------------------- /packages/form/src/components/QueryFilter/demos/query-filter-vertical.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | ProFormCheckbox, 3 | ProFormDatePicker, 4 | ProFormRadio, 5 | ProFormText, 6 | QueryFilter, 7 | } from '@ant-design/pro-components'; 8 | 9 | export default () => { 10 | return ( 11 | 12 | 13 | 14 | 15 | 37 | 42 | 43 | ); 44 | }; 45 | -------------------------------------------------------------------------------- /packages/form/src/components/QueryFilter/demos/query-filter.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | ProForm, 3 | ProFormDateTimePicker, 4 | ProFormText, 5 | } from '@ant-design/pro-components'; 6 | 7 | export default () => { 8 | return ( 9 | 10 | 11 | 22 | 28 | 29 | 30 | ); 31 | }; 32 | -------------------------------------------------------------------------------- /packages/form/src/components/Rate/index.tsx: -------------------------------------------------------------------------------- 1 | import type { RateProps } from 'antd'; 2 | import React from 'react'; 3 | import type { ProFormFieldItemProps } from '../../typing'; 4 | import ProField from '../Field'; 5 | /** 6 | * 评分组件 7 | * 8 | * @param 9 | */ 10 | const ProFormRate: React.ForwardRefRenderFunction< 11 | any, 12 | ProFormFieldItemProps 13 | > = ({ fieldProps, proFieldProps, ...rest }, ref) => { 14 | return ( 15 | 25 | ); 26 | }; 27 | 28 | export default React.forwardRef(ProFormRate); 29 | -------------------------------------------------------------------------------- /packages/form/src/components/SchemaForm/layoutType/Embed.tsx: -------------------------------------------------------------------------------- 1 | const Embed: React.FC<{ children: any }> = ({ children }) => <>{children}; 2 | 3 | export default Embed; 4 | -------------------------------------------------------------------------------- /packages/form/src/components/SchemaForm/layoutType/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Embed } from './Embed'; 2 | export { default as StepsForm } from './StepsForm'; 3 | -------------------------------------------------------------------------------- /packages/form/src/components/SchemaForm/valueType/dependency.tsx: -------------------------------------------------------------------------------- 1 | import { noteOnce } from 'rc-util/lib/warning'; 2 | import ProFormDependency from '../../Dependency'; 3 | import type { ItemType, ProFormRenderValueTypeHelpers } from '../typing'; 4 | 5 | export const dependency = ( 6 | item: ItemType, 7 | helpers: ProFormRenderValueTypeHelpers, 8 | ) => { 9 | /** ProFormDependency */ 10 | if (item.valueType === 'dependency') { 11 | const fieldProps = item.getFieldProps?.(); 12 | noteOnce( 13 | Array.isArray(item.name ?? fieldProps?.name), 14 | 'SchemaForm: fieldProps.name should be NamePath[] when valueType is "dependency"', 15 | ); 16 | noteOnce( 17 | typeof item.columns === 'function', 18 | 'SchemaForm: columns should be a function when valueType is "dependency"', 19 | ); 20 | 21 | if (!Array.isArray(item.name ?? fieldProps?.name)) return null; 22 | 23 | return ( 24 | 25 | {(values: any) => { 26 | if (!item.columns || typeof item.columns !== 'function') return null; 27 | return helpers.genItems(item.columns(values)); 28 | }} 29 | 30 | ); 31 | } 32 | 33 | return true; 34 | }; 35 | -------------------------------------------------------------------------------- /packages/form/src/components/SchemaForm/valueType/divider.tsx: -------------------------------------------------------------------------------- 1 | import { Divider } from 'antd'; 2 | import type { ItemType } from '../typing'; 3 | 4 | export const divider = ( 5 | item: ItemType, 6 | ) => { 7 | /** 分割线 */ 8 | if (item.valueType === 'divider') { 9 | return ; 10 | } 11 | 12 | return true; 13 | }; 14 | -------------------------------------------------------------------------------- /packages/form/src/components/SchemaForm/valueType/formList.tsx: -------------------------------------------------------------------------------- 1 | import { ProFormList } from '../../List'; 2 | import type { ProSchemaRenderValueTypeFunction } from '../typing'; 3 | 4 | export const formList: ProSchemaRenderValueTypeFunction = ( 5 | item, 6 | { genItems }, 7 | ) => { 8 | if (item.valueType === 'formList' && item.dataIndex) { 9 | if (!item.columns || !Array.isArray(item.columns)) return null; 10 | return ( 11 | 21 | {genItems(item.columns)} 22 | 23 | ); 24 | } 25 | 26 | return true; 27 | }; 28 | -------------------------------------------------------------------------------- /packages/form/src/components/SchemaForm/valueType/formSet.tsx: -------------------------------------------------------------------------------- 1 | import ProFormFieldSet from '../../FieldSet'; 2 | import type { ProSchemaRenderValueTypeFunction } from '../typing'; 3 | 4 | export const formSet: ProSchemaRenderValueTypeFunction = ( 5 | item, 6 | { genItems }, 7 | ) => { 8 | if (item.valueType === 'formSet' && item.dataIndex) { 9 | if (!item.columns || !Array.isArray(item.columns)) return null; 10 | return ( 11 | 21 | {genItems(item.columns)} 22 | 23 | ); 24 | } 25 | 26 | return true; 27 | }; 28 | -------------------------------------------------------------------------------- /packages/form/src/components/SchemaForm/valueType/group.tsx: -------------------------------------------------------------------------------- 1 | import { ProFormGroup } from '../../../layouts'; 2 | import type { ProSchemaRenderValueTypeFunction } from '../typing'; 3 | 4 | export const group: ProSchemaRenderValueTypeFunction = (item, { genItems }) => { 5 | if (item.valueType === 'group') { 6 | if (!item.columns || !Array.isArray(item.columns)) return null; 7 | 8 | return ( 9 | 16 | {genItems(item.columns)} 17 | 18 | ); 19 | } 20 | 21 | return true; 22 | }; 23 | -------------------------------------------------------------------------------- /packages/form/src/components/SchemaForm/valueType/ignore.tsx: -------------------------------------------------------------------------------- 1 | import type { ProSchemaRenderValueTypeFunction } from '../typing'; 2 | 3 | export const ignore: ProSchemaRenderValueTypeFunction = (item) => { 4 | // 几种特殊的 value 不处理 5 | if ( 6 | item.valueType && 7 | typeof item.valueType === 'string' && 8 | ['index', 'indexBorder', 'option'].includes(item?.valueType) 9 | ) { 10 | return null; 11 | } 12 | return true; 13 | }; 14 | -------------------------------------------------------------------------------- /packages/form/src/components/SchemaForm/valueType/index.tsx: -------------------------------------------------------------------------------- 1 | import type { 2 | ItemType, 3 | ProFormRenderValueTypeHelpers, 4 | ProSchemaRenderValueTypeFunction, 5 | } from '../typing'; 6 | import { dependency } from './dependency'; 7 | import { divider } from './divider'; 8 | import { field } from './field'; 9 | import { formList } from './formList'; 10 | import { formSet } from './formSet'; 11 | import { group } from './group'; 12 | import { ignore } from './ignore'; 13 | 14 | // 按照数组顺序执行 15 | const tasks: ProSchemaRenderValueTypeFunction[] = [ 16 | ignore, 17 | group, 18 | formList, 19 | formSet, 20 | divider, 21 | dependency, 22 | ]; 23 | 24 | export const renderValueType = ( 25 | item: ItemType, 26 | helpers: ProFormRenderValueTypeHelpers, 27 | ) => { 28 | for (let cur = 0; cur < tasks.length; cur++) { 29 | const task = tasks[cur]; 30 | const dom = task(item, helpers); 31 | 32 | // False 不再遍历 33 | // if (dom === false) { 34 | // return false; 35 | if (dom === true) { 36 | // True 继续下一次 37 | continue; 38 | } else { 39 | // Other Is Dom 40 | return dom; 41 | } 42 | } 43 | 44 | // 最后执行 45 | return field(item, helpers); 46 | }; 47 | -------------------------------------------------------------------------------- /packages/form/src/components/Segmented/index.tsx: -------------------------------------------------------------------------------- 1 | import type { SegmentedProps } from 'antd'; 2 | import React from 'react'; 3 | import type { 4 | ProFormFieldItemProps, 5 | ProFormFieldRemoteProps, 6 | } from '../../typing'; 7 | import ProFormField from '../Field'; 8 | 9 | /** 10 | * 分段控制器 11 | * 12 | * @param 13 | */ 14 | const ProFormSegmented: React.ForwardRefRenderFunction< 15 | any, 16 | ProFormFieldItemProps & ProFormFieldRemoteProps 17 | > = ({ fieldProps, request, params, proFieldProps, ...rest }, ref) => { 18 | return ( 19 | 29 | ); 30 | }; 31 | 32 | const WarpProFormSegmented: React.FC< 33 | ProFormFieldItemProps & ProFormFieldRemoteProps 34 | > = React.forwardRef(ProFormSegmented); 35 | 36 | export default WarpProFormSegmented; 37 | -------------------------------------------------------------------------------- /packages/form/src/components/Switch/index.tsx: -------------------------------------------------------------------------------- 1 | import type { SwitchProps } from 'antd'; 2 | import React from 'react'; 3 | import type { ProFormFieldItemProps } from '../../typing'; 4 | import ProField from '../Field'; 5 | 6 | export type ProFormSwitchProps = Omit< 7 | ProFormFieldItemProps, 8 | 'emptyText' 9 | > & { 10 | checkedChildren?: SwitchProps['checkedChildren']; 11 | unCheckedChildren?: SwitchProps['unCheckedChildren']; 12 | }; 13 | 14 | /** 15 | * @zh-cn 单选 Switch 16 | * @en-us Single Choice Switch 17 | */ 18 | const ProFormSwitch: React.FC = React.forwardRef( 19 | ( 20 | { fieldProps, unCheckedChildren, checkedChildren, proFieldProps, ...rest }, 21 | ref: any, 22 | ) => { 23 | return ( 24 | 41 | ); 42 | }, 43 | ); 44 | 45 | export default ProFormSwitch; 46 | -------------------------------------------------------------------------------- /packages/form/src/components/TextArea/index.tsx: -------------------------------------------------------------------------------- 1 | import type { TextAreaProps } from 'antd/lib/input'; 2 | import type { TextAreaRef } from 'antd/lib/input/TextArea'; 3 | import React from 'react'; 4 | import type { ProFormFieldItemProps } from '../../typing'; 5 | import ProField from '../Field'; 6 | 7 | /** 8 | * 文本选择组件 9 | * 10 | * @param 11 | */ 12 | const ProFormTextArea: React.ForwardRefRenderFunction< 13 | any, 14 | ProFormFieldItemProps 15 | > = ({ fieldProps, proFieldProps, ...rest }, ref) => { 16 | return ( 17 | 24 | ); 25 | }; 26 | 27 | export default React.forwardRef(ProFormTextArea); 28 | -------------------------------------------------------------------------------- /packages/form/src/components/TreeSelect/index.tsx: -------------------------------------------------------------------------------- 1 | import type { TreeSelectProps } from 'antd'; 2 | import type { RefSelectProps } from 'antd/lib/select'; 3 | import React from 'react'; 4 | import type { 5 | ProFormFieldItemProps, 6 | ProFormFieldRemoteProps, 7 | } from '../../typing'; 8 | import ProFormField from '../Field'; 9 | 10 | export type ProFormTreeSelectProps = ProFormFieldItemProps< 11 | TreeSelectProps & { 12 | /** 13 | * 当搜索关键词发生变化时是否请求远程数据 14 | * 15 | * @default true 16 | */ 17 | fetchDataOnSearch?: boolean; 18 | }, 19 | RefSelectProps 20 | > & 21 | ProFormFieldRemoteProps; 22 | 23 | /** 24 | * 级联选择框 25 | * 26 | * @param 27 | */ 28 | const ProFormTreeSelect: React.ForwardRefRenderFunction< 29 | any, 30 | ProFormTreeSelectProps 31 | > = ({ fieldProps, request, params, proFieldProps, ...rest }, ref) => { 32 | return ( 33 | 43 | ); 44 | }; 45 | 46 | const WarpProFormTreeSelect: React.FC = 47 | React.forwardRef(ProFormTreeSelect); 48 | 49 | export default WarpProFormTreeSelect; 50 | -------------------------------------------------------------------------------- /packages/form/src/demos/label-col.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | ProForm, 3 | ProFormCheckbox, 4 | ProFormRadio, 5 | ProFormText, 6 | } from '@ant-design/pro-components'; 7 | import { Button } from 'antd'; 8 | 9 | const layout = { 10 | labelCol: { span: 8 }, 11 | wrapperCol: { span: 16 }, 12 | }; 13 | const tailLayout = { 14 | wrapperCol: { offset: 8, span: 16 }, 15 | }; 16 | 17 | export default () => { 18 | return ( 19 | <> 20 | 27 | 28 | 29 | 34 | 35 | Remember me 36 | 37 | 38 | Remember me 39 | 40 | 41 | 44 | 45 | 46 | 47 | ); 48 | }; 49 | -------------------------------------------------------------------------------- /packages/form/src/demos/labelInValue.tsx: -------------------------------------------------------------------------------- 1 | import { ProForm, ProFormSelect } from '@ant-design/pro-components'; 2 | import { message } from 'antd'; 3 | 4 | export default () => { 5 | return ( 6 | { 8 | message.success('提交成功'); 9 | }} 10 | onValuesChange={(v) => console.log(v)} 11 | > 12 | 32 | 33 | ); 34 | }; 35 | -------------------------------------------------------------------------------- /packages/form/src/demos/params-formref.tsx: -------------------------------------------------------------------------------- 1 | import { BetaSchemaForm } from '@ant-design/pro-components'; 2 | import { useEffect, useRef, useState } from 'react'; 3 | 4 | export default () => { 5 | const targetRef = useRef(); 6 | 7 | const [requestLibData, setRequestLibData] = useState(0); 8 | useEffect(() => { 9 | // 更新requestLibData,并引发reRender 10 | setTimeout(() => { 11 | setRequestLibData(1); 12 | }); 13 | }, []); 14 | // 查看reRender后的ref标记 15 | useEffect(() => console.log('targetRef.current1', targetRef.current)); 16 | // 查看reRender后的ref标记 17 | useEffect(() => { 18 | setTimeout(() => { 19 | console.log('targetRef.current1', targetRef.current); 20 | }, 1000); 21 | }); 22 | return ( 23 | ({})} 25 | params={{ requestLibData }} 26 | columns={[ 27 | { 28 | title: 'money', 29 | dataIndex: 'money', 30 | valueType: 'money', 31 | }, 32 | ]} 33 | formRef={targetRef} 34 | /> 35 | ); 36 | }; 37 | -------------------------------------------------------------------------------- /packages/form/src/demos/typings.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.module.less'; 2 | 3 | interface Window { 4 | DarkReader: any; 5 | } 6 | -------------------------------------------------------------------------------- /packages/form/src/helpers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './grid'; 2 | -------------------------------------------------------------------------------- /packages/form/src/layouts/DrawerForm/style.ts: -------------------------------------------------------------------------------- 1 | import type { GenerateStyle, ProAliasToken } from '@ant-design/pro-provider'; 2 | import { useStyle as useAntdStyle } from '@ant-design/pro-provider'; 3 | 4 | export interface DrawerFormToken extends ProAliasToken { 5 | componentCls: string; 6 | } 7 | 8 | const genDrawerFormStyle: GenerateStyle = (token) => { 9 | return { 10 | [token.componentCls]: { 11 | '&-sidebar-dragger': { 12 | width: '5px', 13 | cursor: 'ew-resize', 14 | padding: '4px 0 0', 15 | borderTop: '1px solid transparent', 16 | position: 'absolute', 17 | top: 0, 18 | left: 0, 19 | bottom: 0, 20 | zIndex: 100, 21 | backgroundColor: 'transparent', 22 | '&-min-disabled': { 23 | cursor: 'w-resize', 24 | }, 25 | '&-max-disabled': { 26 | cursor: 'e-resize', 27 | }, 28 | }, 29 | }, 30 | }; 31 | }; 32 | 33 | export function useStyle(prefixCls: string) { 34 | return useAntdStyle('DrawerForm', (token) => { 35 | const drawerFormToken: DrawerFormToken = { 36 | ...token, 37 | componentCls: `.${prefixCls}`, 38 | }; 39 | 40 | return [genDrawerFormStyle(drawerFormToken)]; 41 | }); 42 | } 43 | -------------------------------------------------------------------------------- /packages/form/src/layouts/ProForm/index.tsx: -------------------------------------------------------------------------------- 1 | import type { FormProps } from 'antd'; 2 | import { Form } from 'antd'; 3 | import React from 'react'; 4 | import type { CommonFormProps } from '../../BaseForm'; 5 | import { BaseForm } from '../../BaseForm'; 6 | import { EditOrReadOnlyContext } from '../../BaseForm/EditOrReadOnlyContext'; 7 | import { Group, ProFormItem } from '../../components'; 8 | 9 | export type ProFormProps< 10 | T = Record, 11 | U = Record, 12 | > = Omit, 'onFinish'> & CommonFormProps; 13 | 14 | function ProForm>( 15 | props: ProFormProps & { 16 | children?: React.ReactNode | React.ReactNode[]; 17 | }, 18 | ) { 19 | return ( 20 | { 23 | return ( 24 | <> 25 | {items} 26 | {submitter} 27 | 28 | ); 29 | }} 30 | {...props} 31 | /> 32 | ); 33 | } 34 | 35 | ProForm.Group = Group; 36 | ProForm.useForm = Form.useForm; 37 | ProForm.Item = ProFormItem; 38 | ProForm.useWatch = Form.useWatch; 39 | ProForm.ErrorList = Form.ErrorList; 40 | ProForm.Provider = Form.Provider; 41 | ProForm.useFormInstance = Form.useFormInstance; 42 | ProForm.EditOrReadOnlyContext = EditOrReadOnlyContext; 43 | 44 | export { ProForm }; 45 | -------------------------------------------------------------------------------- /packages/form/src/layouts/StepsForm/style.ts: -------------------------------------------------------------------------------- 1 | import type { GenerateStyle, ProAliasToken } from '@ant-design/pro-provider'; 2 | import { useStyle as useAntdStyle } from '@ant-design/pro-provider'; 3 | 4 | export interface StepsFormToken extends ProAliasToken { 5 | componentCls: string; 6 | } 7 | 8 | const genStepsFormStyle: GenerateStyle = (token) => { 9 | return { 10 | [token.componentCls]: { 11 | '&-container': { 12 | width: 'max-content', 13 | minWidth: '420px', 14 | maxWidth: '100%', 15 | margin: 'auto', 16 | }, 17 | '&-steps-container': { 18 | maxWidth: '1160px', 19 | margin: 'auto', 20 | [`${token.antCls}-steps-vertical`]: { height: '100%' }, 21 | }, 22 | '&-step': { 23 | display: 'none', 24 | marginBlockStart: '32px', 25 | '&-active': { 26 | display: 'block', 27 | }, 28 | '> form': { maxWidth: '100%' }, 29 | }, 30 | }, 31 | }; 32 | }; 33 | 34 | export function useStyle(prefixCls: string) { 35 | return useAntdStyle('StepsForm', (token) => { 36 | const loginFormToken: StepsFormToken = { 37 | ...token, 38 | componentCls: `.${prefixCls}`, 39 | }; 40 | 41 | return [genStepsFormStyle(loginFormToken)]; 42 | }); 43 | } 44 | -------------------------------------------------------------------------------- /packages/form/src/layouts/index.ts: -------------------------------------------------------------------------------- 1 | import { ProForm } from './ProForm'; 2 | 3 | export { DrawerForm } from './DrawerForm'; 4 | export type { DrawerFormProps } from './DrawerForm'; 5 | export { LightFilter } from './LightFilter'; 6 | export type { LightFilterProps } from './LightFilter'; 7 | export { LoginForm } from './LoginForm'; 8 | export type { LoginFormProps } from './LoginForm'; 9 | export { LoginFormPage } from './LoginFormPage'; 10 | export { ModalForm } from './ModalForm'; 11 | export type { ModalFormProps } from './ModalForm'; 12 | export type { ProFormProps } from './ProForm'; 13 | export { QueryFilter } from './QueryFilter'; 14 | export type { BaseQueryFilterProps, QueryFilterProps } from './QueryFilter'; 15 | export { StepsForm } from './StepsForm'; 16 | export type { StepFormProps, StepsFormProps } from './StepsForm'; 17 | export { ProForm }; 18 | 19 | export const ProFormGroup = ProForm.Group; 20 | -------------------------------------------------------------------------------- /packages/form/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./", 4 | "target": "esnext", 5 | "module": "ESNext", 6 | "moduleResolution": "node", 7 | "jsx": "react-jsx", 8 | "esModuleInterop": true, 9 | "experimentalDecorators": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "noImplicitReturns": true, 13 | "declaration": true, 14 | "skipLibCheck": true, 15 | "resolveJsonModule": true, 16 | "paths": { 17 | "@ant-design/pro-field": ["../../packages/field/src/index.tsx"], 18 | "@ant-design/pro-provider": ["../../packages/provider/src/index.tsx"], 19 | "@ant-design/pro-utils": ["../../packages/utils/src/index.tsx"], 20 | "@ant-design/pro-components": ["../../packages/components/src/index.tsx"] 21 | } 22 | }, 23 | "include": ["./src"] 24 | } 25 | -------------------------------------------------------------------------------- /packages/layout/.fatherrc.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'father'; 2 | 3 | export default defineConfig({ 4 | extends: '../../.fatherrc.base.ts', 5 | }); 6 | -------------------------------------------------------------------------------- /packages/layout/src/components/AppsLogoComponents/AppsLogo.tsx: -------------------------------------------------------------------------------- 1 | /** 2 | * 默认的应用列表的图标 3 | * 4 | */ 5 | export const AppsLogo = () => ( 6 | 15 | ); 16 | -------------------------------------------------------------------------------- /packages/layout/src/components/AppsLogoComponents/types.d.ts: -------------------------------------------------------------------------------- 1 | export type AppItemProps = { 2 | title: React.ReactNode; 3 | desc?: React.ReactNode; 4 | icon?: React.ReactNode | (() => React.ReactNode); 5 | url?: string; 6 | target?: string; 7 | children?: Omit[]; 8 | }; 9 | 10 | export type AppListProps = AppItemProps[]; 11 | -------------------------------------------------------------------------------- /packages/layout/src/components/CollapsedIcon/index.tsx: -------------------------------------------------------------------------------- 1 | import classNames from 'classnames'; 2 | import { ArrowSvgIcon } from '../SiderMenu/Arrow'; 3 | import { useStyle } from './style'; 4 | 5 | export const CollapsedIcon: React.FC = (props) => { 6 | const { isMobile, collapsed, ...rest } = props; 7 | const { wrapSSR, hashId } = useStyle(props.className); 8 | if (isMobile && collapsed) return null; 9 | return wrapSSR( 10 |
17 | 18 |
, 19 | ); 20 | }; 21 | -------------------------------------------------------------------------------- /packages/layout/src/components/Footer.tsx: -------------------------------------------------------------------------------- 1 | import { CopyrightOutlined } from '@ant-design/icons'; 2 | import { Layout } from 'antd'; 3 | import type { CSSProperties } from 'react'; 4 | import React, { Fragment } from 'react'; 5 | import type { WithFalse } from '../typing'; 6 | import { GlobalFooter } from './GlobalFooter'; 7 | 8 | const { Footer } = Layout; 9 | 10 | export type FooterProps = { 11 | links?: WithFalse< 12 | { 13 | key?: string; 14 | title: React.ReactNode; 15 | href: string; 16 | blankTarget?: boolean; 17 | }[] 18 | >; 19 | copyright?: WithFalse; 20 | style?: CSSProperties; 21 | className?: string; 22 | prefixCls?: string; 23 | }; 24 | 25 | const DefaultFooter: React.FC = ({ 26 | links, 27 | copyright, 28 | style, 29 | className, 30 | prefixCls, 31 | }: FooterProps) => ( 32 |
33 | 39 | {copyright} 40 | 41 | ) 42 | } 43 | /> 44 |
45 | ); 46 | 47 | export { DefaultFooter }; 48 | -------------------------------------------------------------------------------- /packages/layout/src/components/FooterToolbar/style/stylish.ts: -------------------------------------------------------------------------------- 1 | import type { GenerateStyle, ProAliasToken } from '@ant-design/pro-provider'; 2 | import { useStyle as useAntdStyle } from '@ant-design/pro-provider'; 3 | 4 | export interface stylishToken extends ProAliasToken { 5 | componentCls: string; 6 | } 7 | 8 | export function useStylish( 9 | prefixCls: string, 10 | { 11 | stylish, 12 | }: { 13 | stylish?: GenerateStyle; 14 | }, 15 | ) { 16 | return useAntdStyle('ProLayoutFooterToolbarStylish', (token) => { 17 | const stylishToken: stylishToken = { 18 | ...token, 19 | componentCls: `.${prefixCls}`, 20 | }; 21 | if (!stylish) return []; 22 | 23 | return [ 24 | { 25 | [`${stylishToken.componentCls}`]: stylish?.(stylishToken), 26 | }, 27 | ]; 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /packages/layout/src/components/GridContent/style.ts: -------------------------------------------------------------------------------- 1 | import type { GenerateStyle, ProAliasToken } from '@ant-design/pro-provider'; 2 | import { useStyle as useAntdStyle } from '@ant-design/pro-provider'; 3 | 4 | export interface GridContentToken extends ProAliasToken { 5 | componentCls: string; 6 | } 7 | 8 | const genGridContentStyle: GenerateStyle = (token) => { 9 | return { 10 | [token.componentCls]: { 11 | width: '100%', 12 | '&-wide': { 13 | maxWidth: 1152, 14 | margin: '0 auto', 15 | }, 16 | }, 17 | }; 18 | }; 19 | 20 | export function useStyle(prefixCls: string) { 21 | return useAntdStyle('ProLayoutGridContent', (token) => { 22 | const GridContentToken: GridContentToken = { 23 | ...token, 24 | componentCls: `.${prefixCls}`, 25 | }; 26 | 27 | return [genGridContentStyle(GridContentToken)]; 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /packages/layout/src/components/Header/style/stylish.ts: -------------------------------------------------------------------------------- 1 | import type { GenerateStyle, ProAliasToken } from '@ant-design/pro-provider'; 2 | import { useStyle as useAntdStyle } from '@ant-design/pro-provider'; 3 | export interface stylishToken extends ProAliasToken { 4 | componentCls: string; 5 | proLayoutCollapsedWidth: number; 6 | } 7 | 8 | export function useStylish( 9 | prefixCls: string, 10 | { 11 | stylish, 12 | proLayoutCollapsedWidth, 13 | }: { 14 | stylish?: GenerateStyle; 15 | proLayoutCollapsedWidth: number; 16 | }, 17 | ) { 18 | return useAntdStyle('ProLayoutHeaderStylish', (token) => { 19 | const stylishToken: stylishToken = { 20 | ...token, 21 | componentCls: `.${prefixCls}`, 22 | proLayoutCollapsedWidth, 23 | }; 24 | if (!stylish) return []; 25 | 26 | return [ 27 | { 28 | [`div${token.proComponentsCls}-layout`]: { 29 | [`${stylishToken.componentCls}`]: stylish?.(stylishToken), 30 | }, 31 | }, 32 | ]; 33 | }); 34 | } 35 | -------------------------------------------------------------------------------- /packages/layout/src/components/PageContainer/demos/hideBreadMenu.tsx: -------------------------------------------------------------------------------- 1 | import { PageContainer, ProCard } from '@ant-design/pro-components'; 2 | import { Descriptions } from 'antd'; 3 | 4 | export default () => ( 5 |
10 | 18 | 曲丽丽 19 | 20 | 421421 21 | 22 | 23 | 2017-01-10 24 | 25 | 26 | 浙江省杭州市西湖区工专路 27 | 28 | 29 | } 30 | > 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
40 | ); 41 | -------------------------------------------------------------------------------- /packages/layout/src/components/PageContainer/style/stylish.ts: -------------------------------------------------------------------------------- 1 | import type { GenerateStyle, ProAliasToken } from '@ant-design/pro-provider'; 2 | import { useStyle as useAntdStyle } from '@ant-design/pro-provider'; 3 | 4 | export interface stylishToken extends ProAliasToken { 5 | componentCls: string; 6 | } 7 | 8 | export function useStylish( 9 | prefixCls: string, 10 | { 11 | stylish, 12 | }: { 13 | stylish?: GenerateStyle; 14 | }, 15 | ) { 16 | return useAntdStyle('ProLayoutPageContainerStylish', (token) => { 17 | const stylishToken: stylishToken = { 18 | ...token, 19 | componentCls: `.${prefixCls}`, 20 | }; 21 | if (!stylish) return []; 22 | 23 | return [ 24 | { 25 | [`div${stylishToken.componentCls}`]: stylish?.(stylishToken), 26 | }, 27 | ]; 28 | }); 29 | } 30 | -------------------------------------------------------------------------------- /packages/layout/src/components/PageHeader/demo/basic.en-US.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 1 3 | title: Basic Page Header 4 | --- 5 | 6 | ## Basic Page Header 7 | 8 | Standard header, suitable for use in scenarios that require a brief description. 9 | 10 | ```tsx | pure 11 | import { PageHeader } from 'antd'; 12 | import React from 'react'; 13 | 14 | const App: React.FC = () => ( 15 | null} 18 | oldtitle="Title" 19 | suboldtitle="This is a subtitle" 20 | /> 21 | ); 22 | 23 | export default App; 24 | ``` 25 | 26 | ```css 27 | .site-page-header { 28 | border: 1px solid rgb(235, 237, 240); 29 | } 30 | ``` 31 | -------------------------------------------------------------------------------- /packages/layout/src/components/PageHeader/demo/basic.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 1 3 | title: 标准样式 4 | --- 5 | 6 | ## 标准样式 7 | 8 | 标准页头,适合使用在需要简单描述的场景。 9 | 10 | ```tsx | pure 11 | import { PageHeader } from 'antd'; 12 | import React from 'react'; 13 | 14 | const App: React.FC = () => ( 15 | null} 18 | title="Title" 19 | subTitle="This is a subtitle" 20 | /> 21 | ); 22 | 23 | export default App; 24 | ``` 25 | 26 | ```css 27 | .site-page-header { 28 | border: 1px solid rgb(235, 237, 240); 29 | } 30 | ``` 31 | -------------------------------------------------------------------------------- /packages/layout/src/components/PageHeader/demo/breadcrumb.en-US.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 3 3 | title: Use with breadcrumbs 4 | --- 5 | 6 | ## Use with breadcrumbs 7 | 8 | With breadcrumbs, it is suitable for deeper pages, allowing users to navigate quickly. 9 | 10 | ```tsx | pure 11 | import { PageHeader } from 'antd'; 12 | import React from 'react'; 13 | 14 | const routes = [ 15 | { 16 | path: 'index', 17 | breadcrumbName: 'First-level Menu', 18 | }, 19 | { 20 | path: 'first', 21 | breadcrumbName: 'Second-level Menu', 22 | }, 23 | { 24 | path: 'second', 25 | breadcrumbName: 'Third-level Menu', 26 | }, 27 | ]; 28 | 29 | const App: React.FC = () => ( 30 | 36 | ); 37 | 38 | export default App; 39 | ``` 40 | -------------------------------------------------------------------------------- /packages/layout/src/components/PageHeader/demo/breadcrumb.md: -------------------------------------------------------------------------------- 1 | --- 2 | order: 3 3 | title: 带面包屑页头 4 | --- 5 | 6 | ## 带面包屑页头 7 | 8 | 带面包屑页头,适合层级比较深的页面,让用户可以快速导航。 9 | 10 | ```tsx | pure 11 | import { PageHeader } from 'antd'; 12 | import React from 'react'; 13 | 14 | const routes = [ 15 | { 16 | path: 'index', 17 | breadcrumbName: 'First-level Menu', 18 | }, 19 | { 20 | path: 'first', 21 | breadcrumbName: 'Second-level Menu', 22 | }, 23 | { 24 | path: 'second', 25 | breadcrumbName: 'Third-level Menu', 26 | }, 27 | ]; 28 | 29 | const App: React.FC = () => ( 30 | 36 | ); 37 | 38 | export default App; 39 | ``` 40 | -------------------------------------------------------------------------------- /packages/layout/src/components/PageLoading/index.tsx: -------------------------------------------------------------------------------- 1 | import type { SpinProps } from 'antd'; 2 | import { Spin } from 'antd'; 3 | import React from 'react'; 4 | 5 | const PageLoading: React.FC = ({ 6 | isLoading, 7 | pastDelay, 8 | timedOut, 9 | error, 10 | retry, 11 | ...reset 12 | }) => ( 13 |
14 | 15 |
16 | ); 17 | 18 | export { PageLoading }; 19 | -------------------------------------------------------------------------------- /packages/layout/src/components/SiderMenu/Arrow.tsx: -------------------------------------------------------------------------------- 1 | function ArrowSvgIcon() { 2 | return ( 3 | 12 | ); 13 | } 14 | 15 | export { ArrowSvgIcon }; 16 | -------------------------------------------------------------------------------- /packages/layout/src/components/SiderMenu/style/stylish.ts: -------------------------------------------------------------------------------- 1 | import type { GenerateStyle, ProAliasToken } from '@ant-design/pro-provider'; 2 | import { useStyle as useAntdStyle } from '@ant-design/pro-provider'; 3 | export interface SiderMenuToken extends ProAliasToken { 4 | componentCls: string; 5 | proLayoutCollapsedWidth: number; 6 | } 7 | 8 | export function useStylish( 9 | prefixCls: string, 10 | { 11 | stylish, 12 | proLayoutCollapsedWidth, 13 | }: { 14 | stylish?: GenerateStyle; 15 | proLayoutCollapsedWidth: number; 16 | }, 17 | ) { 18 | return useAntdStyle('ProLayoutSiderMenuStylish', (token) => { 19 | const siderMenuToken: SiderMenuToken = { 20 | ...token, 21 | componentCls: `.${prefixCls}`, 22 | proLayoutCollapsedWidth, 23 | }; 24 | if (!stylish) return []; 25 | return [ 26 | { 27 | [`div${token.proComponentsCls}-layout`]: { 28 | [`${siderMenuToken.componentCls}`]: stylish?.(siderMenuToken), 29 | }, 30 | }, 31 | ]; 32 | }); 33 | } 34 | -------------------------------------------------------------------------------- /packages/layout/src/components/WaterMark/demos/text.tsx: -------------------------------------------------------------------------------- 1 | /** Title: 文字水印 */ 2 | import { WaterMark } from '@ant-design/pro-components'; 3 | 4 | export default () => ( 5 | 6 |
7 | 8 | ); 9 | -------------------------------------------------------------------------------- /packages/layout/src/components/WaterMark/demos/textRows.tsx: -------------------------------------------------------------------------------- 1 | /** Title: 多行文字水印 */ 2 | import { WaterMark } from '@ant-design/pro-components'; 3 | 4 | export default () => ( 5 | 6 |
7 | 8 | ); 9 | -------------------------------------------------------------------------------- /packages/layout/src/demos/DefaultOpenAllMenu.tsx: -------------------------------------------------------------------------------- 1 | import { PageContainer, ProLayout } from '@ant-design/pro-components'; 2 | import complexMenu from './complexMenu'; 3 | 4 | export default () => ( 5 |
10 | 21 | 22 |
Hello World
23 |
24 |
25 |
26 | ); 27 | -------------------------------------------------------------------------------- /packages/layout/src/demos/IconFont.tsx: -------------------------------------------------------------------------------- 1 | import { PageContainer, ProLayout } from '@ant-design/pro-components'; 2 | 3 | export default () => ( 4 |
9 | 34 | 35 |
Hello World
36 |
37 |
38 |
39 | ); 40 | -------------------------------------------------------------------------------- /packages/layout/src/demos/MenuGroup.tsx: -------------------------------------------------------------------------------- 1 | import { PageContainer, ProLayout } from '@ant-design/pro-components'; 2 | import complexMenu from './complexMenu'; 3 | 4 | export default () => ( 5 |
10 | 19 | 20 |
Hello World
21 |
22 |
23 |
24 | ); 25 | -------------------------------------------------------------------------------- /packages/layout/src/demos/TopmenuNested.tsx: -------------------------------------------------------------------------------- 1 | import { PageContainer, ProLayout } from '@ant-design/pro-components'; 2 | import complexMenu from './complexMenu'; 3 | 4 | export default () => ( 5 |
11 | 20 | 29 | 30 |
Hello World
31 |
32 |
33 |
34 |
35 | ); 36 | -------------------------------------------------------------------------------- /packages/layout/src/demos/customMenu.ts: -------------------------------------------------------------------------------- 1 | export default [ 2 | { 3 | path: '/', 4 | name: '欢迎', 5 | routes: [ 6 | { 7 | path: '/welcome', 8 | name: 'one', 9 | routes: [ 10 | { 11 | path: '/welcome/welcome', 12 | name: 'two', 13 | exact: true, 14 | }, 15 | ], 16 | }, 17 | ], 18 | }, 19 | { 20 | path: '/demo', 21 | name: '例子', 22 | }, 23 | ]; 24 | -------------------------------------------------------------------------------- /packages/layout/src/demos/footer.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | DefaultFooter, 3 | PageContainer, 4 | ProLayout, 5 | } from '@ant-design/pro-components'; 6 | import defaultProps from './_defaultProps'; 7 | 8 | export default () => ( 9 | ( 20 | 27 | )} 28 | > 29 | Hello World 30 | 31 | ); 32 | -------------------------------------------------------------------------------- /packages/layout/src/demos/hideMenu.tsx: -------------------------------------------------------------------------------- 1 | import { PageContainer, ProLayout } from '@ant-design/pro-components'; 2 | import defaultProps from './_defaultProps'; 3 | 4 | export default () => ( 5 | ( 14 |
23 | {dom} 24 |
25 | )} 26 | > 27 | Hello World 28 |
29 | ); 30 | -------------------------------------------------------------------------------- /packages/layout/src/locales/en-US.ts: -------------------------------------------------------------------------------- 1 | import settingDrawer from './en-US/settingDrawer'; 2 | 3 | export default { 4 | ...settingDrawer, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/layout/src/locales/index.ts: -------------------------------------------------------------------------------- 1 | import { isBrowser } from '@ant-design/pro-utils'; 2 | import enUSLocal from './en-US'; 3 | import itITLocal from './it-IT'; 4 | import koKRLocal from './ko-KR'; 5 | import zhLocal from './zh-CN'; 6 | import zhTWLocal from './zh-TW'; 7 | 8 | const locales = { 9 | 'zh-CN': zhLocal, 10 | 'zh-TW': zhTWLocal, 11 | 'en-US': enUSLocal, 12 | 'it-IT': itITLocal, 13 | 'ko-KR': koKRLocal, 14 | }; 15 | 16 | type GLocaleWindow = { 17 | g_locale: keyof typeof locales; 18 | }; 19 | 20 | export type LocaleType = keyof typeof locales; 21 | 22 | export const getLanguage = (): string => { 23 | // support ssr 24 | if (!isBrowser()) return 'zh-CN'; 25 | const lang = window.localStorage.getItem('umi_locale'); 26 | return ( 27 | lang || (window as unknown as GLocaleWindow).g_locale || navigator.language 28 | ); 29 | }; 30 | export const gLocaleObject = (): Record => { 31 | const gLocale = getLanguage(); 32 | return locales[gLocale as 'zh-CN'] || locales['zh-CN']; 33 | }; 34 | -------------------------------------------------------------------------------- /packages/layout/src/locales/it-IT.ts: -------------------------------------------------------------------------------- 1 | import settingDrawer from './it-IT/settingDrawer'; 2 | 3 | export default { 4 | ...settingDrawer, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/layout/src/locales/ko-KR.ts: -------------------------------------------------------------------------------- 1 | import settingDrawer from './ko-KR/settingDrawer'; 2 | 3 | export default { 4 | ...settingDrawer, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/layout/src/locales/zh-CN.ts: -------------------------------------------------------------------------------- 1 | import settingDrawer from './zh-CN/settingDrawer'; 2 | 3 | export default { 4 | ...settingDrawer, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/layout/src/locales/zh-TW.ts: -------------------------------------------------------------------------------- 1 | import settingDrawer from './zh-TW/settingDrawer'; 2 | 3 | export default { 4 | ...settingDrawer, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/layout/src/utils/getMenuData.ts: -------------------------------------------------------------------------------- 1 | import { transformRoute } from '@umijs/route-utils'; 2 | import type { MenuDataItem, MessageDescriptor, Route } from '../typing'; 3 | 4 | function fromEntries(iterable: any) { 5 | return [...iterable].reduce( 6 | (obj: Record, [key, val]) => { 7 | // eslint-disable-next-line no-param-reassign 8 | obj[key] = val; 9 | return obj; 10 | }, 11 | {}, 12 | ); 13 | } 14 | 15 | const getMenuData = ( 16 | routes: Readonly, 17 | menu?: { locale?: boolean }, 18 | formatMessage?: (message: MessageDescriptor) => string, 19 | menuDataRender?: (menuData: MenuDataItem[]) => MenuDataItem[], 20 | ): { 21 | breadcrumb: Record; 22 | breadcrumbMap: Map; 23 | menuData: MenuDataItem[]; 24 | } => { 25 | const { menuData, breadcrumb } = transformRoute( 26 | routes as Route[], 27 | menu?.locale || false, 28 | formatMessage, 29 | true, 30 | ); 31 | 32 | if (!menuDataRender) { 33 | return { 34 | breadcrumb: fromEntries(breadcrumb), 35 | breadcrumbMap: breadcrumb, 36 | menuData, 37 | }; 38 | } 39 | return getMenuData(menuDataRender(menuData), menu, formatMessage, undefined); 40 | }; 41 | 42 | export { getMenuData }; 43 | -------------------------------------------------------------------------------- /packages/layout/src/utils/pathTools.ts: -------------------------------------------------------------------------------- 1 | // /userInfo/2144/id => ['/userInfo','/userInfo/2144,'/userInfo/2144/id'] 2 | export function urlToList(url?: string): string[] { 3 | if (!url || url === '/') { 4 | return ['/']; 5 | } 6 | const urlList = url.split('/').filter((i) => i); 7 | return urlList.map( 8 | (urlItem, index) => `/${urlList.slice(0, index + 1).join('/')}`, 9 | ); 10 | } 11 | -------------------------------------------------------------------------------- /packages/layout/src/utils/useCurrentMenuLayoutProps.ts: -------------------------------------------------------------------------------- 1 | import { omitUndefined } from '@ant-design/pro-utils'; 2 | import { useEffect, useState } from 'react'; 3 | import type { ProSettings } from '../defaultSettings'; 4 | 5 | const useCurrentMenuLayoutProps = (currentMenu: ProSettings) => { 6 | const [currentMenuLayoutProps, setCurrentMenuLayoutProps] = useState({}); 7 | 8 | useEffect(() => { 9 | setCurrentMenuLayoutProps( 10 | omitUndefined({ 11 | // 有时候会变成对象,是原来的方式 12 | layout: 13 | typeof currentMenu.layout !== 'object' 14 | ? currentMenu.layout 15 | : undefined, 16 | navTheme: currentMenu.navTheme, 17 | menuRender: currentMenu.menuRender, 18 | footerRender: currentMenu.footerRender, 19 | menuHeaderRender: currentMenu.menuHeaderRender, 20 | headerRender: currentMenu.headerRender, 21 | fixSiderbar: currentMenu.fixSiderbar, 22 | }), 23 | ); 24 | }, [ 25 | currentMenu.layout, 26 | currentMenu.navTheme, 27 | currentMenu.menuRender, 28 | currentMenu.footerRender, 29 | currentMenu.menuHeaderRender, 30 | currentMenu.headerRender, 31 | currentMenu.fixSiderbar, 32 | ]); 33 | return currentMenuLayoutProps; 34 | }; 35 | 36 | export { useCurrentMenuLayoutProps }; 37 | -------------------------------------------------------------------------------- /packages/layout/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./", 4 | "target": "esnext", 5 | "module": "ESNext", 6 | "moduleResolution": "node", 7 | "jsx": "react-jsx", 8 | "esModuleInterop": true, 9 | "experimentalDecorators": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "noImplicitReturns": true, 13 | "declaration": true, 14 | "skipLibCheck": true, 15 | "resolveJsonModule": true, 16 | "resolvePackageJsonExports": false, 17 | "resolvePackageJsonImports": false, 18 | "paths": { 19 | "@ant-design/pro-provider": ["../../packages/provider/src/index.tsx"], 20 | "@ant-design/pro-components": ["../../packages/components/src/index.tsx"], 21 | "@ant-design/pro-utils": ["../../packages/utils/src/index.tsx"] 22 | } 23 | }, 24 | "include": ["./src"] 25 | } 26 | -------------------------------------------------------------------------------- /packages/list/.fatherrc.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'father'; 2 | 3 | export default defineConfig({ 4 | extends: '../../.fatherrc.base.ts', 5 | }); 6 | -------------------------------------------------------------------------------- /packages/list/src/constants.ts: -------------------------------------------------------------------------------- 1 | const PRO_LIST_KEYS = [ 2 | 'title', 3 | 'subTitle', 4 | 'avatar', 5 | 'description', 6 | 'extra', 7 | 'content', 8 | 'actions', 9 | 'type', 10 | ]; 11 | 12 | const PRO_LIST_KEYS_MAP = PRO_LIST_KEYS.reduce((pre, next) => { 13 | pre.set(next, true); 14 | return pre; 15 | }, new Map()); 16 | 17 | export { PRO_LIST_KEYS, PRO_LIST_KEYS_MAP }; 18 | -------------------------------------------------------------------------------- /packages/provider/.fatherrc.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'father'; 2 | 3 | export default defineConfig({ 4 | extends: '../../.fatherrc.base.ts', 5 | }); 6 | -------------------------------------------------------------------------------- /packages/provider/README.md: -------------------------------------------------------------------------------- 1 | # @ant-design/pro-provider 2 | 3 | > @ant-design/pro-provider. 4 | 5 | See our website [@ant-design/pro-provider](https://procomponent.ant.design/) for more information. 6 | 7 | ## Install 8 | 9 | Using npm: 10 | 11 | ```bash 12 | $ npm install --save @ant-design/pro-provider 13 | ``` 14 | 15 | or using yarn: 16 | 17 | ```bash 18 | $ yarn add @ant-design/pro-provider 19 | ``` 20 | -------------------------------------------------------------------------------- /packages/provider/src/utils/merge.ts: -------------------------------------------------------------------------------- 1 | export const merge = >(...rest: any[]): T => { 2 | const obj = {} as Record; 3 | const il = rest.length; 4 | let key; 5 | let i = 0; 6 | for (; i < il; i += 1) { 7 | for (key in rest[i]) { 8 | if (rest[i].hasOwnProperty(key)) { 9 | if ( 10 | typeof obj[key] === 'object' && 11 | typeof rest[i][key] === 'object' && 12 | obj[key] !== undefined && 13 | obj[key] !== null && 14 | !Array.isArray(obj[key]) && 15 | !Array.isArray(rest[i][key]) 16 | ) { 17 | obj[key] = { 18 | ...obj[key], 19 | ...rest[i][key], 20 | }; 21 | } else { 22 | obj[key] = rest[i][key]; 23 | } 24 | } 25 | } 26 | } 27 | return obj as T; 28 | }; 29 | -------------------------------------------------------------------------------- /packages/provider/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./", 4 | "target": "esnext", 5 | "module": "ESNext", 6 | "moduleResolution": "node", 7 | "jsx": "react-jsx", 8 | "esModuleInterop": true, 9 | "experimentalDecorators": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "noImplicitReturns": true, 13 | "declaration": true, 14 | "skipLibCheck": true, 15 | "resolveJsonModule": true 16 | }, 17 | "include": ["./src"] 18 | } 19 | -------------------------------------------------------------------------------- /packages/skeleton/.fatherrc.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'father'; 2 | 3 | export default defineConfig({ 4 | extends: '../../.fatherrc.base.ts', 5 | }); 6 | -------------------------------------------------------------------------------- /packages/skeleton/README.md: -------------------------------------------------------------------------------- 1 | # @ant-design/pro-skeleton 2 | 3 | > @ant-design/pro-skeleton. 4 | 5 | See our website [@ant-design/pro-skeleton](https://procomponent.ant.design/) for more information. 6 | 7 | ## Install 8 | 9 | Using npm: 10 | 11 | ```bash 12 | $ npm install --save @ant-design/pro-skeleton 13 | ``` 14 | 15 | or using yarn: 16 | 17 | ```bash 18 | $ yarn add @ant-design/pro-skeleton 19 | ``` 20 | -------------------------------------------------------------------------------- /packages/skeleton/src/components/skeleton.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: ProSkeleton - 骨架屏 3 | atomId: ProSkeleton 4 | --- 5 | 6 | # ProSkeleton - 骨架屏 7 | 8 | > 该组件为内部组件,请勿直接使用。 9 | 10 | 页面级别的骨架屏,不支持自定义 11 | 12 | ## 安装和初始化 13 | 14 | ```typescript | pure 15 | import Skeleton from '@ant-design/pro-skeleton'; 16 | 17 | return ; 18 | ``` 19 | 20 | ## DEMO 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | ## API 31 | 32 | | 参数 | 说明 | 类型 | 默认值 | 33 | | --- | --- | --- | --- | 34 | | type | 不同类型的骨架屏 | `'list' \| 'result' \| 'descriptions'` | list | 35 | | active | 是否显示动态 | boolean | true | 36 | | pageHeader | 是否显示 pageHeader 的骨架屏 descriptions 和 list 有效 | - | - | 37 | | statistic | 统计信息骨架屏的数量 | `number` \| `false` | - | 38 | | list | 列表的骨架屏,可以控制数量 | `number` \| `false` | - | 39 | | toolbar | 列表的操作栏骨架屏 | boolean | - | 40 | | renderFormItem | 自定义 `mode=update 或 edit` 下的 dom 表现,一般用于渲染编辑框 | - | - | 41 | | render | 自定义 `mode=read` 下的 dom 表现,只是单纯的表现形式 | - | - | 42 | -------------------------------------------------------------------------------- /packages/skeleton/src/demos/descriptions.tsx: -------------------------------------------------------------------------------- 1 | import ProSkeleton from '@ant-design/pro-skeleton'; 2 | 3 | export default () => { 4 | return ( 5 |
11 | 12 |
13 | ); 14 | }; 15 | -------------------------------------------------------------------------------- /packages/skeleton/src/demos/list.static.tsx: -------------------------------------------------------------------------------- 1 | import ProSkeleton from '@ant-design/pro-skeleton'; 2 | 3 | export default () => ( 4 |
10 | 11 |
12 | ); 13 | -------------------------------------------------------------------------------- /packages/skeleton/src/demos/list.tsx: -------------------------------------------------------------------------------- 1 | import ProSkeleton from '@ant-design/pro-skeleton'; 2 | 3 | export default () => ( 4 |
10 | 11 |
12 | ); 13 | -------------------------------------------------------------------------------- /packages/skeleton/src/demos/result.tsx: -------------------------------------------------------------------------------- 1 | import ProSkeleton from '@ant-design/pro-skeleton'; 2 | 3 | export default () => ( 4 |
10 | 11 |
12 | ); 13 | -------------------------------------------------------------------------------- /packages/skeleton/src/index.tsx: -------------------------------------------------------------------------------- 1 | import 'antd/lib/skeleton/style'; 2 | import React from 'react'; 3 | import type { DescriptionsPageSkeletonProps } from './components/Descriptions'; 4 | import DescriptionsPageSkeleton, { 5 | DescriptionsSkeleton, 6 | TableItemSkeleton, 7 | TableSkeleton, 8 | } from './components/Descriptions'; 9 | import type { ListPageSkeletonProps } from './components/List'; 10 | import ListPageSkeleton, { 11 | ListSkeleton, 12 | ListSkeletonItem, 13 | ListToolbarSkeleton, 14 | PageHeaderSkeleton, 15 | } from './components/List'; 16 | import ResultPageSkeleton from './components/Result'; 17 | 18 | const ProSkeleton: React.FC< 19 | ListPageSkeletonProps & 20 | DescriptionsPageSkeletonProps & { 21 | type?: 'list' | 'result' | 'descriptions'; 22 | active?: boolean; 23 | } 24 | > = ({ type = 'list', ...rest }) => { 25 | if (type === 'result') { 26 | return ; 27 | } 28 | 29 | if (type === 'descriptions') { 30 | return ; 31 | } 32 | 33 | return ; 34 | }; 35 | 36 | export { 37 | DescriptionsSkeleton, 38 | ListPageSkeleton, 39 | ListSkeleton, 40 | ListSkeletonItem, 41 | ListToolbarSkeleton, 42 | PageHeaderSkeleton, 43 | ProSkeleton, 44 | TableItemSkeleton, 45 | TableSkeleton, 46 | }; 47 | 48 | export default ProSkeleton; 49 | -------------------------------------------------------------------------------- /packages/skeleton/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./", 4 | "target": "esnext", 5 | "module": "ESNext", 6 | "moduleResolution": "node", 7 | "jsx": "react-jsx", 8 | "esModuleInterop": true, 9 | "experimentalDecorators": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "noImplicitReturns": true, 13 | "declaration": true, 14 | "skipLibCheck": true, 15 | "resolveJsonModule": true 16 | }, 17 | "include": ["./src"] 18 | } 19 | -------------------------------------------------------------------------------- /packages/table/.fatherrc.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'father'; 2 | 3 | export default defineConfig({ 4 | extends: '../../.fatherrc.base.ts', 5 | }); 6 | -------------------------------------------------------------------------------- /packages/table/src/components/Alert/style.ts: -------------------------------------------------------------------------------- 1 | import type { GenerateStyle, ProAliasToken } from '@ant-design/pro-provider'; 2 | import { setAlpha, useStyle as useAntdStyle } from '@ant-design/pro-provider'; 3 | 4 | export interface ProToken extends ProAliasToken { 5 | componentCls: string; 6 | } 7 | 8 | const genProStyle: GenerateStyle = (token) => { 9 | return { 10 | [token.componentCls]: { 11 | marginBlockEnd: 16, 12 | backgroundColor: setAlpha(token.colorTextBase, 0.02), 13 | borderRadius: token.borderRadius, 14 | border: 'none', 15 | '&-container': { 16 | paddingBlock: token.paddingSM, 17 | paddingInline: token.paddingLG, 18 | }, 19 | '&-info': { 20 | display: 'flex', 21 | alignItems: 'center', 22 | transition: 'all 0.3s', 23 | color: token.colorTextTertiary, 24 | '&-content': { 25 | flex: 1, 26 | }, 27 | '&-option': { 28 | minWidth: 48, 29 | paddingInlineStart: 16, 30 | }, 31 | }, 32 | }, 33 | }; 34 | }; 35 | 36 | export function useStyle(prefixCls: string) { 37 | return useAntdStyle('ProTableAlert', (token) => { 38 | const proToken: ProToken = { 39 | ...token, 40 | componentCls: `.${prefixCls}`, 41 | }; 42 | 43 | return [genProStyle(proToken)]; 44 | }); 45 | } 46 | -------------------------------------------------------------------------------- /packages/table/src/components/DragSortTable/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: DragSortTable - 拖动排序表格 3 | atomId: DragSortTable 4 | --- 5 | 6 | # DragSortTable - 拖动排序表格 7 | 8 | `DragSortTable`排序采用的[dnd-kit](https://dndkit.com/),需要提供`rowKey`来确定数据的唯一值,否则不能正常工作。 9 | 10 | ## Demo 11 | 12 | ### 拖拽排序 13 | 14 | 15 | 16 | ### 拖拽排序编辑表格 17 | 18 | 19 | 20 | ## DragSortTable 21 | 22 | | 属性 | 描述 | 类型 | 默认值 | 23 | | --- | --- | --- | --- | 24 | | dragSortKey | 如配置此参数,则会在该 key 对应的行显示拖拽排序把手,允许拖拽排序 | `string` | - | 25 | | dragSortHandlerRender | 渲染自定义拖动排序把手的函数 如配置了 dragSortKey 但未配置此参数,则使用默认把手图标 | `(rowData: T, idx: number) => React.ReactNode` | `` | 26 | | onDragSortEnd | 拖动排序完成回调 | `(beforeIndex: number, afterIndex: number, newDataSource: T[]) => Promise \| void` | - | 27 | -------------------------------------------------------------------------------- /packages/table/src/components/DragSortTable/style.ts: -------------------------------------------------------------------------------- 1 | import type { GenerateStyle, ProAliasToken } from '@ant-design/pro-provider'; 2 | import { useStyle as useAntdStyle } from '@ant-design/pro-provider'; 3 | 4 | export interface ProListToken extends ProAliasToken { 5 | componentCls: string; 6 | } 7 | 8 | const genProListStyle: GenerateStyle = (token) => { 9 | return { 10 | [token.componentCls]: { 11 | '&-icon': { 12 | marginInlineEnd: 8, 13 | color: token.colorTextSecondary, 14 | cursor: 'grab !important', 15 | padding: 4, 16 | fontSize: 12, 17 | borderRadius: token.borderRadius, 18 | '&:hover': { 19 | color: token.colorText, 20 | backgroundColor: token.colorInfoBg, 21 | }, 22 | }, 23 | }, 24 | }; 25 | }; 26 | 27 | export function useStyle(prefixCls: string) { 28 | return useAntdStyle('DragSortTable', (token) => { 29 | const proListToken: ProListToken = { 30 | ...token, 31 | componentCls: `.${prefixCls}`, 32 | }; 33 | return [genProListStyle(proListToken)]; 34 | }); 35 | } 36 | -------------------------------------------------------------------------------- /packages/table/src/components/ToolBar/FullscreenIcon.tsx: -------------------------------------------------------------------------------- 1 | import { FullscreenExitOutlined, FullscreenOutlined } from '@ant-design/icons'; 2 | import { useIntl } from '@ant-design/pro-provider'; 3 | import { isBrowser } from '@ant-design/pro-utils'; 4 | import { Tooltip } from 'antd'; 5 | import React, { useEffect, useState } from 'react'; 6 | 7 | const FullScreenIcon = () => { 8 | const intl = useIntl(); 9 | const [fullscreen, setFullscreen] = useState(false); 10 | useEffect(() => { 11 | if (!isBrowser()) { 12 | return; 13 | } 14 | document.onfullscreenchange = () => { 15 | setFullscreen(!!document.fullscreenElement); 16 | }; 17 | }, []); 18 | return fullscreen ? ( 19 | 20 | 21 | 22 | ) : ( 23 | 24 | 25 | 26 | ); 27 | }; 28 | 29 | export default React.memo(FullScreenIcon); 30 | -------------------------------------------------------------------------------- /packages/table/src/demos/search.tsx: -------------------------------------------------------------------------------- 1 | import type { ProColumns } from '@ant-design/pro-components'; 2 | import { ProTable } from '@ant-design/pro-components'; 3 | 4 | type GithubIssueItem = { 5 | key: number; 6 | name: string; 7 | createdAt: number; 8 | }; 9 | 10 | const columns: ProColumns[] = [ 11 | { 12 | title: '序号', 13 | dataIndex: 'index', 14 | valueType: 'indexBorder', 15 | }, 16 | { 17 | title: '标题', 18 | dataIndex: 'name', 19 | search: false, 20 | }, 21 | ]; 22 | 23 | export default () => ( 24 | 25 | columns={columns} 26 | request={async (params) => { 27 | console.log(params); 28 | return { 29 | data: [ 30 | { 31 | key: 1, 32 | name: `TradeCode ${1}`, 33 | createdAt: 1602572994055, 34 | }, 35 | ], 36 | success: true, 37 | }; 38 | }} 39 | search={false} 40 | rowKey="key" 41 | options={{ 42 | search: true, 43 | }} 44 | headerTitle="toolbar 中搜索" 45 | /> 46 | ); 47 | -------------------------------------------------------------------------------- /packages/table/src/utils/columnSort.ts: -------------------------------------------------------------------------------- 1 | import type { ColumnsState } from '../Store/Provide'; 2 | 3 | export const columnSort = 4 | (columnsMap: Record) => (a: any, b: any) => { 5 | const { fixed: aFixed, index: aIndex } = a; 6 | const { fixed: bFixed, index: bIndex } = b; 7 | if ( 8 | (aFixed === 'left' && bFixed !== 'left') || 9 | (bFixed === 'right' && aFixed !== 'right') 10 | ) { 11 | return -2; 12 | } 13 | if ( 14 | (bFixed === 'left' && aFixed !== 'left') || 15 | (aFixed === 'right' && bFixed !== 'right') 16 | ) { 17 | return 2; 18 | } 19 | // 如果没有index,在 dataIndex 或者 key 不存在的时候他会报错 20 | const aKey = a.key || `${aIndex}`; 21 | const bKey = b.key || `${bIndex}`; 22 | if (columnsMap[aKey]?.order || columnsMap[bKey]?.order) { 23 | return (columnsMap[aKey]?.order || 0) - (columnsMap[bKey]?.order || 0); 24 | } 25 | return (a.index || 0) - (b.index || 0); 26 | }; 27 | -------------------------------------------------------------------------------- /packages/table/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./", 4 | "target": "esnext", 5 | "module": "ESNext", 6 | "moduleResolution": "node", 7 | "jsx": "react-jsx", 8 | "esModuleInterop": true, 9 | "experimentalDecorators": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "noImplicitReturns": true, 13 | "declaration": true, 14 | "skipLibCheck": true, 15 | "resolveJsonModule": true, 16 | "paths": { 17 | "@ant-design/pro-form": ["../../packages/form/src/index.tsx"], 18 | "@ant-design/pro-field": ["../../packages/field/src/index.tsx"], 19 | "@ant-design/pro-provider": ["../../packages/provider/src/index.tsx"], 20 | "@ant-design/pro-utils": ["../../packages/utils/src/index.tsx"], 21 | "@ant-design/pro-card": ["../../packages/card/src/index.tsx"], 22 | "@ant-design/pro-components": ["../../packages/components/src/index.tsx"] 23 | } 24 | }, 25 | "include": ["./src"] 26 | } 27 | -------------------------------------------------------------------------------- /packages/utils/.fatherrc.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'father'; 2 | 3 | export default defineConfig({ 4 | extends: '../../.fatherrc.base.ts', 5 | }); 6 | -------------------------------------------------------------------------------- /packages/utils/README.md: -------------------------------------------------------------------------------- 1 | # @ant-design/pro-utils 2 | 3 | > @ant-design/pro-utils. 4 | 5 | See our website [@ant-design/pro-utils](https://procomponent.ant.design/) for more information. 6 | 7 | ## Install 8 | 9 | Using npm: 10 | 11 | ```bash 12 | $ npm install --save @ant-design/pro-utils 13 | ``` 14 | 15 | or using yarn: 16 | 17 | ```bash 18 | $ yarn add @ant-design/pro-utils 19 | ``` 20 | -------------------------------------------------------------------------------- /packages/utils/src/compareVersions/menuOverlayCompatible.tsx: -------------------------------------------------------------------------------- 1 | import type { MenuProps } from 'antd'; 2 | import { Menu } from 'antd'; 3 | import { omitUndefined } from '../omitUndefined'; 4 | import { compareVersions } from './index'; 5 | import { getVersion } from './openVisibleCompatible'; 6 | 7 | const menuOverlayCompatible = (menu: MenuProps) => { 8 | const props = 9 | compareVersions(getVersion(), '4.24.0') > -1 10 | ? { 11 | menu: menu, 12 | } 13 | : { 14 | overlay: , 15 | }; 16 | 17 | return omitUndefined(props); 18 | }; 19 | 20 | export { menuOverlayCompatible }; 21 | -------------------------------------------------------------------------------- /packages/utils/src/compareVersions/openVisibleCompatible.ts: -------------------------------------------------------------------------------- 1 | import { version } from 'antd'; 2 | import { omitUndefined } from '../omitUndefined'; 3 | import { compareVersions } from './index'; 4 | 5 | export const getVersion = () => { 6 | if (typeof process === 'undefined') return version; 7 | return process?.env?.ANTD_VERSION || version; 8 | }; 9 | 10 | const openVisibleCompatible = (open?: boolean, onOpenChange?: any) => { 11 | const props = 12 | compareVersions(getVersion(), '4.23.0') > -1 13 | ? { 14 | open: open, 15 | onOpenChange: onOpenChange, 16 | } 17 | : { 18 | visible: open, 19 | onVisibleChange: onOpenChange, 20 | }; 21 | 22 | return omitUndefined(props); 23 | }; 24 | 25 | export { openVisibleCompatible }; 26 | -------------------------------------------------------------------------------- /packages/utils/src/compatible/compatibleBorder.ts: -------------------------------------------------------------------------------- 1 | import { version } from 'antd'; 2 | import { Variant } from 'antd/es/config-provider'; 3 | import { compareVersions } from '../compareVersions'; 4 | 5 | /** 6 | * 兼容 antd 5.13.0 以下版本的 bordered 属性 7 | * @param bordered 8 | * @returns 9 | */ 10 | export const compatibleBorder = (bordered?: boolean) => { 11 | if (bordered === undefined) { 12 | return {}; 13 | } 14 | return compareVersions(version, '5.13.0') <= 0 15 | ? { bordered } 16 | : ({ 17 | variant: bordered ? undefined : 'borderless', 18 | } as { 19 | variant?: Variant; 20 | }); 21 | }; 22 | -------------------------------------------------------------------------------- /packages/utils/src/components/DropdownFooter/style.ts: -------------------------------------------------------------------------------- 1 | import type { GenerateStyle, ProAliasToken } from '@ant-design/pro-provider'; 2 | import { useStyle as useAntdStyle } from '@ant-design/pro-provider'; 3 | 4 | export interface ProToken extends ProAliasToken { 5 | componentCls: string; 6 | } 7 | 8 | const genProStyle: GenerateStyle = (token) => { 9 | return { 10 | [token.componentCls]: { 11 | display: 'flex', 12 | justifyContent: 'space-between', 13 | paddingBlock: 8, 14 | paddingInlineStart: 8, 15 | paddingInlineEnd: 8, 16 | borderBlockStart: `1px solid ${token.colorSplit}`, 17 | }, 18 | }; 19 | }; 20 | 21 | export function useStyle(prefixCls: string) { 22 | return useAntdStyle('DropdownFooter', (token) => { 23 | const proToken: ProToken = { 24 | ...token, 25 | componentCls: `.${prefixCls}`, 26 | }; 27 | 28 | return [genProStyle(proToken)]; 29 | }); 30 | } 31 | -------------------------------------------------------------------------------- /packages/utils/src/components/ErrorBoundary/index.tsx: -------------------------------------------------------------------------------- 1 | import { Result } from 'antd'; 2 | import type { ErrorInfo } from 'react'; 3 | import React from 'react'; 4 | 5 | // eslint-disable-next-line @typescript-eslint/ban-types 6 | class ErrorBoundary extends React.Component< 7 | { children?: React.ReactNode }, 8 | { hasError: boolean; errorInfo: string } 9 | > { 10 | state = { hasError: false, errorInfo: '' }; 11 | 12 | static getDerivedStateFromError(error: Error) { 13 | return { hasError: true, errorInfo: error.message }; 14 | } 15 | 16 | componentDidCatch(error: any, errorInfo: ErrorInfo) { 17 | // You can also log the error to an error reporting service 18 | // eslint-disable-next-line no-console 19 | console.log(error, errorInfo); 20 | } 21 | 22 | render() { 23 | if (this.state.hasError) { 24 | // You can render any custom fallback UI 25 | return ( 26 | 31 | ); 32 | } 33 | return this.props.children; 34 | } 35 | } 36 | 37 | export { ErrorBoundary }; 38 | -------------------------------------------------------------------------------- /packages/utils/src/components/FilterDropdown/style.ts: -------------------------------------------------------------------------------- 1 | import type { GenerateStyle, ProAliasToken } from '@ant-design/pro-provider'; 2 | import { useStyle as useAntdStyle } from '@ant-design/pro-provider'; 3 | 4 | export interface ProToken extends ProAliasToken { 5 | componentCls: string; 6 | } 7 | 8 | const genProStyle: GenerateStyle = (token) => { 9 | return { 10 | [`${token.componentCls}-label`]: { cursor: 'pointer' }, 11 | [`${token.componentCls}-overlay`]: { 12 | minWidth: '200px', 13 | marginBlockStart: '4px', 14 | }, 15 | [`${token.componentCls}-content`]: { paddingBlock: 16, paddingInline: 16 }, 16 | }; 17 | }; 18 | 19 | export function useStyle(prefixCls: string) { 20 | return useAntdStyle('FilterDropdown', (token) => { 21 | const proToken: ProToken = { 22 | ...token, 23 | componentCls: `.${prefixCls}`, 24 | }; 25 | 26 | return [genProStyle(proToken)]; 27 | }); 28 | } 29 | -------------------------------------------------------------------------------- /packages/utils/src/getFieldPropsOrFormItemProps/index.tsx: -------------------------------------------------------------------------------- 1 | import type { FormInstance } from 'antd'; 2 | import { runFunction } from '../runFunction'; 3 | 4 | /** 5 | * 因为 fieldProps 支持了 function 所以新增了这个方法 6 | * 7 | * @param fieldProps 8 | * @param form 9 | */ 10 | export const getFieldPropsOrFormItemProps = ( 11 | fieldProps: any, 12 | form?: FormInstance | null, 13 | extraProps?: any, 14 | ): Record & { 15 | onChange: any; 16 | colSize: number; 17 | } => { 18 | if (form === undefined) { 19 | return fieldProps as any; 20 | } 21 | return runFunction(fieldProps, form, extraProps); 22 | }; 23 | -------------------------------------------------------------------------------- /packages/utils/src/hooks/useDebounceFn/index.ts: -------------------------------------------------------------------------------- 1 | import { useCallback, useEffect, useRef } from 'react'; 2 | import { useRefFunction } from '../useRefFunction'; 3 | /** 4 | * 一个去抖的 hook,传入一个 function,返回一个去抖后的 function 5 | * @param {(...args:T) => Promise} fn 6 | * @param {number} wait? 7 | */ 8 | export function useDebounceFn( 9 | fn: (...args: T) => Promise, 10 | wait?: number, 11 | ) { 12 | const callback = useRefFunction(fn); 13 | 14 | const timer = useRef(); 15 | 16 | const cancel = useCallback(() => { 17 | if (timer.current) { 18 | clearTimeout(timer.current); 19 | timer.current = null; 20 | } 21 | }, []); 22 | 23 | const run = useCallback( 24 | async (...args: any): Promise => { 25 | if (wait === 0 || wait === undefined) { 26 | return callback(...args); 27 | } 28 | cancel(); 29 | return new Promise((resolve) => { 30 | timer.current = setTimeout(async () => { 31 | resolve(await callback(...args)); 32 | return; 33 | }, wait); 34 | }); 35 | }, 36 | [callback, cancel, wait], 37 | ); 38 | 39 | useEffect(() => { 40 | return cancel; 41 | }, [cancel]); 42 | 43 | return { 44 | run, 45 | cancel, 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /packages/utils/src/hooks/useDebounceValue/index.ts: -------------------------------------------------------------------------------- 1 | import type { DependencyList } from 'react'; 2 | import { useEffect, useState } from 'react'; 3 | import { useLatest } from '../useLatest'; 4 | /** 5 | * 一个去抖的setState 减少更新的频率 6 | * @param {T} value 7 | * @param {number=100} delay 8 | * @param {DependencyList} deps? 9 | * @returns T 10 | */ 11 | export function useDebounceValue( 12 | value: T, 13 | delay: number = 100, 14 | deps?: DependencyList, 15 | ): T { 16 | const [debouncedValue, setDebouncedValue] = useState(value); 17 | const valueRef = useLatest(value); 18 | 19 | useEffect( 20 | () => { 21 | const handler = setTimeout(() => { 22 | setDebouncedValue(valueRef.current); 23 | }, delay); 24 | 25 | return () => clearTimeout(handler); 26 | }, 27 | // eslint-disable-next-line react-hooks/exhaustive-deps 28 | deps ? [delay, ...deps] : undefined, 29 | ); 30 | 31 | return debouncedValue; 32 | } 33 | -------------------------------------------------------------------------------- /packages/utils/src/hooks/useDeepCompareMemo/index.ts: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { useDeepCompareMemoize } from '../useDeepCompareEffect'; 3 | 4 | /** 5 | * `useDeepCompareMemo` will only recompute the memoized value when one of the 6 | * `deps` has changed. 7 | * 8 | * Usage note: only use this if `deps` are objects or arrays that contain 9 | * objects. Otherwise you should just use React.useMemo. 10 | * 11 | */ 12 | function useDeepCompareMemo( 13 | factory: () => T, 14 | dependencies: React.DependencyList, 15 | ) { 16 | return React.useMemo( 17 | factory, 18 | useDeepCompareMemoize(dependencies) as unknown as React.DependencyList, 19 | ); 20 | } 21 | 22 | export default useDeepCompareMemo; 23 | -------------------------------------------------------------------------------- /packages/utils/src/hooks/useDocumentTitle/index.ts: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react'; 2 | import { isBrowser } from '../../isBrowser'; 3 | 4 | export function useDocumentTitle( 5 | titleInfo: { 6 | title: string; 7 | id: string; 8 | pageName: string; 9 | }, 10 | appDefaultTitle: string | false, 11 | ) { 12 | const titleText = 13 | typeof titleInfo.pageName === 'string' ? titleInfo.title : appDefaultTitle; 14 | useEffect(() => { 15 | if (isBrowser() && titleText) { 16 | document.title = titleText; 17 | } 18 | }, [titleInfo.title, titleText]); 19 | } 20 | -------------------------------------------------------------------------------- /packages/utils/src/hooks/useForceRender/index.ts: -------------------------------------------------------------------------------- 1 | import { useCallback, useState } from 'react'; 2 | 3 | export default function useForceRender() { 4 | const [, setValue] = useState(true); 5 | 6 | const updateValue = useCallback(() => setValue((oldValue) => !oldValue), []); 7 | 8 | return updateValue; 9 | } 10 | -------------------------------------------------------------------------------- /packages/utils/src/hooks/useLatest/index.ts: -------------------------------------------------------------------------------- 1 | import { useRef } from 'react'; 2 | 3 | /** 4 | * @see https://github.com/streamich/react-use/blob/master/docs/useLatest.md 5 | */ 6 | export const useLatest = (value: T): { readonly current: T } => { 7 | const ref = useRef(value); 8 | ref.current = value; 9 | return ref; 10 | }; 11 | -------------------------------------------------------------------------------- /packages/utils/src/hooks/usePrevious/index.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useRef } from 'react'; 2 | 3 | export const usePrevious = (state: T): T | undefined => { 4 | const ref = useRef(); 5 | 6 | useEffect(() => { 7 | ref.current = state; 8 | }); 9 | 10 | return ref.current; 11 | }; 12 | -------------------------------------------------------------------------------- /packages/utils/src/hooks/useReactiveRef/index.ts: -------------------------------------------------------------------------------- 1 | import type { MutableRefObject, RefObject } from 'react'; 2 | import useForceRender from '../useForceRender'; 3 | import { useRefCallback } from '../useRefCallback'; 4 | 5 | export function useReactiveRef(initialValue: T): MutableRefObject; 6 | 7 | export function useReactiveRef(initialValue: T | null): RefObject; 8 | 9 | export function useReactiveRef(): MutableRefObject< 10 | T | undefined 11 | >; 12 | 13 | export function useReactiveRef( 14 | initialValue?: T | null, 15 | ): MutableRefObject { 16 | const forceRender = useForceRender(); 17 | 18 | const ref = useRefCallback(forceRender, initialValue); 19 | 20 | return ref; 21 | } 22 | -------------------------------------------------------------------------------- /packages/utils/src/hooks/useRefCallback/index.ts: -------------------------------------------------------------------------------- 1 | import type { MutableRefObject, RefObject } from 'react'; 2 | import { useMemo } from 'react'; 3 | 4 | type Callback = (currentRef: T) => void; 5 | 6 | export function useRefCallback( 7 | callback: Callback>, 8 | initialValue: T, 9 | ): MutableRefObject; 10 | 11 | export function useRefCallback( 12 | callback: Callback>, 13 | initialValue: T | null, 14 | ): RefObject; 15 | 16 | export function useRefCallback( 17 | callback: Callback>, 18 | ): MutableRefObject; 19 | 20 | export function useRefCallback( 21 | callback: Callback>, 22 | initialValue?: T | null, 23 | ): MutableRefObject { 24 | const ref: MutableRefObject = useMemo(() => { 25 | const defaultValue = { 26 | current: initialValue, 27 | }; 28 | 29 | return new Proxy(defaultValue, { 30 | set(target, prop, newValue: T) { 31 | if (!Object.is((target as any)[prop], newValue)) { 32 | (target as any)[prop] = newValue; 33 | callback(ref); 34 | } 35 | 36 | return true; 37 | }, 38 | }); 39 | }, []); 40 | 41 | return ref; 42 | } 43 | -------------------------------------------------------------------------------- /packages/utils/src/hooks/useRefFunction/index.ts: -------------------------------------------------------------------------------- 1 | import { useCallback, useRef } from 'react'; 2 | 3 | const useRefFunction = any>(reFunction: T) => { 4 | const ref = useRef(null); 5 | ref.current = reFunction; 6 | return useCallback((...rest: Parameters): ReturnType => { 7 | return ref.current?.(...(rest as any)); 8 | }, []); 9 | }; 10 | 11 | export { useRefFunction }; 12 | -------------------------------------------------------------------------------- /packages/utils/src/isBrowser/index.ts: -------------------------------------------------------------------------------- 1 | const isNode = 2 | typeof process !== 'undefined' && 3 | process.versions != null && 4 | process.versions.node != null; 5 | 6 | /** 7 | * 用于判断当前是否在浏览器环境中。 8 | * 首先会判断当前是否处于测试环境中(通过 process.env.NODE_ENV === 'TEST' 判断), 9 | * 如果是,则返回 true。否则,会进一步判断是否存在 window 对象、document 对象以及 matchMedia 方法 10 | * 同时通过 !isNode 判断当前不是在服务器(Node.js)环境下执行, 11 | * 如果都符合,则返回 true 表示当前处于浏览器环境中。 12 | * @returns boolean 13 | */ 14 | export const isBrowser = () => { 15 | if (typeof process !== 'undefined' && process.env.NODE_ENV === 'TEST') { 16 | return true; 17 | } 18 | return ( 19 | typeof window !== 'undefined' && 20 | typeof window.document !== 'undefined' && 21 | typeof window.matchMedia !== 'undefined' && 22 | !isNode 23 | ); 24 | }; 25 | -------------------------------------------------------------------------------- /packages/utils/src/isDropdownValueType/index.ts: -------------------------------------------------------------------------------- 1 | export const isDropdownValueType = (valueType: string) => { 2 | let isDropdown = false; 3 | if ( 4 | (typeof valueType === 'string' && 5 | valueType.startsWith('date') && 6 | !valueType.endsWith('Range')) || 7 | valueType === 'select' || 8 | valueType === 'time' 9 | ) { 10 | isDropdown = true; 11 | } 12 | return isDropdown; 13 | }; 14 | -------------------------------------------------------------------------------- /packages/utils/src/isImg/index.ts: -------------------------------------------------------------------------------- 1 | /** 判断是否是图片链接 */ 2 | export function isImg(path: string): boolean { 3 | return /\w.(png|jpg|jpeg|svg|webp|gif|bmp)$/i.test(path); 4 | } 5 | -------------------------------------------------------------------------------- /packages/utils/src/isNil/index.ts: -------------------------------------------------------------------------------- 1 | export const isNil = (value: any): value is null | undefined => 2 | value === null || value === undefined; 3 | -------------------------------------------------------------------------------- /packages/utils/src/isUrl/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 判断是不是一个 url 3 | * @param {string|undefined} path 4 | * @returns boolean 5 | */ 6 | export const isUrl = (path: string | undefined): boolean => { 7 | if (!path) return false; 8 | if (!path.startsWith('http')) { 9 | return false; 10 | } 11 | try { 12 | const url = new URL(path); 13 | return !!url; 14 | } catch (error) { 15 | return false; 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /packages/utils/src/merge/index.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable prefer-rest-params */ 2 | 3 | /** 4 | * 用于合并 n 个对象 5 | * @param {any[]} ...rest 6 | * @returns T 7 | */ 8 | const merge = (...rest: any[]): T => { 9 | const obj = {} as Record as any; 10 | const il = rest.length; 11 | let key; 12 | let i = 0; 13 | for (; i < il; i += 1) { 14 | // eslint-disable-next-line no-restricted-syntax 15 | for (key in rest[i]) { 16 | if (rest[i].hasOwnProperty(key)) { 17 | if ( 18 | typeof obj[key] === 'object' && 19 | typeof rest[i][key] === 'object' && 20 | obj[key] !== undefined && 21 | obj[key] !== null && 22 | !Array.isArray(obj[key]) && 23 | !Array.isArray(rest[i][key]) 24 | ) { 25 | obj[key] = { 26 | ...obj[key], 27 | ...rest[i][key], 28 | }; 29 | } else { 30 | obj[key] = rest[i][key]; 31 | } 32 | } 33 | } 34 | } 35 | return obj as T; 36 | }; 37 | 38 | export { merge }; 39 | -------------------------------------------------------------------------------- /packages/utils/src/nanoid/index.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable prefer-const */ 2 | 3 | let index = 0; 4 | let genNanoid = (t = 21) => { 5 | if (typeof window === 'undefined') return (index += 1).toFixed(0); 6 | if (!window.crypto) return (index += 1).toFixed(0); 7 | let e = '', 8 | r = crypto.getRandomValues(new Uint8Array(t)); 9 | // eslint-disable-next-line no-param-reassign 10 | for (; t--; ) { 11 | let n = 63 & r[t]; 12 | e += 13 | n < 36 14 | ? n.toString(36) 15 | : n < 62 16 | ? (n - 26).toString(36).toUpperCase() 17 | : n < 63 18 | ? '_' 19 | : '-'; 20 | } 21 | return e; 22 | }; 23 | 24 | /** 25 | * 生成uuid,如果不支持 randomUUID,就用 genNanoid 26 | * 27 | * @returns string 28 | */ 29 | export const nanoid = (): string => { 30 | if (typeof window === 'undefined') return genNanoid(); 31 | // @ts-ignore 32 | if ( 33 | window.crypto && 34 | window.crypto.randomUUID && 35 | typeof crypto.randomUUID == 'function' 36 | ) { 37 | // @ts-ignore 38 | return crypto.randomUUID(); 39 | } 40 | return genNanoid(); 41 | }; 42 | -------------------------------------------------------------------------------- /packages/utils/src/omitBoolean/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 剔除 boolean 值 3 | * @param {boolean|T} obj 4 | * @returns T 5 | */ 6 | export const omitBoolean = (obj: boolean | T): T | undefined => { 7 | if (obj && obj !== true) { 8 | return obj; 9 | } 10 | return undefined; 11 | }; 12 | -------------------------------------------------------------------------------- /packages/utils/src/omitUndefined/index.ts: -------------------------------------------------------------------------------- 1 | type OmitUndefined = { 2 | [P in keyof T]: NonNullable; 3 | }; 4 | 5 | export const omitUndefined = >( 6 | obj: T, 7 | ): OmitUndefined => { 8 | const newObj = {} as Record as T; 9 | Object.keys(obj || {}).forEach((key) => { 10 | if (obj[key] !== undefined) { 11 | (newObj as any)[key] = obj[key]; 12 | } 13 | }); 14 | if (Object.keys(newObj as Record).length < 1) { 15 | return undefined as any; 16 | } 17 | return newObj as OmitUndefined; 18 | }; 19 | -------------------------------------------------------------------------------- /packages/utils/src/omitUndefinedAndEmptyArr/index.ts: -------------------------------------------------------------------------------- 1 | export const omitUndefinedAndEmptyArr = >( 2 | obj: T, 3 | ): T => { 4 | const newObj = {} as Record as Record; 5 | Object.keys(obj || {}).forEach((key) => { 6 | if (Array.isArray(obj[key]) && obj[key]?.length === 0) { 7 | return; 8 | } 9 | if (obj[key] === undefined) { 10 | return; 11 | } 12 | newObj[key] = obj[key]; 13 | }); 14 | return newObj as T; 15 | }; 16 | -------------------------------------------------------------------------------- /packages/utils/src/parseValueToMoment/index.ts: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs'; 2 | import customParseFormat from 'dayjs/plugin/customParseFormat'; 3 | import { isNil } from '../isNil'; 4 | 5 | dayjs.extend(customParseFormat); 6 | 7 | type DateValue = 8 | | dayjs.Dayjs 9 | | dayjs.Dayjs[] 10 | | string 11 | | string[] 12 | | number 13 | | number[]; 14 | 15 | /** 16 | * 一个比较hack的moment判断工具 17 | * @param value 18 | * @returns 19 | */ 20 | const isMoment = (value: any) => !!value?._isAMomentObject; 21 | 22 | export const parseValueToDay = ( 23 | value: DateValue, 24 | formatter?: string, 25 | ): dayjs.Dayjs | dayjs.Dayjs[] | null | undefined => { 26 | if (isNil(value) || dayjs.isDayjs(value) || isMoment(value)) { 27 | if (isMoment(value)) { 28 | return dayjs(value as dayjs.Dayjs); 29 | } 30 | return value as dayjs.Dayjs | null | undefined; 31 | } 32 | if (Array.isArray(value)) { 33 | return (value as any[]).map( 34 | (v) => parseValueToDay(v, formatter) as dayjs.Dayjs, 35 | ); 36 | } 37 | if (typeof value === 'number') return dayjs(value); 38 | return dayjs(value, formatter); 39 | }; 40 | -------------------------------------------------------------------------------- /packages/utils/src/pickProFormItemProps/index.tsx: -------------------------------------------------------------------------------- 1 | const antdFormItemPropsList = [ 2 | // https://ant.design/components/form-cn/#Form.Item 3 | 'colon', 4 | 'dependencies', 5 | 'extra', 6 | 'getValueFromEvent', 7 | 'getValueProps', 8 | 'hasFeedback', 9 | 'help', 10 | 'htmlFor', 11 | 'initialValue', 12 | 'noStyle', 13 | 'label', 14 | 'labelAlign', 15 | 'labelCol', 16 | 'name', 17 | 'preserve', 18 | 'normalize', 19 | 'required', 20 | 'rules', 21 | 'shouldUpdate', 22 | 'trigger', 23 | 'validateFirst', 24 | 'validateStatus', 25 | 'validateTrigger', 26 | 'valuePropName', 27 | 'wrapperCol', 28 | 'hidden', 29 | // 我自定义的 30 | 'addonBefore', 31 | 'addonAfter', 32 | 'addonWarpStyle', 33 | ]; 34 | 35 | // eslint-disable-next-line @typescript-eslint/ban-types 36 | export function pickProFormItemProps(props: {}) { 37 | const attrs = {} as Record; 38 | antdFormItemPropsList.forEach((key) => { 39 | if ((props as any)[key] !== undefined) { 40 | attrs[key] = (props as any)[key]; 41 | } 42 | }); 43 | return attrs; 44 | } 45 | -------------------------------------------------------------------------------- /packages/utils/src/pickProProps/index.tsx: -------------------------------------------------------------------------------- 1 | const proFieldProps = `valueType request plain renderFormItem render text formItemProps valueEnum`; 2 | 3 | const proFormProps = `fieldProps isDefaultDom groupProps contentRender submitterProps submitter`; 4 | 5 | export function pickProProps(props: Record) { 6 | const propList = `${proFieldProps} ${proFormProps}`.split(/[\s\n]+/); 7 | 8 | const attrs = {} as Record; 9 | Object.keys(props || {}).forEach((key) => { 10 | if (propList.includes(key)) { 11 | return; 12 | } 13 | attrs[key] = props[key]; 14 | }); 15 | return attrs; 16 | } 17 | -------------------------------------------------------------------------------- /packages/utils/src/runFunction/index.ts: -------------------------------------------------------------------------------- 1 | /** 如果是个方法执行一下它 */ 2 | export function runFunction(valueEnum: any, ...rest: T) { 3 | if (typeof valueEnum === 'function') { 4 | return valueEnum(...rest); 5 | } 6 | return valueEnum; 7 | } 8 | -------------------------------------------------------------------------------- /packages/utils/src/stringify/index.ts: -------------------------------------------------------------------------------- 1 | import { configure } from 'safe-stable-stringify'; 2 | 3 | const stringify = configure({ 4 | bigint: true, 5 | circularValue: 'Magic circle!', 6 | deterministic: false, 7 | maximumDepth: 4, 8 | // maximumBreadth: 4, 9 | }); 10 | 11 | export { configure, stringify }; 12 | 13 | export default stringify; 14 | -------------------------------------------------------------------------------- /packages/utils/src/useMediaQuery/query.ts: -------------------------------------------------------------------------------- 1 | import { useLayoutEffect, useState } from 'react'; 2 | 3 | export default function useMediaQuery(mediaQuery: string) { 4 | const isSsr = typeof window === 'undefined'; 5 | 6 | const [matches, setMatches] = useState(() => 7 | isSsr ? false : window.matchMedia(mediaQuery).matches, 8 | ); 9 | useLayoutEffect(() => { 10 | if (isSsr) { 11 | return; 12 | } 13 | const mediaQueryList = window.matchMedia(mediaQuery); 14 | const listener = (e: any) => setMatches(e.matches); 15 | mediaQueryList.addListener(listener); 16 | return () => mediaQueryList.removeListener(listener); 17 | }, [mediaQuery]); 18 | return matches; 19 | } 20 | -------------------------------------------------------------------------------- /packages/utils/src/useMountMergeState/index.ts: -------------------------------------------------------------------------------- 1 | import useMergedState from 'rc-util/lib/hooks/useMergedState'; 2 | 3 | export { useMergedState as useMountMergeState }; 4 | -------------------------------------------------------------------------------- /packages/utils/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./", 4 | "target": "esnext", 5 | "module": "ESNext", 6 | "moduleResolution": "node", 7 | "jsx": "react-jsx", 8 | "esModuleInterop": true, 9 | "experimentalDecorators": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "noImplicitReturns": true, 13 | "declaration": true, 14 | "skipLibCheck": true, 15 | "resolveJsonModule": true, 16 | "paths": { 17 | "@ant-design/pro-provider": ["../../packages/provider/src/index.tsx"] 18 | } 19 | }, 20 | "include": ["./src"] 21 | } 22 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'packages/*' 3 | -------------------------------------------------------------------------------- /public/CNAME: -------------------------------------------------------------------------------- 1 | procomponents.ant.design 2 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ant-design/pro-components/6b51b6f750d7fd0f833d4536e578ea22ce94f708/public/favicon.ico -------------------------------------------------------------------------------- /public/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ant-design/pro-components/6b51b6f750d7fd0f833d4536e578ea22ce94f708/public/icon.png -------------------------------------------------------------------------------- /scripts/changelogs.js: -------------------------------------------------------------------------------- 1 | const docker = require('@umijs/doctor'); 2 | const path = require('path'); 3 | 4 | const repo_path = path.join(__dirname, '..'); 5 | 6 | const genChangelogs = () => { 7 | docker.genChangelogs(repo_path); 8 | }; 9 | 10 | genChangelogs(); 11 | -------------------------------------------------------------------------------- /scripts/checkPublish.js: -------------------------------------------------------------------------------- 1 | const docker = require('@umijs/doctor'); 2 | const path = require('path'); 3 | 4 | const repo_path = path.join(__dirname, '..'); 5 | 6 | const checkPublish = () => { 7 | docker.checkPublish(repo_path); 8 | }; 9 | 10 | checkPublish(); 11 | -------------------------------------------------------------------------------- /scripts/gen_version.js: -------------------------------------------------------------------------------- 1 | const { readdirSync, existsSync, fstat, writeFileSync } = require('fs'); 2 | const { join } = require('path'); 3 | const prettier = require('prettier'); 4 | 5 | // utils must build before core 6 | // runtime must build before renderer-react 7 | let packagesPath = join(__dirname, '../packages'); 8 | const pkgList = readdirSync(packagesPath) 9 | .filter((pkg) => pkg.charAt(0) !== '.') 10 | .map((pkg) => { 11 | const package_path = join(packagesPath, pkg); 12 | if (!existsSync(join(package_path, 'package.json'))) return; 13 | const json = require(join(package_path, 'package.json')); 14 | return { 15 | name: json.name, 16 | version: json.version, 17 | }; 18 | }); 19 | 20 | const file_content = ` 21 | 22 | export const version = { 23 | ${pkgList 24 | .map((pak) => { 25 | return `"${pak.name}": '${pak.version}'`; 26 | }) 27 | .join(',\n ')} 28 | } 29 | `; 30 | 31 | prettier 32 | .format(file_content, { parser: 'typescript' }) 33 | .then((formattedCode) => { 34 | writeFileSync( 35 | join(packagesPath, 'components', '/src/version.ts'), 36 | formattedCode, 37 | ); 38 | }); 39 | -------------------------------------------------------------------------------- /scripts/generateSizeLimit.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const fs = require('fs'); 3 | const writePkg = require('write-pkg'); 4 | 5 | const cwd = process.cwd(); 6 | const ignoreDirPath = ['.DS_Store']; 7 | 8 | const filePath = path.resolve(cwd, 'package.json'); 9 | const packagesDir = path.resolve(cwd, 'packages'); 10 | const json = JSON.parse(fs.readFileSync(filePath, 'utf8')); 11 | 12 | delete json['size-limit']; 13 | 14 | let componentsNames = fs.readdirSync(packagesDir); 15 | 16 | componentsNames = componentsNames.filter( 17 | (dir) => ignoreDirPath.indexOf(dir) === -1, 18 | ); 19 | 20 | (async () => { 21 | const sizeLimitConfig = []; 22 | componentsNames.forEach((component) => { 23 | sizeLimitConfig.push({ 24 | path: `packages/${component}/lib/**/*.js`, 25 | limit: '2 s', 26 | webpack: false, 27 | running: false, 28 | }); 29 | sizeLimitConfig.push({ 30 | path: `packages/${component}/es/**/*.js`, 31 | limit: '2 s', 32 | webpack: false, 33 | running: false, 34 | }); 35 | }); 36 | 37 | await writePkg(cwd, { ...json, 'size-limit': sizeLimitConfig }); 38 | })(); 39 | -------------------------------------------------------------------------------- /scripts/preDeploy.js: -------------------------------------------------------------------------------- 1 | const { existsSync, readdirSync } = require('fs'); 2 | const { join } = require('path'); 3 | 4 | (async () => { 5 | const pkgs = readdirSync(join(__dirname, '../packages')).filter( 6 | (pkg) => pkg.charAt(0) !== '.', 7 | ); 8 | 9 | pkgs.forEach((shortName) => { 10 | const distPath = join(__dirname, '..', 'packages', shortName, 'es'); 11 | const distExists = existsSync(distPath); 12 | if (!distExists) { 13 | // 如果没有先生成 dist 目录,dumi build 之后,在 codesandbox 里面会找不到 css 样式。 14 | console.error('Please execute "pnpm build" first!'); 15 | process.exit(1); 16 | } 17 | }); 18 | })(); 19 | -------------------------------------------------------------------------------- /scripts/replaceEs.js: -------------------------------------------------------------------------------- 1 | function replacePath(path) { 2 | if (path.node.source && path.node.source.value?.includes('es/')) { 3 | const esModule = path.node.source.value.replace('/es/', '/lib/'); 4 | try { 5 | if (require.resolve(esModule)) { 6 | path.node.source.value = esModule; 7 | } 8 | } catch (error) { 9 | console.log(error); 10 | } 11 | } 12 | } 13 | 14 | function replaceLib() { 15 | return { 16 | visitor: { 17 | ImportDeclaration: replacePath, 18 | ExportNamedDeclaration: replacePath, 19 | }, 20 | }; 21 | } 22 | module.exports = replaceLib; 23 | -------------------------------------------------------------------------------- /scripts/replaceLib.js: -------------------------------------------------------------------------------- 1 | function replacePath(path) { 2 | if (path.node.source && path.node.source.value?.includes('lib/')) { 3 | const esModule = path.node.source.value.replace('/lib/', '/es/'); 4 | try { 5 | if (require.resolve(esModule)) { 6 | path.node.source.value = esModule; 7 | } 8 | } catch (error) { 9 | console.log(error); 10 | } 11 | } 12 | } 13 | 14 | function replaceLib() { 15 | return { 16 | visitor: { 17 | ImportDeclaration: replacePath, 18 | ExportNamedDeclaration: replacePath, 19 | }, 20 | }; 21 | } 22 | module.exports = replaceLib; 23 | -------------------------------------------------------------------------------- /scripts/replaceLodash.js: -------------------------------------------------------------------------------- 1 | function replaceLodashImport(path) { 2 | if (path.node.source && path.node.source.value?.startsWith('lodash-es/')) { 3 | const cjsImport = path.node.source.value.replace('lodash-es/', 'lodash/'); 4 | try { 5 | if (require.resolve(cjsImport)) { 6 | path.node.source.value = cjsImport; 7 | } 8 | } catch (error) { 9 | console.log(error); 10 | } 11 | } 12 | } 13 | 14 | function replaceLodash() { 15 | return { 16 | visitor: { 17 | ImportDeclaration: replaceLodashImport, 18 | }, 19 | }; 20 | } 21 | module.exports = replaceLodash; 22 | -------------------------------------------------------------------------------- /scripts/syncTNPM.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable global-require */ 2 | const execa = require('execa'); 3 | const { join } = require('path'); 4 | const getPackages = require('./utils/getPackages'); 5 | 6 | process.setMaxListeners(Infinity); 7 | 8 | module.exports = (publishPkgList) => { 9 | const pkgList = (publishPkgList || getPackages()).map((name) => { 10 | // eslint-disable-next-line import/no-dynamic-require 11 | return require(join(__dirname, '../packages', name, 'package.json')).name; 12 | }); 13 | const commands = pkgList.map((pkg) => { 14 | const subprocess = execa('tnpm', ['sync', pkg]); 15 | subprocess.stdout.pipe(process.stdout); 16 | return subprocess; 17 | }); 18 | Promise.all(commands); 19 | }; 20 | -------------------------------------------------------------------------------- /scripts/utils/exec.js: -------------------------------------------------------------------------------- 1 | const { spawn } = require('child_process'); 2 | 3 | module.exports = function exec(command, args, opts) { 4 | return new Promise((resolve, reject) => { 5 | const child = spawn(command, args, { 6 | shell: true, 7 | stdio: 'inherit', 8 | env: process.env, 9 | ...opts, 10 | }); 11 | child.once('error', (err) => { 12 | console.log(err); 13 | reject(err); 14 | }); 15 | child.once('close', (code) => { 16 | if (code === 1) { 17 | process.exit(1); 18 | } else { 19 | resolve(); 20 | } 21 | }); 22 | }); 23 | }; 24 | -------------------------------------------------------------------------------- /scripts/utils/getPackages.js: -------------------------------------------------------------------------------- 1 | const { readdirSync } = require('fs'); 2 | const { join } = require('path'); 3 | 4 | module.exports = function getPackages() { 5 | return readdirSync(join(__dirname, '../../packages')).filter( 6 | (pkg) => pkg.charAt(0) !== '.', 7 | ); 8 | }; 9 | -------------------------------------------------------------------------------- /scripts/utils/isNextVersion.js: -------------------------------------------------------------------------------- 1 | module.exports = function (version) { 2 | return ( 3 | version.includes('-rc.') || 4 | version.includes('-beta.') || 5 | version.includes('-alpha.') 6 | ); 7 | }; 8 | -------------------------------------------------------------------------------- /scripts/verifyCommit.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-extraneous-dependencies */ 2 | // Invoked on the commit-msg git hook by yorkie. 3 | 4 | const { chalk } = require('@umijs/utils'); 5 | 6 | const msgPath = process.env.GIT_PARAMS; 7 | const msg = require('fs').readFileSync(msgPath, 'utf-8').trim(); 8 | 9 | const commitRE = 10 | /^(((\ud83c[\udf00-\udfff])|(\ud83d[\udc00-\ude4f\ude80-\udeff])|[\u2600-\u2B55]) )?(revert: )?(feat|fix|docs|UI|refactor|⚡perf|workflow|build|CI|typos|chore|tests|types|wip|release|dep)(\(.+\))?: .{1,50}/; 11 | 12 | if (!commitRE.test(msg)) { 13 | console.log(); 14 | console.error( 15 | ` ${chalk.bgRed.white(' ERROR ')} ${chalk.red( 16 | `invalid commit message format.`, 17 | )}\n\n${chalk.red( 18 | ` Proper commit message format is required for automated changelog generation. Examples:\n\n`, 19 | )} 20 | ${chalk.green(`💥 feat(compiler): add 'comments' option`)}\n 21 | ${chalk.green(`🐛 fix(compiler): fix some bug`)}\n 22 | ${chalk.green(`📝 docs(compiler): add some docs`)}\n 23 | ${chalk.green(`💄 UI(compiler): better styles`)}\n 24 | ${chalk.green(`🎨 chore(compiler): do something`)}\n 25 | ${chalk.red(`See .github/commit-convention.md for more details.\n`)}`, 26 | ); 27 | process.exit(1); 28 | } 29 | -------------------------------------------------------------------------------- /tests/card/demo.test.ts: -------------------------------------------------------------------------------- 1 | import demoTest from '../demo'; 2 | 3 | demoTest('card'); 4 | -------------------------------------------------------------------------------- /tests/descriptions/demo.test.ts: -------------------------------------------------------------------------------- 1 | import demoTest from '../demo'; 2 | 3 | demoTest('descriptions'); 4 | -------------------------------------------------------------------------------- /tests/doc.test.ts: -------------------------------------------------------------------------------- 1 | import demoTest from './demo'; 2 | 3 | demoTest('docs/components'); 4 | -------------------------------------------------------------------------------- /tests/field/demo.test.ts: -------------------------------------------------------------------------------- 1 | import demoTest from '../demo'; 2 | 3 | demoTest('field'); 4 | -------------------------------------------------------------------------------- /tests/field/status.test.tsx: -------------------------------------------------------------------------------- 1 | import Field from '@ant-design/pro-field'; 2 | import { cleanup, render } from '@testing-library/react'; 3 | 4 | afterEach(() => { 5 | cleanup(); 6 | }); 7 | 8 | describe('Field Status', () => { 9 | afterEach(() => { 10 | cleanup(); 11 | }); 12 | const statusList = [ 13 | 'Success', 14 | 'Error', 15 | 'Processing', 16 | 'Default', 17 | 'Warning', 18 | 'success', 19 | 'error', 20 | 'processing', 21 | 'default', 22 | 'warning', 23 | ]; 24 | statusList.forEach((status) => { 25 | it(`🥩 ${status} render`, async () => { 26 | const { container } = render( 27 | , 37 | ); 38 | expect(container).toMatchSnapshot(); 39 | }); 40 | }); 41 | 42 | it(`🥩 red color render`, async () => { 43 | const { container } = render( 44 | , 54 | ); 55 | expect(container).toMatchSnapshot(); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /tests/form/__snapshots__/upload.test.tsx.snap: -------------------------------------------------------------------------------- 1 | // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html 2 | 3 | exports[`ProFormUpload > 🏐 ProFormUploadButton support disable 1`] = `""`; 4 | -------------------------------------------------------------------------------- /tests/form/demo.test.ts: -------------------------------------------------------------------------------- 1 | import demoTest from '../demo'; 2 | 3 | demoTest('form'); 4 | -------------------------------------------------------------------------------- /tests/form/proFormSegmented.test.tsx: -------------------------------------------------------------------------------- 1 | import ProForm, { ProFormSegmented } from '@ant-design/pro-form'; 2 | import { cleanup, render } from '@testing-library/react'; 3 | 4 | afterEach(() => { 5 | cleanup(); 6 | }); 7 | 8 | describe('ProFormSegmented', () => { 9 | it('📦 ProFormSegmented supports fieldProps.options', async () => { 10 | const options = [ 11 | { label: 'a', value: 'a' }, 12 | { label: 'b', value: 'b' }, 13 | ]; 14 | 15 | const { container } = render( 16 | 17 | 22 | , 23 | ); 24 | 25 | expect(container.querySelectorAll('.ant-segmented-item').length).toBe( 26 | options.length, 27 | ); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /tests/form/ssr.test.tsx: -------------------------------------------------------------------------------- 1 | // @vitest-environment node 2 | 3 | import ProForm, { DrawerForm, ModalForm } from '@ant-design/pro-form'; 4 | import { renderToString } from 'react-dom/server'; 5 | 6 | test('ssr', () => { 7 | expect(renderToString()).toBeDefined(); 8 | expect(renderToString()).toBeDefined(); 9 | expect(renderToString()).toBeDefined(); 10 | }); 11 | -------------------------------------------------------------------------------- /tests/layout/demo.test.ts: -------------------------------------------------------------------------------- 1 | import demoTest from '../demo'; 2 | 3 | demoTest('layout'); 4 | -------------------------------------------------------------------------------- /tests/layout/footer.test.tsx: -------------------------------------------------------------------------------- 1 | import { DefaultFooter } from '@ant-design/pro-components'; 2 | import { cleanup, render } from '@testing-library/react'; 3 | 4 | afterEach(() => { 5 | cleanup(); 6 | }); 7 | 8 | describe('DefaultFooter test', () => { 9 | it('🦶 set title', () => { 10 | const wrapper = render(); 11 | expect( 12 | !!wrapper.baseElement.querySelector('.ant-pro-global-footer-links'), 13 | ).toBeFalsy(); 14 | }); 15 | 16 | it('🦶 copyright support false', () => { 17 | const wrapper = render(); 18 | expect(wrapper.asFragment()).toMatchSnapshot(); 19 | }); 20 | 21 | it('🦶 links support false', () => { 22 | const wrapper = render(); 23 | expect(wrapper.asFragment()).toMatchSnapshot(); 24 | }); 25 | 26 | it('🦶 if copyright and links falsy both, should not to render nothing', () => { 27 | const wrapper = render(); 28 | expect( 29 | !!wrapper.baseElement.querySelector('.ant-pro-global-footer'), 30 | ).toBeFalsy(); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /tests/list/demo.test.ts: -------------------------------------------------------------------------------- 1 | import demoTest from '../demo'; 2 | 3 | demoTest('list'); 4 | -------------------------------------------------------------------------------- /tests/no-duplicated.ts: -------------------------------------------------------------------------------- 1 | // make sure no duplicated export interface 2 | export * from '../packages/card/src'; 3 | export * from '../packages/descriptions/src'; 4 | export * from '../packages/form/src'; 5 | export * from '../packages/layout/src'; 6 | export * from '../packages/list/src'; 7 | export * from '../packages/skeleton/src'; 8 | export * from '../packages/table/src'; 9 | -------------------------------------------------------------------------------- /tests/skeleton/demo.test.ts: -------------------------------------------------------------------------------- 1 | import demoTest from '../demo'; 2 | 3 | demoTest('skeleton'); 4 | -------------------------------------------------------------------------------- /tests/table/demo.test.ts: -------------------------------------------------------------------------------- 1 | import demoTest from '../demo'; 2 | 3 | demoTest('table'); 4 | -------------------------------------------------------------------------------- /tests/tsconfig.duplicate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "noEmit": true 5 | }, 6 | "include": ["no-duplicated.ts"] 7 | } 8 | -------------------------------------------------------------------------------- /typings.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.module.less'; 2 | declare module 'classnames'; 3 | 4 | interface Window { 5 | DarkReader: any; 6 | } 7 | -------------------------------------------------------------------------------- /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "git": { 3 | "deploymentEnabled": { 4 | "main": false 5 | } 6 | } 7 | } 8 | --------------------------------------------------------------------------------