themelia-react-ui 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +190 -1
- package/README.md +92 -13
- package/dist/{accordion-BRWh3BM1.js → accordion-BRTcsp8J.js} +8 -8
- package/dist/accordion-BRTcsp8J.js.map +1 -0
- package/dist/{action-menu-Cx3SdfbN.js → action-menu-Drxw_vJk.js} +36 -36
- package/dist/action-menu-Drxw_vJk.js.map +1 -0
- package/dist/affordance-geometry.generated-CL84ZN9A.js +63 -0
- package/dist/affordance-geometry.generated-CL84ZN9A.js.map +1 -0
- package/dist/{ai-artifact-DkOArd3-.js → ai-artifact-DLVdK0Py.js} +151 -155
- package/dist/ai-artifact-DLVdK0Py.js.map +1 -0
- package/dist/{app-shell-BH_bGcE2.js → app-shell-C_fKpljx.js} +11 -10
- package/dist/app-shell-C_fKpljx.js.map +1 -0
- package/dist/{attachment-DsLgNHXt.js → attachment-DbjUWsP0.js} +12 -12
- package/dist/{attachment-DsLgNHXt.js.map → attachment-DbjUWsP0.js.map} +1 -1
- package/dist/auth-CAQcasMV.js +723 -0
- package/dist/auth-CAQcasMV.js.map +1 -0
- package/dist/{avatar-CsnWaYmt.js → avatar-Bu2HhitA.js} +76 -71
- package/dist/avatar-Bu2HhitA.js.map +1 -0
- package/dist/{badge-BZXZT9wd.js → badge-CzId1Wlm.js} +4 -4
- package/dist/{badge-BZXZT9wd.js.map → badge-CzId1Wlm.js.map} +1 -1
- package/dist/base/accordion.js +1 -1
- package/dist/base/action-menu.js +1 -1
- package/dist/base/attachment.js +1 -1
- package/dist/base/avatar.js +1 -1
- package/dist/base/badge.js +1 -1
- package/dist/base/buttons.js +3 -2
- package/dist/base/cards.js +3 -3
- package/dist/base/carousel.js +25 -27
- package/dist/base/carousel.js.map +1 -1
- package/dist/base/cascader.js +150 -148
- package/dist/base/cascader.js.map +1 -1
- package/dist/base/chart.js +1 -1
- package/dist/base/choice-inputs.js +3 -2
- package/dist/base/code-block.js +1 -1
- package/dist/base/combobox.js +1 -1
- package/dist/base/command.js +1 -1
- package/dist/base/copyable.js +1 -1
- package/dist/base/date-pickers.js +3 -3
- package/dist/base/display.js +7 -7
- package/dist/base/feedback.js +4 -3
- package/dist/base/forms-numeric.js +1 -1
- package/dist/base/forms.js +2 -2
- package/dist/base/inline-edit.js +233 -0
- package/dist/base/inline-edit.js.map +1 -0
- package/dist/base/item.js +1 -1
- package/dist/base/media-gallery.js +1 -1
- package/dist/base/navigation.js +6 -6
- package/dist/base/popover-menu.js +1 -1
- package/dist/base/popover.js +1 -1
- package/dist/base/qr-code.js +1 -1
- package/dist/base/repeaters.js +33 -33
- package/dist/base/repeaters.js.map +1 -1
- package/dist/base/sheet.js +1 -1
- package/dist/base/sidebar.js +1 -1
- package/dist/base/signature-pad.js +83 -81
- package/dist/base/signature-pad.js.map +1 -1
- package/dist/base/skeleton.js +1 -1
- package/dist/base/spinner.js +1 -1
- package/dist/base/structure.js +1 -1
- package/dist/base/table.js +1 -1
- package/dist/base/text-inputs.js +2 -2
- package/dist/base/toaster.js +6 -6
- package/dist/base/toaster.js.map +1 -1
- package/dist/base/tree.js +1 -1
- package/dist/base/upload-queue.js +1 -1
- package/dist/base/upload.js +3 -3
- package/dist/base/value-inputs.js +1 -1
- package/dist/blocks/admin.js +134 -134
- package/dist/blocks/admin.js.map +1 -1
- package/dist/blocks/ai.js +120 -117
- package/dist/blocks/ai.js.map +1 -1
- package/dist/blocks/analytics/usage-card.js +3 -0
- package/dist/blocks/analytics.js +530 -491
- package/dist/blocks/analytics.js.map +1 -1
- package/dist/blocks/collaboration.js +2 -2
- package/dist/blocks/commerce/receipt.js +1 -1
- package/dist/blocks/commerce.js +395 -383
- package/dist/blocks/commerce.js.map +1 -1
- package/dist/blocks/data-display.js +1 -1
- package/dist/blocks/onboarding.js +6 -6
- package/dist/blocks/onboarding.js.map +1 -1
- package/dist/blocks/planning.js +311 -0
- package/dist/blocks/planning.js.map +1 -0
- package/dist/blocks/timelines.js +1 -1
- package/dist/{breadcrumbs-DdQ_I5ra.js → breadcrumbs-BuYz5SDU.js} +9 -8
- package/dist/breadcrumbs-BuYz5SDU.js.map +1 -0
- package/dist/button-BZDasD04.js +651 -0
- package/dist/button-BZDasD04.js.map +1 -0
- package/dist/{button-BS6l5JUw.js → button-BZyfTvwm.js} +3 -3
- package/dist/button-BZyfTvwm.js.map +1 -0
- package/dist/buttons-D_6KJvEE.js +99 -0
- package/dist/buttons-D_6KJvEE.js.map +1 -0
- package/dist/{cards-BMB0laLG.js → cards-qGSErLw_.js} +12 -12
- package/dist/{cards-BMB0laLG.js.map → cards-qGSErLw_.js.map} +1 -1
- package/dist/chart-Bsc5BICK.js +150 -0
- package/dist/chart-Bsc5BICK.js.map +1 -0
- package/dist/checkbox-BQNDjUCh.js +34 -0
- package/dist/checkbox-BQNDjUCh.js.map +1 -0
- package/dist/choice-inputs-Mk3iWbhr.js +725 -0
- package/dist/choice-inputs-Mk3iWbhr.js.map +1 -0
- package/dist/{code-block-DIlqzoiD.js → code-block-DzHKRybS.js} +23 -23
- package/dist/code-block-DzHKRybS.js.map +1 -0
- package/dist/{collapsible-DsnktFNv.js → collapsible-ClvC7Bj3.js} +3 -3
- package/dist/{collapsible-DsnktFNv.js.map → collapsible-ClvC7Bj3.js.map} +1 -1
- package/dist/{collection-content-C4fthJV_.js → collection-content-D6S8cv_n.js} +3 -3
- package/dist/{collection-content-C4fthJV_.js.map → collection-content-D6S8cv_n.js.map} +1 -1
- package/dist/{combobox-HDftpzxt.js → combobox-BFnbJJp3.js} +18 -18
- package/dist/combobox-BFnbJJp3.js.map +1 -0
- package/dist/{combobox-CHD750do.js → combobox-hozNwUcc.js} +313 -316
- package/dist/combobox-hozNwUcc.js.map +1 -0
- package/dist/{command-D0kWBZfd.js → command-BnmSchli.js} +9 -9
- package/dist/command-BnmSchli.js.map +1 -0
- package/dist/comments-u5L0OGip.js +1156 -0
- package/dist/comments-u5L0OGip.js.map +1 -0
- package/dist/components/base/buttons/button-group.recipes.d.ts +1 -1
- package/dist/components/base/buttons/button.recipes.d.ts +10 -19
- package/dist/components/base/buttons/use-pending-button-focus.d.ts +3 -0
- package/dist/components/base/cards/card.recipes.d.ts +13 -5
- package/dist/components/base/cards/partials/card-primitives.d.ts +9 -4
- package/dist/components/base/cards/smart-card.types.d.ts +3 -1
- package/dist/components/base/date-pickers/date-picker.recipes.d.ts +5 -18
- package/dist/components/base/date-pickers/datepicker.types.d.ts +3 -0
- package/dist/components/base/forms/form-field.d.ts +1 -0
- package/dist/components/base/forms/form-sizing.d.ts +3 -3
- package/dist/components/base/inline-edit/index.d.ts +2 -0
- package/dist/components/base/inline-edit/inline-edit.d.ts +81 -0
- package/dist/components/base/inline-edit/inline-edit.recipes.d.ts +6 -0
- package/dist/components/base/navigation/tabs.d.ts +3 -5
- package/dist/components/base/popover/popover.recipes.d.ts +3 -3
- package/dist/components/base/structure/structure.recipes.d.ts +6 -0
- package/dist/components/base/table/index.d.ts +1 -1
- package/dist/components/base/text-inputs/clear-native-field.d.ts +2 -0
- package/dist/components/base/text-inputs/input-trailing-action.d.ts +3 -0
- package/dist/components/blocks/analytics/index.d.ts +1 -0
- package/dist/components/blocks/analytics/types.d.ts +1 -1
- package/dist/components/blocks/analytics/usage-card/index.d.ts +3 -0
- package/dist/components/blocks/analytics/usage-card/types.d.ts +52 -0
- package/dist/components/blocks/analytics/usage-card/usage-card.d.ts +6 -0
- package/dist/components/blocks/analytics/usage-card/usage-card.data.d.ts +19 -0
- package/dist/components/blocks/analytics/usage-card/usage-card.strings.d.ts +22 -0
- package/dist/components/blocks/collaboration/message/message.recipes.d.ts +12 -0
- package/dist/components/blocks/data-display/empty-state/partials/illustrations/document-stack.d.ts +1 -4
- package/dist/components/blocks/data-display/empty-state/partials/illustrations/inbox-clean.d.ts +1 -4
- package/dist/components/blocks/data-display/empty-state/partials/illustrations/index.d.ts +3 -3
- package/dist/components/blocks/data-display/empty-state/partials/illustrations/stacked-cards.d.ts +1 -6
- package/dist/components/blocks/planning/index.d.ts +3 -0
- package/dist/components/blocks/planning/task-card.d.ts +3 -0
- package/dist/components/blocks/planning/task-card.strings.d.ts +15 -0
- package/dist/components/blocks/planning/task-card.types.d.ts +66 -0
- package/dist/components/features/combobox/components/error-message.d.ts +1 -1
- package/dist/components/features/comments/hooks/use-attachment-upload.d.ts +5 -0
- package/dist/components/features/filters/facets/search-facet.d.ts +0 -12
- package/dist/components/features/filters/facets/tags-facet.d.ts +1 -1
- package/dist/components/features/media-library/media-library.d.ts +1 -1
- package/dist/components/features/media-library/media-library.types.d.ts +9 -1
- package/dist/components/features/media-library/partials/media-library-partials.d.ts +1 -1
- package/dist/components/features/overlays/hooks/use-pending-overlay-focus.d.ts +2 -0
- package/dist/components/features/overlays/overlays.types.d.ts +5 -4
- package/dist/components/features/rich-text-editor/rich-text-editor.recipes.d.ts +2 -1
- package/dist/components/features/table/data-table.d.ts +1 -1
- package/dist/components/features/table/table.types.d.ts +1 -1
- package/dist/components/features/theme-tweaker/theme-provider-settings.d.ts +3 -1
- package/dist/components/layout/auth/auth.types.d.ts +1 -0
- package/dist/components/layout/page/page.d.ts +0 -1
- package/dist/components/layout/page/page.types.d.ts +9 -3
- package/dist/components/layout/sidebar/sidebar.context.d.ts +1 -1
- package/dist/components/layout/sidebar/sidebar.types.d.ts +4 -0
- package/dist/components/layout/workspace/workspace.types.d.ts +3 -0
- package/dist/components/typography/heading.d.ts +5 -2
- package/dist/components/typography/index.d.ts +1 -1
- package/dist/components/typography/text.styles.d.ts +10 -0
- package/dist/components/ui/popover.d.ts +1 -1
- package/dist/components/ui/sidebar.d.ts +1 -1
- package/dist/components/ui/table.d.ts +2 -1
- package/dist/container.recipes-D9t8MHR3.js +27 -0
- package/dist/container.recipes-D9t8MHR3.js.map +1 -0
- package/dist/{containers-CPNyNo1_.js → containers-DqB-bSYE.js} +34 -56
- package/dist/containers-DqB-bSYE.js.map +1 -0
- package/dist/control-group-recipes-DBXmfh2E.js +21 -0
- package/dist/control-group-recipes-DBXmfh2E.js.map +1 -0
- package/dist/{copyable-B7SBXJMr.js → copyable-BTSByfmq.js} +6 -6
- package/dist/{copyable-B7SBXJMr.js.map → copyable-BTSByfmq.js.map} +1 -1
- package/dist/{data-display-b3d1TfL4.js → data-display-Bihs9Ven.js} +542 -329
- package/dist/data-display-Bihs9Ven.js.map +1 -0
- package/dist/{date-BFNMnrS5.js → date-DOKhJPu7.js} +4 -4
- package/dist/{date-BFNMnrS5.js.map → date-DOKhJPu7.js.map} +1 -1
- package/dist/{date-picker-DI6kPNof.js → date-picker-DzP5HQq7.js} +492 -472
- package/dist/date-picker-DzP5HQq7.js.map +1 -0
- package/dist/date-pickers-BpgGz7S-.js +196 -0
- package/dist/date-pickers-BpgGz7S-.js.map +1 -0
- package/dist/{display-ByI5tkqy.js → display-CS6Hbk18.js} +8 -8
- package/dist/{display-ByI5tkqy.js.map → display-CS6Hbk18.js.map} +1 -1
- package/dist/{dropdown-menu-BlnyHr-9.js → dropdown-menu-D-boNgGO.js} +7 -7
- package/dist/{dropdown-menu-BlnyHr-9.js.map → dropdown-menu-D-boNgGO.js.map} +1 -1
- package/dist/features/activities.js +152 -141
- package/dist/features/activities.js.map +1 -1
- package/dist/features/ai-chat.js +182 -179
- package/dist/features/ai-chat.js.map +1 -1
- package/dist/features/async-preview.js +9 -9
- package/dist/features/async-preview.js.map +1 -1
- package/dist/features/combobox.js +1 -1
- package/dist/features/comments.js +1 -1
- package/dist/features/data-view.js +25 -23
- package/dist/features/data-view.js.map +1 -1
- package/dist/features/email-composer/engine.js +1 -1
- package/dist/features/email-composer.js +103 -104
- package/dist/features/email-composer.js.map +1 -1
- package/dist/features/event-calendar.js +375 -373
- package/dist/features/event-calendar.js.map +1 -1
- package/dist/features/filters.js +1 -1
- package/dist/features/global-search.js +222 -224
- package/dist/features/global-search.js.map +1 -1
- package/dist/features/kanban.js +29 -29
- package/dist/features/kanban.js.map +1 -1
- package/dist/features/map.js +59 -58
- package/dist/features/map.js.map +1 -1
- package/dist/features/media-library.js +856 -855
- package/dist/features/media-library.js.map +1 -1
- package/dist/features/mentions.js +1 -1
- package/dist/features/overlays.js +1 -1
- package/dist/features/products.js +1210 -1209
- package/dist/features/products.js.map +1 -1
- package/dist/features/questionnaire.js +133 -132
- package/dist/features/questionnaire.js.map +1 -1
- package/dist/features/resource-assignment.js +29 -31
- package/dist/features/resource-assignment.js.map +1 -1
- package/dist/features/resource.js +13 -13
- package/dist/features/resource.js.map +1 -1
- package/dist/features/rich-text-editor.js +2 -2
- package/dist/features/schema-form.js +82 -82
- package/dist/features/schema-form.js.map +1 -1
- package/dist/features/suggestions.js +3 -3
- package/dist/features/sync.js +4 -4
- package/dist/features/sync.js.map +1 -1
- package/dist/features/table.js +1 -1
- package/dist/features/theme-tweaker.js +456 -450
- package/dist/features/theme-tweaker.js.map +1 -1
- package/dist/feedback-CJkUAapr.js +233 -0
- package/dist/feedback-CJkUAapr.js.map +1 -0
- package/dist/field-affordance-recipes-uKY4MsZ_.js +25 -0
- package/dist/field-affordance-recipes-uKY4MsZ_.js.map +1 -0
- package/dist/{field-state-recipes-CBTRt9Bt.js → field-state-recipes-DQQpiLWC.js} +3 -3
- package/dist/field-state-recipes-DQQpiLWC.js.map +1 -0
- package/dist/{filters-qtrcv1hf.js → filters-D6FF8L6s.js} +715 -720
- package/dist/filters-D6FF8L6s.js.map +1 -0
- package/dist/{form-field-C6W-y2hR.js → form-field-CZwrkP7m.js} +17 -9
- package/dist/form-field-CZwrkP7m.js.map +1 -0
- package/dist/{form-sizing-39NohSqn.js → form-sizing-QP8aIRaW.js} +10 -6
- package/dist/form-sizing-QP8aIRaW.js.map +1 -0
- package/dist/{forms-BF-HSbff.js → forms-B5NCbkSC.js} +35 -35
- package/dist/{forms-BF-HSbff.js.map → forms-B5NCbkSC.js.map} +1 -1
- package/dist/forms-numeric-Crrm80Lm.js +867 -0
- package/dist/forms-numeric-Crrm80Lm.js.map +1 -0
- package/dist/{header-B8ex54cY.js → header-kxruN3RM.js} +53 -49
- package/dist/header-kxruN3RM.js.map +1 -0
- package/dist/{hooks-D6UBVzf2.js → hooks-BrlnCwQd.js} +2 -2
- package/dist/{hooks-D6UBVzf2.js.map → hooks-BrlnCwQd.js.map} +1 -1
- package/dist/{http-CLTVJc5I.js → http-CdEIHyQf.js} +2 -2
- package/dist/http-CdEIHyQf.js.map +1 -0
- package/dist/{icon-badge-Dv0RYQwj.js → icon-badge-Btc6pQrp.js} +4 -4
- package/dist/{icon-badge-Dv0RYQwj.js.map → icon-badge-Btc6pQrp.js.map} +1 -1
- package/dist/index.js +2 -2
- package/dist/input-SX9V0AL3.js +255 -0
- package/dist/input-SX9V0AL3.js.map +1 -0
- package/dist/input-vxcaNCYC.js +20 -0
- package/dist/input-vxcaNCYC.js.map +1 -0
- package/dist/{item-pJ0GsOiJ.js → item-DE4YnuJx.js} +18 -17
- package/dist/item-DE4YnuJx.js.map +1 -0
- package/dist/layout/app-shell.js +1 -1
- package/dist/layout/auth.js +1 -1
- package/dist/layout/containers.js +1 -1
- package/dist/layout/header.js +1 -1
- package/dist/layout/hooks.js +1 -1
- package/dist/layout/navigation.js +1 -1
- package/dist/layout/page.js +1 -1
- package/dist/layout/settings.js +1 -1
- package/dist/layout/sidebar.js +2 -2
- package/dist/layout/workspace.js +1 -1
- package/dist/layout.js +10 -10
- package/dist/lib/affordance-geometry.generated.d.ts +44 -4
- package/dist/lib/control-group-recipes.d.ts +22 -0
- package/dist/lib/field-affordance-recipes.d.ts +35 -2
- package/dist/lib/field-state-recipes.d.ts +2 -2
- package/dist/lib/navigation-row-recipes.d.ts +3 -2
- package/dist/lib/overlay-anatomy-recipes.d.ts +1 -1
- package/dist/lib/surface-recipes.d.ts +5 -2
- package/dist/lib/token-merge.generated.d.ts +144 -2
- package/dist/lib/ui-provider/types.d.ts +4 -2
- package/dist/lib/use-prefers-reduced-motion.d.ts +2 -0
- package/dist/lib/utils.js +1 -1
- package/dist/{media-gallery-Ca4YmvBi.js → media-gallery-DLp3HAz0.js} +75 -74
- package/dist/media-gallery-DLp3HAz0.js.map +1 -0
- package/dist/{mentions-CRio8mTm.js → mentions-Cl0Kt_Pd.js} +52 -50
- package/dist/{mentions-CRio8mTm.js.map → mentions-Cl0Kt_Pd.js.map} +1 -1
- package/dist/message-SZUNB1eX.js +127 -0
- package/dist/message-SZUNB1eX.js.map +1 -0
- package/dist/{navigation-BTrEb5u4.js → navigation-DnQSNMT0.js} +64 -55
- package/dist/navigation-DnQSNMT0.js.map +1 -0
- package/dist/{navigation-DqEITuD2.js → navigation-DyytsLRB.js} +37 -37
- package/dist/navigation-DyytsLRB.js.map +1 -0
- package/dist/{navigation-row-recipes-BFpvGPGE.js → navigation-row-recipes-DQEXQcqY.js} +3 -3
- package/dist/navigation-row-recipes-DQEXQcqY.js.map +1 -0
- package/dist/{number-BNT_BIzJ.js → number-DasMFWEG.js} +4 -4
- package/dist/{number-BNT_BIzJ.js.map → number-DasMFWEG.js.map} +1 -1
- package/dist/overlays-DUbs1KEi.js +1011 -0
- package/dist/overlays-DUbs1KEi.js.map +1 -0
- package/dist/{page-BMBGjJY8.js → page-hGmT4nWK.js} +75 -64
- package/dist/page-hGmT4nWK.js.map +1 -0
- package/dist/{page-header-BH41wCyY.js → page-header-D8nERkn5.js} +9 -9
- package/dist/page-header-D8nERkn5.js.map +1 -0
- package/dist/{pagination-C29vvt3I.js → pagination-NLGqRirf.js} +20 -20
- package/dist/pagination-NLGqRirf.js.map +1 -0
- package/dist/{popover-TInGXsjg.js → popover-CghIYdQf.js} +23 -22
- package/dist/popover-CghIYdQf.js.map +1 -0
- package/dist/{popover-menu-BzqXqE72.js → popover-menu-B4PoWhRl.js} +6 -6
- package/dist/{popover-menu-BzqXqE72.js.map → popover-menu-B4PoWhRl.js.map} +1 -1
- package/dist/{popover.recipes-zgBhMlUu.js → popover.recipes-QlD4JenO.js} +5 -5
- package/dist/popover.recipes-QlD4JenO.js.map +1 -0
- package/dist/{primitives-DKPOGVpj.js → primitives-C7ff0QaI.js} +120 -113
- package/dist/primitives-C7ff0QaI.js.map +1 -0
- package/dist/primitives.js +3 -3
- package/dist/progress-BroqrAyV.js +169 -0
- package/dist/progress-BroqrAyV.js.map +1 -0
- package/dist/{receipt-DYWTQGEc.js → receipt-BuJynLgf.js} +8 -8
- package/dist/{receipt-DYWTQGEc.js.map → receipt-BuJynLgf.js.map} +1 -1
- package/dist/{rich-text-B7sBAdDG.js → rich-text-DlxDOtf4.js} +4 -4
- package/dist/{rich-text-B7sBAdDG.js.map → rich-text-DlxDOtf4.js.map} +1 -1
- package/dist/rich-text-editor-BKyG7rWz.js +574 -0
- package/dist/rich-text-editor-BKyG7rWz.js.map +1 -0
- package/dist/{rich-text-editor.recipes-DxvOE0Lp.js → rich-text-editor.recipes-B72Nfuze.js} +35 -26
- package/dist/rich-text-editor.recipes-B72Nfuze.js.map +1 -0
- package/dist/{scroll-area-BheMQ270.js → scroll-area-D-pIhEKl.js} +3 -3
- package/dist/scroll-area-D-pIhEKl.js.map +1 -0
- package/dist/{separator-Gk_WXH-l.js → separator-BNIgG3au.js} +3 -3
- package/dist/{separator-Gk_WXH-l.js.map → separator-BNIgG3au.js.map} +1 -1
- package/dist/{separator-DO0EbCEm.js → separator-BhtFyo4x.js} +2 -2
- package/dist/{separator-DO0EbCEm.js.map → separator-BhtFyo4x.js.map} +1 -1
- package/dist/services/actions.js +1 -1
- package/dist/{settings-D9f_wdIC.js → settings-DOTOzeZ2.js} +10 -9
- package/dist/{settings-D9f_wdIC.js.map → settings-DOTOzeZ2.js.map} +1 -1
- package/dist/{sheet-vOUloJ4O.js → sheet-BFhrNehm.js} +11 -11
- package/dist/sheet-BFhrNehm.js.map +1 -0
- package/dist/{sidebar-CNBKFDRW.js → sidebar-CyR4XKwR.js} +219 -200
- package/dist/sidebar-CyR4XKwR.js.map +1 -0
- package/dist/{sidebar-C3UKkbC5.js → sidebar-SvGJ0Zwi.js} +63 -58
- package/dist/sidebar-SvGJ0Zwi.js.map +1 -0
- package/dist/{skeleton-BvRhK8y-.js → skeleton-3F0uhYn3.js} +4 -4
- package/dist/{skeleton-BvRhK8y-.js.map → skeleton-3F0uhYn3.js.map} +1 -1
- package/dist/{smart-card-B5FcKODh.js → smart-card-DjGVV2xr.js} +206 -199
- package/dist/smart-card-DjGVV2xr.js.map +1 -0
- package/dist/{spinner-JtlFJ7Nc.js → spinner-Cpf7oRkF.js} +5 -5
- package/dist/{spinner-JtlFJ7Nc.js.map → spinner-Cpf7oRkF.js.map} +1 -1
- package/dist/{structure-BvW4vG4H.js → structure-CRdqVawd.js} +14 -14
- package/dist/{structure-BvW4vG4H.js.map → structure-CRdqVawd.js.map} +1 -1
- package/dist/{structure.recipes-DjqnBpwz.js → structure.recipes-Bqhf9oIh.js} +2 -2
- package/dist/structure.recipes-Bqhf9oIh.js.map +1 -0
- package/dist/style.css +1 -1
- package/dist/{surface-recipes-CQfRr-VL.js → surface-recipes-Dd__PD-w.js} +4 -3
- package/dist/surface-recipes-Dd__PD-w.js.map +1 -0
- package/dist/{table-DnlAJ-xR.js → table-CLtJTxoR.js} +17 -16
- package/dist/table-CLtJTxoR.js.map +1 -0
- package/dist/table-CcRDZiLP.js +1444 -0
- package/dist/table-CcRDZiLP.js.map +1 -0
- package/dist/tabs-BNgu7g0u.js +188 -0
- package/dist/tabs-BNgu7g0u.js.map +1 -0
- package/dist/text-inputs-DsR56TR-.js +330 -0
- package/dist/text-inputs-DsR56TR-.js.map +1 -0
- package/dist/{text.styles-BwB7vAF2.js → text.styles-Q4sGAIgA.js} +18 -10
- package/dist/text.styles-Q4sGAIgA.js.map +1 -0
- package/dist/theme.css +77 -115
- package/dist/{timelines-CnZ2S_Gr.js → timelines-D1pkt3se.js} +84 -78
- package/dist/timelines-D1pkt3se.js.map +1 -0
- package/dist/{tree-COD9BGdU.js → tree-BtmYyMZV.js} +8 -8
- package/dist/{tree-COD9BGdU.js.map → tree-BtmYyMZV.js.map} +1 -1
- package/dist/typography/rich-text.js +1 -1
- package/dist/typography-BxQgiZyw.js +96 -0
- package/dist/typography-BxQgiZyw.js.map +1 -0
- package/dist/typography.js +1 -1
- package/dist/{ui-provider-CftIB6TY.js → ui-provider-DRPn3qNl.js} +3 -2
- package/dist/ui-provider-DRPn3qNl.js.map +1 -0
- package/dist/ui-provider.js +1 -1
- package/dist/{upload-DIzw1dx1.js → upload-CDbYw1WN.js} +326 -323
- package/dist/upload-CDbYw1WN.js.map +1 -0
- package/dist/{upload-queue-xRJ3qDmd.js → upload-queue-CNd_hH_a.js} +25 -25
- package/dist/upload-queue-CNd_hH_a.js.map +1 -0
- package/dist/usage-card-VyJLUwRr.js +457 -0
- package/dist/usage-card-VyJLUwRr.js.map +1 -0
- package/dist/utils-BvH9PSmq.js +4275 -0
- package/dist/utils-BvH9PSmq.js.map +1 -0
- package/dist/value-inputs-D0KCrfVC.js +840 -0
- package/dist/value-inputs-D0KCrfVC.js.map +1 -0
- package/dist/{workspace-Cbqz4FzN.js → workspace-CcR8r-Nt.js} +115 -122
- package/dist/workspace-CcR8r-Nt.js.map +1 -0
- package/docs/consumer-skill/SKILL.md +112 -18
- package/docs/consumer-skill/examples/analytics.tsx +34 -0
- package/docs/consumer-skill/examples/app-layout.tsx +42 -12
- package/docs/consumer-skill/examples/detail.tsx +24 -9
- package/docs/consumer-skill/examples/manifest.json +27 -1
- package/docs/consumer-skill/examples/planning-usage-edit.tsx +29 -0
- package/docs/consumer-skill/examples/scoped-directory.tsx +77 -0
- package/docs/consumer-skill/examples/website.tsx +56 -0
- package/docs/consumer-skill/references/analytics.md +70 -0
- package/docs/consumer-skill/references/composition.md +219 -2
- package/docs/consumer-skill/references/design-contract.md +37 -10
- package/docs/consumer-skill/references/discovery.md +93 -5
- package/docs/consumer-skill/references/installation.md +20 -3
- package/docs/consumer-skill/references/integration.md +26 -0
- package/docs/consumer-skill/references/public-api.json +2416 -388
- package/docs/consumer-skill/references/review.md +126 -0
- package/docs/consumer-skill/references/theming.md +52 -7
- package/docs/consumer-skill/references/tokens.json +177 -9
- package/docs/consumer-skill/references/workflows.md +129 -1
- package/docs/consumer-skill/scripts/check-composition.mjs +31 -0
- package/docs/consumer-skill/scripts/composition-policy.mjs +317 -0
- package/docs/consumer-skill/scripts/discovery.mjs +65 -8
- package/docs/consumer-skill/scripts/surface-policy.mjs +66 -0
- package/package.json +30 -6
- package/dist/accordion-BRWh3BM1.js.map +0 -1
- package/dist/action-menu-Cx3SdfbN.js.map +0 -1
- package/dist/affordance-geometry.generated-DXl-Zb3Z.js +0 -23
- package/dist/affordance-geometry.generated-DXl-Zb3Z.js.map +0 -1
- package/dist/ai-artifact-DkOArd3-.js.map +0 -1
- package/dist/app-shell-BH_bGcE2.js.map +0 -1
- package/dist/auth-BDB1V_2q.js +0 -704
- package/dist/auth-BDB1V_2q.js.map +0 -1
- package/dist/avatar-CsnWaYmt.js.map +0 -1
- package/dist/breadcrumbs-DdQ_I5ra.js.map +0 -1
- package/dist/button-BS6l5JUw.js.map +0 -1
- package/dist/buttons-Co6GavvM.js +0 -674
- package/dist/buttons-Co6GavvM.js.map +0 -1
- package/dist/chart-DVfcwQu6.js +0 -149
- package/dist/chart-DVfcwQu6.js.map +0 -1
- package/dist/choice-inputs-CavA-SGV.js +0 -644
- package/dist/choice-inputs-CavA-SGV.js.map +0 -1
- package/dist/code-block-DIlqzoiD.js.map +0 -1
- package/dist/combobox-CHD750do.js.map +0 -1
- package/dist/combobox-HDftpzxt.js.map +0 -1
- package/dist/command-D0kWBZfd.js.map +0 -1
- package/dist/comments-CvYeglMS.js +0 -1132
- package/dist/comments-CvYeglMS.js.map +0 -1
- package/dist/containers-CPNyNo1_.js.map +0 -1
- package/dist/data-display-b3d1TfL4.js.map +0 -1
- package/dist/date-picker-DI6kPNof.js.map +0 -1
- package/dist/date-pickers-ByP6Cv2z.js +0 -224
- package/dist/date-pickers-ByP6Cv2z.js.map +0 -1
- package/dist/feedback-a9j9J-9A.js +0 -391
- package/dist/feedback-a9j9J-9A.js.map +0 -1
- package/dist/field-affordance-recipes-CHdUtn2Z.js +0 -17
- package/dist/field-affordance-recipes-CHdUtn2Z.js.map +0 -1
- package/dist/field-state-recipes-CBTRt9Bt.js.map +0 -1
- package/dist/filters-qtrcv1hf.js.map +0 -1
- package/dist/form-field-C6W-y2hR.js.map +0 -1
- package/dist/form-sizing-39NohSqn.js.map +0 -1
- package/dist/forms-numeric-Y15Bg5Nr.js +0 -867
- package/dist/forms-numeric-Y15Bg5Nr.js.map +0 -1
- package/dist/header-B8ex54cY.js.map +0 -1
- package/dist/http-CLTVJc5I.js.map +0 -1
- package/dist/input-DMorJiTI.js +0 -202
- package/dist/input-DMorJiTI.js.map +0 -1
- package/dist/input-ci9fIgFH.js +0 -20
- package/dist/input-ci9fIgFH.js.map +0 -1
- package/dist/item-pJ0GsOiJ.js.map +0 -1
- package/dist/media-gallery-Ca4YmvBi.js.map +0 -1
- package/dist/message-B5-6LeYl.js +0 -108
- package/dist/message-B5-6LeYl.js.map +0 -1
- package/dist/navigation-BTrEb5u4.js.map +0 -1
- package/dist/navigation-DqEITuD2.js.map +0 -1
- package/dist/navigation-row-recipes-BFpvGPGE.js.map +0 -1
- package/dist/overlays-DBqV0J_V.js +0 -982
- package/dist/overlays-DBqV0J_V.js.map +0 -1
- package/dist/page-BMBGjJY8.js.map +0 -1
- package/dist/page-header-BH41wCyY.js.map +0 -1
- package/dist/pagination-C29vvt3I.js.map +0 -1
- package/dist/popover-TInGXsjg.js.map +0 -1
- package/dist/popover.recipes-zgBhMlUu.js.map +0 -1
- package/dist/primitives-DKPOGVpj.js.map +0 -1
- package/dist/rich-text-editor-BZSJchAF.js +0 -575
- package/dist/rich-text-editor-BZSJchAF.js.map +0 -1
- package/dist/rich-text-editor.recipes-DxvOE0Lp.js.map +0 -1
- package/dist/scroll-area-BheMQ270.js.map +0 -1
- package/dist/select-B2mb-qN2.js +0 -108
- package/dist/select-B2mb-qN2.js.map +0 -1
- package/dist/sheet-vOUloJ4O.js.map +0 -1
- package/dist/sidebar-C3UKkbC5.js.map +0 -1
- package/dist/sidebar-CNBKFDRW.js.map +0 -1
- package/dist/smart-card-B5FcKODh.js.map +0 -1
- package/dist/structure.recipes-DjqnBpwz.js.map +0 -1
- package/dist/surface-recipes-CQfRr-VL.js.map +0 -1
- package/dist/table-DnlAJ-xR.js.map +0 -1
- package/dist/table-ghtAQ-JJ.js +0 -1424
- package/dist/table-ghtAQ-JJ.js.map +0 -1
- package/dist/tabs-DY09eoZg.js +0 -187
- package/dist/tabs-DY09eoZg.js.map +0 -1
- package/dist/text-inputs-BhOcedTo.js +0 -331
- package/dist/text-inputs-BhOcedTo.js.map +0 -1
- package/dist/text.styles-BwB7vAF2.js.map +0 -1
- package/dist/timelines-CnZ2S_Gr.js.map +0 -1
- package/dist/typography-Cv8MT-82.js +0 -96
- package/dist/typography-Cv8MT-82.js.map +0 -1
- package/dist/ui-provider-CftIB6TY.js.map +0 -1
- package/dist/upload-DIzw1dx1.js.map +0 -1
- package/dist/upload-queue-xRJ3qDmd.js.map +0 -1
- package/dist/utils-C2EKeIw3.js +0 -72
- package/dist/utils-C2EKeIw3.js.map +0 -1
- package/dist/value-inputs-Co1fu-xv.js +0 -824
- package/dist/value-inputs-Co1fu-xv.js.map +0 -1
- package/dist/workspace-Cbqz4FzN.js.map +0 -1
|
@@ -1,32 +1,126 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: themelia-react-ui-consumer
|
|
3
|
-
description: Use when building, integrating, theming or migrating
|
|
3
|
+
description: Use when building, integrating, theming or migrating React apps and public websites with themelia-react-ui, including admin pages, forms, layouts and workflows; not for library internals.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Themelia React UI consumer
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Build from the public owner that fits the task. Use the exact family import,
|
|
9
|
+
its supported props and the application's data, callbacks and product conventions.
|
|
10
|
+
Before writing JSX, resolve the installed contract below. Select an owner in the
|
|
11
|
+
table or finder, read its declaration and the matching recipe, then adapt the
|
|
12
|
+
app's data/callbacks. Do not infer props or missing capabilities from names alone.
|
|
9
13
|
|
|
10
|
-
|
|
14
|
+
## Start with an owner
|
|
11
15
|
|
|
12
|
-
|
|
16
|
+
| Task | Exact import and starting symbols |
|
|
17
|
+
| --- | --- |
|
|
18
|
+
| KPI cards, revenue, trends, comparisons | `themelia-react-ui/blocks/analytics`: `Metric`, `MetricGrid`, `MetricBar`, `MetricComparison`, `MetricGradient`, `MetricMicroGrid`, `ChartCard`, `ActivityHeatmap` |
|
|
19
|
+
| Used/limit quotas and period/retry states | `themelia-react-ui/blocks/analytics/usage-card`: `UsageCard` |
|
|
20
|
+
| Record facts, one plain value, empty regions | `themelia-react-ui/blocks/data-display`: `MetadataList`, `InlineStat`, `EmptyState` |
|
|
21
|
+
| Query-driven directory or tabular comparison | `themelia-react-ui/features/data-view`: `DataView`; `themelia-react-ui/features/table`: `DataTable`, `ResourceCell` |
|
|
22
|
+
| Query criteria and facets | `themelia-react-ui/features/filters`: `FilterLayout`, `SelectFacet`, `SearchFacet`, `DateFacet` |
|
|
23
|
+
| Modal action, confirmation, drawer | `themelia-react-ui/features/overlays`: `ActionDialog`, `ConfirmDialog`, `ActionDrawer`, `useOverlayVisibility` |
|
|
24
|
+
| Fields, schema-driven forms, inline drafts | `themelia-react-ui/base/forms`: `FormField`, `FormSection`, `FormActionsBar`; `themelia-react-ui/features/schema-form`: `SchemaForm`; `themelia-react-ui/base/inline-edit`: `InlineEdit` |
|
|
25
|
+
| Application shell, sidebar, route identity | `themelia-react-ui/layout/app-shell`: `AppLayout`; `themelia-react-ui/layout/sidebar`: `AppSidebar`; `themelia-react-ui/layout/page`: `Page` |
|
|
26
|
+
| Public website and content sections | `themelia-react-ui/layout/containers`: `Container`, `Section`, `PageViewport` |
|
|
27
|
+
| Task summaries and conversation messages | `themelia-react-ui/blocks/planning`: `TaskCard`; `themelia-react-ui/blocks/collaboration`: `Message`, `MessageBubble` |
|
|
28
|
+
| Timelines, activity, commerce workflows | `themelia-react-ui/blocks/timelines`: `Timeline`, `StepsCard`; `themelia-react-ui/features/activities`: `ActivityLog`; discover the commerce subject below |
|
|
29
|
+
| Money, dates, counts and contact values | `themelia-react-ui/primitives`: `Money`, `Date`, `DateTime`, `Number`, `Percent`, `Email`, `Phone` |
|
|
30
|
+
| Display roles and sanitized rich HTML | `themelia-react-ui/typography`: `Heading`, `Text`, `DisplayLabel`, `Label`, `TextLink`; `themelia-react-ui/typography/rich-text`: `RichText` |
|
|
13
31
|
|
|
14
|
-
|
|
15
|
-
- [Installed setup](references/installation.md): package resolution, copied-skill freshness and manual installation.
|
|
16
|
-
- [Composition](references/composition.md): card anatomy, responsive structures, spacing and menu/display ownership.
|
|
17
|
-
- [Design contract](references/design-contract.md): application freedom, library-owned geometry, independent variants and enforcement limits.
|
|
18
|
-
- [Integration](references/integration.md): installation, CSS, state, routing, overlays and verification.
|
|
19
|
-
- [Theme extension](references/theming.md): compact tokens, scoped portals, radius and drift prevention.
|
|
20
|
-
- [Generated tokens](references/tokens.json): current structural roots/defaults, advanced settings and utility vocabulary.
|
|
21
|
-
- [Workflows](references/workflows.md): collection/navigation, detail, validated edit and destructive confirmation; callback ownership, optional peers and verification.
|
|
22
|
-
- [Typed example](examples/composition.tsx): public-import composition verified against the packed package.
|
|
32
|
+
For example, a KPI owns formatting, hierarchy and trend presentation:
|
|
23
33
|
|
|
24
|
-
|
|
34
|
+
```tsx
|
|
35
|
+
import { Metric, MetricGrid, type MetricData } from 'themelia-react-ui/blocks/analytics';
|
|
36
|
+
import { InlineStat, MetadataList } from 'themelia-react-ui/blocks/data-display';
|
|
25
37
|
|
|
26
|
-
|
|
38
|
+
const revenue: MetricData = {
|
|
39
|
+
id: 'revenue', label: 'Revenue', value: 42500,
|
|
40
|
+
valueType: 'currency', currency: 'USD',
|
|
41
|
+
change: { value: '+12%', direction: 'up' }, trend: 'positive',
|
|
42
|
+
};
|
|
43
|
+
export const Revenue = () => <Metric variant="card" data={revenue} />;
|
|
44
|
+
export const Dashboard = () => <MetricGrid metrics={[revenue]} columns={3} />;
|
|
45
|
+
export const InvoiceCount = () => <InlineStat label="Invoices" value={18} />;
|
|
46
|
+
export const AccountFacts = () => <MetadataList items={[
|
|
47
|
+
{ id: 'email', label: 'Email', value: 'morgan@example.com' },
|
|
48
|
+
]} />;
|
|
49
|
+
```
|
|
27
50
|
|
|
28
|
-
|
|
51
|
+
`Metric variant="card"`, default `MetricGrid`, `UsageCard` and `TaskCard` already
|
|
52
|
+
own their surfaces. MetadataList, InlineStat and ChartCard delegate framing;
|
|
53
|
+
Receipt owns its flat paper and insets. Choose a custom subject when its content
|
|
54
|
+
or lifecycle calls for it; reuse the appropriate lower owners within it.
|
|
55
|
+
The analytics barrel requires optional `recharts`, including without a sparkline;
|
|
56
|
+
the focused UsageCard import has no chart peer. See [analytics](references/analytics.md).
|
|
29
57
|
|
|
30
|
-
|
|
58
|
+
## Resolve the installed contract
|
|
31
59
|
|
|
32
|
-
|
|
60
|
+
Follow [installed setup](references/installation.md) to resolve the app's package
|
|
61
|
+
and check copied guidance after upgrades. Import `themelia-react-ui/style.css`
|
|
62
|
+
once; shipped components need no source scanning. Apps authoring semantic
|
|
63
|
+
utilities process `theme.css` in their Tailwind v4 build.
|
|
64
|
+
|
|
65
|
+
For another task or an unfamiliar prop, run the bundled [finder](references/discovery.md):
|
|
66
|
+
|
|
67
|
+
```sh
|
|
68
|
+
node node_modules/themelia-react-ui/docs/consumer-skill/scripts/find-components.mjs record directory --limit 5
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Task nouns retain richer alternatives; case-exact symbols such as `DataTable`
|
|
72
|
+
and exact imports select their precise contract. Follow `relevantSymbols` and
|
|
73
|
+
`nextReads` to the matching declaration, reference and recipe. Check the reported
|
|
74
|
+
optional peers before assigning props. The [public index](references/public-api.json)
|
|
75
|
+
contains all families; catalogue routes and private source paths are not imports.
|
|
76
|
+
RichText accepts sanitized HTML; convert Markdown in the app before passing `html`.
|
|
77
|
+
|
|
78
|
+
## Compose and adapt the screen
|
|
79
|
+
|
|
80
|
+
Use Page for route identity/commands and Container/Section for content-led sites.
|
|
81
|
+
Card frames one independent subject. Put status/count/version badges in
|
|
82
|
+
`titleSuffix`, actions in `headerAction`/`actions`, and pre-title context in
|
|
83
|
+
`headerStart`. Use `surface="flat" padding="none"` within an existing boundary.
|
|
84
|
+
Use the table/query/selection/row-action seams when they fit the workflow.
|
|
85
|
+
Keep fixed parent context while criteria change; make command scope clear.
|
|
86
|
+
|
|
87
|
+
Give each inset and gap one owner: page/container gutters, surface padding,
|
|
88
|
+
section rhythm and Stack/Grid sibling gaps. Use Heading/Text and formatted
|
|
89
|
+
primitives for display copy; choose Heading `tag` for semantics and `size` for
|
|
90
|
+
visual emphasis. Keep typography margin-free and primary rows at the shared size.
|
|
91
|
+
Choose `textGap`, density, control `size` and surface padding independently.
|
|
92
|
+
Shells own global corners; controls/rows own bounded inner corners. Change
|
|
93
|
+
`--radius` at the theme boundary; keep per-component radius classes out of callers.
|
|
94
|
+
Omit control size to inherit provider defaults. Public props and regions own
|
|
95
|
+
internal anatomy; application placement, alignment and overflow remain flexible.
|
|
96
|
+
|
|
97
|
+
Treat appearance feedback as an acceptance criterion. Inspect the reported
|
|
98
|
+
state and improve its owning composition or recipe. A passing static check
|
|
99
|
+
cannot establish that hierarchy, contrast, corners or spacing look right.
|
|
100
|
+
Use CSS semantic surface/foreground pairs and existing structural roots for
|
|
101
|
+
appearance; UIProvider supplies defaults. Use ThemeScope for scoped portals and
|
|
102
|
+
native `dir` plus DirectionProvider for RTL. See [theming](references/theming.md).
|
|
103
|
+
|
|
104
|
+
Keep controlled values authoritative and per-mount callbacks in the component.
|
|
105
|
+
The app owns routes, permissions, translation, transport and persistence. Preserve
|
|
106
|
+
pending drafts and ignore superseded results; show loading, empty, error/retry,
|
|
107
|
+
disabled and validation states. Use overlay focus/dismissal/pending contracts.
|
|
108
|
+
For server-component apps, mount interactive families from a client wrapper.
|
|
109
|
+
|
|
110
|
+
## Read the matching recipe and verify
|
|
111
|
+
|
|
112
|
+
| Work | Focused guidance and complete example |
|
|
113
|
+
| --- | --- |
|
|
114
|
+
| Structure, Card, public websites, heading scale | [Composition](references/composition.md), [website](examples/website.tsx) |
|
|
115
|
+
| Shell/sidebar/header and parent adaptation | [Layout composition](references/composition.md#application-layouts), [workspace](examples/app-layout.tsx) |
|
|
116
|
+
| Directory, detail, editing and confirmation | [Workflows](references/workflows.md), [directory](examples/scoped-directory.tsx), [detail](examples/detail.tsx), [edit](examples/edit.tsx), [confirmation](examples/destructive-confirm.tsx) |
|
|
117
|
+
| KPI, facts, quota/task summaries | [Analytics](references/analytics.md), [analytics recipe](examples/analytics.tsx), [task/usage/inline edit](examples/planning-usage-edit.tsx) |
|
|
118
|
+
| Email, receipts, files, messages and integrations | [Domain composition](references/composition.md#receipts), [recipe exports/peers](examples/manifest.json), [integration](references/integration.md) |
|
|
119
|
+
| Shared anatomy and source review | [Design contract](references/design-contract.md), [optional read-only checker](references/review.md) |
|
|
120
|
+
|
|
121
|
+
Run the app's type/lint/behavior checks. Inspect long content and missing values
|
|
122
|
+
at narrow/desktop parent widths in light/dark themes. Open menus/overlays and
|
|
123
|
+
execute keyboard selection, dismissal/focus return, callbacks, validation and
|
|
124
|
+
failure/retry. Keep source findings, inspected images and executed interactions
|
|
125
|
+
separate; the optional checker reports errors, review warnings and unresolved
|
|
126
|
+
expressions. Install/copy the complete skill manually after package upgrades.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ErrorState, LoadingState } from 'themelia-react-ui/base/feedback';
|
|
2
|
+
import { Metric, MetricGrid, type MetricData } from 'themelia-react-ui/blocks/analytics';
|
|
3
|
+
import { EmptyState, InlineStat } from 'themelia-react-ui/blocks/data-display';
|
|
4
|
+
|
|
5
|
+
export type RevenueOverviewState =
|
|
6
|
+
| { status: 'loading'; metrics: MetricData[] }
|
|
7
|
+
| { status: 'ready'; metrics: MetricData[] }
|
|
8
|
+
| { status: 'error'; message: string };
|
|
9
|
+
|
|
10
|
+
/** The app owns accepted values, loading labels, requests and retry effects. */
|
|
11
|
+
export function RevenueOverview({ state, onRetry }: {
|
|
12
|
+
state: RevenueOverviewState;
|
|
13
|
+
onRetry: () => void;
|
|
14
|
+
}) {
|
|
15
|
+
if (state.status === 'error') {
|
|
16
|
+
return <ErrorState title="Revenue unavailable" description={state.message}
|
|
17
|
+
onRetry={onRetry} retryLabel="Retry revenue" />;
|
|
18
|
+
}
|
|
19
|
+
if (!state.metrics.length) {
|
|
20
|
+
return state.status === 'loading'
|
|
21
|
+
? <LoadingState label="Loading revenue" />
|
|
22
|
+
: <EmptyState title="No revenue metrics" description="Choose a period with reported revenue." />;
|
|
23
|
+
}
|
|
24
|
+
return <MetricGrid metrics={state.metrics} columns={4} loading={state.status === 'loading'} />;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function RevenueMetric({ data, loading = false }: { data: MetricData; loading?: boolean }) {
|
|
28
|
+
return <Metric data={data} variant="card" loading={loading} />;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** A factual count has no comparison/trend semantics and owns no extra Card. */
|
|
32
|
+
export function PlainStatistic({ invoices }: { invoices: number | null }) {
|
|
33
|
+
return <InlineStat label="Invoices" value={invoices} />;
|
|
34
|
+
}
|
|
@@ -4,28 +4,58 @@ import { Card } from 'themelia-react-ui/base/cards';
|
|
|
4
4
|
import { SidebarTrigger } from 'themelia-react-ui/base/sidebar';
|
|
5
5
|
import { Stack } from 'themelia-react-ui/base/structure';
|
|
6
6
|
import { AppLayout, type AppLayoutVariant } from 'themelia-react-ui/layout/app-shell';
|
|
7
|
+
import { HeaderUserMenu, type HeaderUserMenuProps } from 'themelia-react-ui/layout/header';
|
|
7
8
|
import { Page } from 'themelia-react-ui/layout/page';
|
|
8
|
-
import { LayoutSidebarProvider } from 'themelia-react-ui/layout/sidebar';
|
|
9
|
+
import { AppSidebar, LayoutSidebarProvider, SidebarNavigationUser, type AppSidebarProps } from 'themelia-react-ui/layout/sidebar';
|
|
10
|
+
import type { UIConfig } from 'themelia-react-ui/ui-provider';
|
|
9
11
|
import { Text } from 'themelia-react-ui/typography';
|
|
10
12
|
|
|
11
|
-
/**
|
|
12
|
-
export
|
|
13
|
+
/** Use at the application's single UIProvider mount; CSS owns palette/geometry. */
|
|
14
|
+
export const workspaceUIDefaults: UIConfig = {
|
|
15
|
+
density: { defaultScale: 'md' },
|
|
16
|
+
card: { defaultSurface: 'card', defaultHeaderDivider: true, defaultFooterDivider: true },
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export interface WorkspaceLayoutProps {
|
|
13
20
|
variant?: AppLayoutVariant;
|
|
14
|
-
|
|
21
|
+
/** Optional replacement for the assembled AppSidebar. */
|
|
22
|
+
sidebar?: ReactNode;
|
|
23
|
+
navigationGroups?: AppSidebarProps['navigationGroups'];
|
|
24
|
+
currentUrl?: string;
|
|
25
|
+
renderLink?: AppSidebarProps['renderLink'];
|
|
26
|
+
workspaceLinks?: AppSidebarProps['workspaceLinks'];
|
|
27
|
+
/** Custom pinned control; replaces the built-in workspace-link trigger. */
|
|
28
|
+
workspaceSwitcher?: ReactNode;
|
|
29
|
+
user?: HeaderUserMenuProps['user'];
|
|
30
|
+
onLogout?: () => void;
|
|
15
31
|
onCreate: () => void;
|
|
16
|
-
|
|
17
|
-
|
|
32
|
+
narrow?: boolean;
|
|
33
|
+
children?: ReactNode;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** The app accepts route/identity data and wires navigation/persistence callbacks. */
|
|
37
|
+
export function WorkspaceLayout({ variant = 'inset', sidebar, navigationGroups = {},
|
|
38
|
+
currentUrl, renderLink, workspaceLinks, workspaceSwitcher, user, onLogout,
|
|
39
|
+
onCreate, narrow, children }: WorkspaceLayoutProps) {
|
|
40
|
+
const sidebarAccount = !sidebar && (variant === 'sidebar' || variant === 'inset');
|
|
41
|
+
const brand = <Text weight="semibold">Admin</Text>;
|
|
42
|
+
const account = user && !sidebarAccount ? <HeaderUserMenu user={user} onLogout={onLogout} /> : null;
|
|
43
|
+
const navigation = sidebar ?? <AppSidebar className="h-full" logo={brand} collapsedLogo={<Text>A</Text>}
|
|
44
|
+
currentUrl={currentUrl} renderLink={renderLink} navigationGroups={navigationGroups}
|
|
45
|
+
workspaceLinks={workspaceSwitcher ? undefined : workspaceLinks}
|
|
46
|
+
slots={{ headerEnd: workspaceSwitcher, footer: user && sidebarAccount ? <SidebarNavigationUser user={user} onLogout={onLogout} /> : undefined }} />;
|
|
47
|
+
const content = <Page narrow={narrow} gutter={variant === 'stacked' ? 'none' : undefined}
|
|
18
48
|
header={{ title: 'Workspace', description: 'Review activity and manage your records.',
|
|
19
|
-
actions: <Button onClick={onCreate}>Create record</Button> }}>
|
|
20
|
-
<Card title="Activity"><Text>Application content goes here.</Text></Card>
|
|
49
|
+
headingTag: 'h1', actions: <Button onClick={onCreate}>Create record</Button> }}>
|
|
50
|
+
{children ?? <Card title="Activity" footerText="Latest workspace activity"><Text>Application content goes here.</Text></Card>}
|
|
21
51
|
</Page>;
|
|
22
|
-
const brand = <Text weight="semibold">Admin</Text>;
|
|
23
52
|
const trigger = <SidebarTrigger />;
|
|
24
53
|
return <LayoutSidebarProvider adaptTo="container" className="min-h-0">
|
|
25
54
|
{variant === 'stacked' ? <AppLayout variant="stacked" className="h-svh min-h-0" logo={brand}
|
|
26
|
-
nav={<Stack direction="horizontal" gap="sm"><Button onClick={onCreate}>Create record</Button></Stack>}>{content}</AppLayout>
|
|
55
|
+
slots={{headerEnd: account}} nav={<Stack direction="horizontal" gap="sm"><Button onClick={onCreate}>Create record</Button></Stack>}>{content}</AppLayout>
|
|
27
56
|
: variant === 'sidebar' || variant === 'inset' ? <AppLayout variant={variant} className="h-svh min-h-0"
|
|
28
|
-
sidebar={
|
|
29
|
-
: <AppLayout variant={variant} className="h-svh min-h-0" logo={brand} sidebar={
|
|
57
|
+
sidebar={navigation} sidebarTrigger={trigger} slots={{ toolbarStart: brand, toolbarEnd: account }}>{content}</AppLayout>
|
|
58
|
+
: <AppLayout variant={variant} className="h-svh min-h-0" logo={brand} sidebar={navigation}
|
|
59
|
+
sidebarTrigger={trigger} slots={{headerEnd: account}}>{content}</AppLayout>}
|
|
30
60
|
</LayoutSidebarProvider>;
|
|
31
61
|
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { Building2 } from 'lucide-react';
|
|
1
2
|
import { Button } from 'themelia-react-ui/base/buttons';
|
|
2
3
|
import { Card } from 'themelia-react-ui/base/cards';
|
|
3
|
-
import {
|
|
4
|
+
import { MetadataList } from 'themelia-react-ui/blocks/data-display';
|
|
4
5
|
import { Date, Email, Money, Value } from 'themelia-react-ui/primitives';
|
|
5
|
-
import {
|
|
6
|
+
import { Page } from 'themelia-react-ui/layout/page';
|
|
6
7
|
|
|
7
8
|
export interface AccountDetailRecord {
|
|
8
9
|
id: string; name: string; email: string | null;
|
|
@@ -15,14 +16,28 @@ export interface AccountDetailProps {
|
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
export function AccountDetail({ account, onEdit, onBack }: AccountDetailProps) {
|
|
18
|
-
return <Card title={account.name}
|
|
19
|
+
return <Card title={account.name} headerPlacement="frame"
|
|
19
20
|
headerAction={<Button onClick={() => onEdit(account.id)}>Edit account</Button>}
|
|
20
21
|
footerSlot={<Button tone="secondary" buttonStyle="outline" onClick={onBack}>Back to accounts</Button>}>
|
|
21
|
-
<
|
|
22
|
-
<Stack gap="xs"><Text type="secondary">Account ID</Text><Value>{account.id}</Value></Stack>
|
|
23
|
-
<Stack gap="xs"><Text type="secondary">Email</Text><Email value={account.email} /></Stack>
|
|
24
|
-
<Stack gap="xs"><Text type="secondary">Created</Text><Date value={account.createdAt} /></Stack>
|
|
25
|
-
<Stack gap="xs"><Text type="secondary">Balance</Text><Money amount={account.balanceMinor} currency={account.currency} unit="minor" /></Stack>
|
|
26
|
-
</Grid>
|
|
22
|
+
<AccountFacts account={account}/>
|
|
27
23
|
</Card>;
|
|
28
24
|
}
|
|
25
|
+
|
|
26
|
+
/** A focused resource route: Page owns measure, gutters, identity and commands. */
|
|
27
|
+
export function AccountDetailPage({account,onEdit,onBack}:AccountDetailProps) {
|
|
28
|
+
return <Page narrow header={{title:account.name,description:'Account details',onBack,
|
|
29
|
+
backLabel:'Back to accounts',actions:<Button onClick={()=>onEdit(account.id)}>Edit account</Button>}}>
|
|
30
|
+
<Card title="Contact and billing" icon={<Building2/>} headerPlacement="frame">
|
|
31
|
+
<AccountFacts account={account}/>
|
|
32
|
+
</Card>
|
|
33
|
+
</Page>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function AccountFacts({account}:{account:AccountDetailRecord}) {
|
|
37
|
+
return <MetadataList columns={{ base: 1, md: 2 }} items={[
|
|
38
|
+
{ id: 'id', label: 'Account ID', value: <Value>{account.id}</Value> },
|
|
39
|
+
{ id: 'email', label: 'Email', value: <Email value={account.email} /> },
|
|
40
|
+
{ id: 'created', label: 'Created', value: <Date value={account.createdAt} /> },
|
|
41
|
+
{ id: 'balance', label: 'Balance', value: <Money amount={account.balanceMinor} currency={account.currency} unit="minor" /> },
|
|
42
|
+
]} />;
|
|
43
|
+
}
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"examples": [
|
|
4
|
+
{
|
|
5
|
+
"file": "website.tsx",
|
|
6
|
+
"exports": ["WebsiteLandingPage"],
|
|
7
|
+
"phase": "basic",
|
|
8
|
+
"optionalPeers": []
|
|
9
|
+
},
|
|
4
10
|
{
|
|
5
11
|
"file": "composition.tsx",
|
|
6
12
|
"exports": [
|
|
@@ -19,10 +25,16 @@
|
|
|
19
25
|
"@tanstack/react-table"
|
|
20
26
|
]
|
|
21
27
|
},
|
|
28
|
+
{
|
|
29
|
+
"file": "scoped-directory.tsx",
|
|
30
|
+
"exports": ["ScopedDirectory"],
|
|
31
|
+
"phase": "optional",
|
|
32
|
+
"optionalPeers": ["@tanstack/react-table", "react-day-picker"]
|
|
33
|
+
},
|
|
22
34
|
{
|
|
23
35
|
"file": "detail.tsx",
|
|
24
36
|
"exports": [
|
|
25
|
-
"AccountDetail"
|
|
37
|
+
"AccountDetail", "AccountDetailPage"
|
|
26
38
|
],
|
|
27
39
|
"phase": "basic",
|
|
28
40
|
"optionalPeers": []
|
|
@@ -89,6 +101,20 @@
|
|
|
89
101
|
],
|
|
90
102
|
"phase": "basic",
|
|
91
103
|
"optionalPeers": []
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"file": "planning-usage-edit.tsx",
|
|
107
|
+
"exports": [
|
|
108
|
+
"WorkspaceSummary"
|
|
109
|
+
],
|
|
110
|
+
"phase": "basic",
|
|
111
|
+
"optionalPeers": []
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"file": "analytics.tsx",
|
|
115
|
+
"exports": ["RevenueOverview", "RevenueMetric", "PlainStatistic"],
|
|
116
|
+
"phase": "optional",
|
|
117
|
+
"optionalPeers": ["recharts"]
|
|
92
118
|
}
|
|
93
119
|
]
|
|
94
120
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { InlineEdit } from 'themelia-react-ui/base/inline-edit';
|
|
3
|
+
import { Card } from 'themelia-react-ui/base/cards';
|
|
4
|
+
import { AdaptiveGrid, Stack } from 'themelia-react-ui/base/structure';
|
|
5
|
+
import { TaskCard, type TaskCardItem } from 'themelia-react-ui/blocks/planning';
|
|
6
|
+
import { UsageCard, type UsageCardData } from 'themelia-react-ui/blocks/analytics/usage-card';
|
|
7
|
+
|
|
8
|
+
/** The application supplies persistence, authoritative tasks and usage. */
|
|
9
|
+
export function WorkspaceSummary({
|
|
10
|
+
initialName, tasks, usage, saveName, completeTask,
|
|
11
|
+
}: {
|
|
12
|
+
initialName: string;
|
|
13
|
+
tasks: readonly TaskCardItem[];
|
|
14
|
+
usage: UsageCardData;
|
|
15
|
+
saveName: (name: string, signal: AbortSignal) => Promise<void>;
|
|
16
|
+
completeTask: (id: string, completed: boolean) => void;
|
|
17
|
+
}) {
|
|
18
|
+
const [name, setName] = useState(initialName);
|
|
19
|
+
return <Stack gap="xl">
|
|
20
|
+
<Card title="Workspace">
|
|
21
|
+
<InlineEdit label="Project name" value={name} onValueChange={setName} required
|
|
22
|
+
onSave={(draft, {signal}) => saveName(draft, signal)} />
|
|
23
|
+
</Card>
|
|
24
|
+
<AdaptiveGrid minColumnWidth="md" gap="xl">
|
|
25
|
+
<TaskCard title="Release checklist" items={tasks} defaultExpanded onItemCompletedChange={completeTask} />
|
|
26
|
+
<UsageCard title="Workspace usage" data={usage} />
|
|
27
|
+
</AdaptiveGrid>
|
|
28
|
+
</Stack>;
|
|
29
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { useMemo, type ReactNode } from 'react';
|
|
2
|
+
import { Button } from 'themelia-react-ui/base/buttons';
|
|
3
|
+
import { Stack } from 'themelia-react-ui/base/structure';
|
|
4
|
+
import { FilterLayout, FilterProvider, FilterType, type ActiveFilter, type FilterConfig } from 'themelia-react-ui/features/filters';
|
|
5
|
+
import { DataTable, ResourceCell, type DataTableProps } from 'themelia-react-ui/features/table';
|
|
6
|
+
import { Page } from 'themelia-react-ui/layout/page';
|
|
7
|
+
import { Email } from 'themelia-react-ui/primitives';
|
|
8
|
+
import { Text } from 'themelia-react-ui/typography';
|
|
9
|
+
|
|
10
|
+
export interface DirectoryContact { id: string; name: string; role: string; email: string | null; }
|
|
11
|
+
export type DirectoryState =
|
|
12
|
+
| { status: 'loading' }
|
|
13
|
+
| { status: 'error'; message: string }
|
|
14
|
+
| { status: 'ready'; records: DirectoryContact[] };
|
|
15
|
+
export interface ScopedDirectoryProps {
|
|
16
|
+
scope: { id: string; label: string };
|
|
17
|
+
state: DirectoryState;
|
|
18
|
+
filters: ActiveFilter[];
|
|
19
|
+
onQueryChange: (query: { scopeId: string; filters: ActiveFilter[] }) => void;
|
|
20
|
+
onRetry: () => void;
|
|
21
|
+
onBack: () => void;
|
|
22
|
+
onCreate?: () => void;
|
|
23
|
+
onOpen: (id: string) => void;
|
|
24
|
+
exportAction?: ReactNode;
|
|
25
|
+
/** App chooses from available parent width; compact identity retains contact reach. */
|
|
26
|
+
compact?: boolean;
|
|
27
|
+
// Authoritative server pagination; the app preserves scope/query in its URLs.
|
|
28
|
+
pagination?: DataTableProps<DirectoryContact, unknown>['pagination'];
|
|
29
|
+
onPageChange?: DataTableProps<DirectoryContact, unknown>['onPageChange'];
|
|
30
|
+
}
|
|
31
|
+
const criteria: FilterConfig[] = [{
|
|
32
|
+
key: 'q', label: 'Search contacts', placeholder: 'Name, email or role',
|
|
33
|
+
type: FilterType.SEARCH, icon: null, operator: 'contains', delay: 0,
|
|
34
|
+
displayConfig: { display: 'always' },
|
|
35
|
+
}];
|
|
36
|
+
const columns: DataTableProps<DirectoryContact, unknown>['columns'] = [
|
|
37
|
+
{ id: 'identity', header: 'Contact', cell: ({ row }) => <ResourceCell title={row.original.name}
|
|
38
|
+
subtitle={<Text size="xs" type="secondary">{row.original.role}</Text>} /> },
|
|
39
|
+
{ accessorKey: 'email', header: 'Email', cell: ({ row }) => <Email value={row.original.email} /> },
|
|
40
|
+
];
|
|
41
|
+
const compactColumns: DataTableProps<DirectoryContact, unknown>['columns'] = [
|
|
42
|
+
{ id: 'identity', header: 'Contact', cell: ({ row }) => <ResourceCell title={row.original.name}
|
|
43
|
+
subtitle={<Text size="xs" type="secondary">{row.original.role}</Text>}
|
|
44
|
+
metadata={<Email value={row.original.email} />} /> },
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
// Parent scope is navigation context, never a removable filter. The app loads
|
|
48
|
+
// matching records. Its detail view keeps other operational facts available.
|
|
49
|
+
export function ScopedDirectory(props: ScopedDirectoryProps) {
|
|
50
|
+
const rowActions = useMemo<DataTableProps<DirectoryContact, unknown>['rowActions']>(() => [
|
|
51
|
+
{ id: 'open', label: 'Open contact', onClick: contact => props.onOpen(contact.id) },
|
|
52
|
+
], [props.onOpen]);
|
|
53
|
+
return <Page header={{ title: 'Contacts', headingTag: 'h1',
|
|
54
|
+
description: 'People responsible for bookings, billing and operations.',
|
|
55
|
+
onBack: props.onBack, backLabel: 'All businesses',
|
|
56
|
+
slots: { beforeTitle: <Text type="secondary">Business: {props.scope.label}</Text> },
|
|
57
|
+
actions: props.onCreate ? <Button tone="primary" onClick={props.onCreate}>New contact</Button> : undefined,
|
|
58
|
+
}}>
|
|
59
|
+
<FilterProvider filters={criteria} activeFilters={props.filters}
|
|
60
|
+
navigating={props.state.status === 'loading'}
|
|
61
|
+
onFilterChange={filters => props.onQueryChange({ scopeId: props.scope.id,
|
|
62
|
+
// A cleared search can emit ['']; it is not an applied criterion here.
|
|
63
|
+
filters: filters.filter(filter => filter.key !== 'q' || filter.value.some(value => value.trim() !== '')),
|
|
64
|
+
})}>
|
|
65
|
+
<DataTable columns={props.compact ? compactColumns : columns} data={props.state.status === 'ready' ? props.state.records : []}
|
|
66
|
+
getRowId={contact => contact.id} enableSorting={false} enableColumnVisibility={false}
|
|
67
|
+
showFullscreenToggle={false} manualPagination pagination={props.state.status === 'ready' ? props.pagination : undefined} onPageChange={props.onPageChange}
|
|
68
|
+
topbarContent={<FilterLayout variant="compact" showClearFilters />} topbarEnd={props.exportAction}
|
|
69
|
+
emptyStateMessage={props.state.status === 'loading' ? 'Loading contacts…' :
|
|
70
|
+
props.state.status === 'error' ? 'Contacts could not be loaded.' :
|
|
71
|
+
props.filters.length ? 'No contacts match these criteria.' : 'No contacts in this business yet.'}
|
|
72
|
+
emptyStateAction={props.state.status === 'error' ? <Stack gap="dense"><Text role="alert" type="error">{props.state.message}</Text>
|
|
73
|
+
<Button tone="secondary" buttonStyle="outline" onClick={props.onRetry}>Retry contacts</Button></Stack> : undefined}
|
|
74
|
+
rowActions={rowActions} />
|
|
75
|
+
</FilterProvider>
|
|
76
|
+
</Page>;
|
|
77
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { useId } from 'react';
|
|
2
|
+
import { Button } from 'themelia-react-ui/base/buttons';
|
|
3
|
+
import { Card } from 'themelia-react-ui/base/cards';
|
|
4
|
+
import { Grid, Stack } from 'themelia-react-ui/base/structure';
|
|
5
|
+
import { Container, Section } from 'themelia-react-ui/layout/containers';
|
|
6
|
+
import { Money, type MoneyValue } from 'themelia-react-ui/primitives';
|
|
7
|
+
import { Heading, Text } from 'themelia-react-ui/typography';
|
|
8
|
+
|
|
9
|
+
export interface ServiceOffer {
|
|
10
|
+
id: string;
|
|
11
|
+
title: string;
|
|
12
|
+
description: string;
|
|
13
|
+
price: MoneyValue;
|
|
14
|
+
priceNote: string;
|
|
15
|
+
href: string;
|
|
16
|
+
actionLabel: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Copy, prices, billing terms, destinations and site navigation belong to the app. */
|
|
20
|
+
export function WebsiteLandingPage({ title, description, actionLabel, actionHref, servicesTitle, offers, locale }: {
|
|
21
|
+
title: string;
|
|
22
|
+
description: string;
|
|
23
|
+
actionLabel: string;
|
|
24
|
+
actionHref: string;
|
|
25
|
+
servicesTitle: string;
|
|
26
|
+
offers: readonly ServiceOffer[];
|
|
27
|
+
locale?: string;
|
|
28
|
+
}) {
|
|
29
|
+
const introId = useId();
|
|
30
|
+
const servicesId = useId();
|
|
31
|
+
return <Container render={<main />} maxWidth="xl" className="py-surface-lg">
|
|
32
|
+
<Stack gap="2xl">
|
|
33
|
+
<Section aria-labelledby={introId}>
|
|
34
|
+
<Stack gap="normal">
|
|
35
|
+
<Heading tag="h1" size="4xl" id={introId}>{title}</Heading>
|
|
36
|
+
<Text type="secondary">{description}</Text>
|
|
37
|
+
</Stack>
|
|
38
|
+
<Stack direction="horizontal" gap="md">
|
|
39
|
+
<Button href={actionHref} tone="primary">{actionLabel}</Button>
|
|
40
|
+
</Stack>
|
|
41
|
+
</Section>
|
|
42
|
+
<Section aria-labelledby={servicesId}>
|
|
43
|
+
<Heading tag="h2" size="2xl" id={servicesId}>{servicesTitle}</Heading>
|
|
44
|
+
<Grid columns={{ base: 1, md: 2, lg: 3 }} gap="xl">
|
|
45
|
+
{offers.map(offer => <Card key={offer.id} title={offer.title} description={offer.description}
|
|
46
|
+
footerSlot={<Button href={offer.href} tone="secondary" buttonStyle="outline">{offer.actionLabel}</Button>}>
|
|
47
|
+
<Stack gap="dense">
|
|
48
|
+
<Money {...offer.price} locale={locale} align="left" weight="semibold" />
|
|
49
|
+
<Text type="secondary" size="xs">{offer.priceNote}</Text>
|
|
50
|
+
</Stack>
|
|
51
|
+
</Card>)}
|
|
52
|
+
</Grid>
|
|
53
|
+
</Section>
|
|
54
|
+
</Stack>
|
|
55
|
+
</Container>;
|
|
56
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Metrics and statistics
|
|
2
|
+
|
|
3
|
+
Use this reference for dashboard KPIs, revenue overviews, statistic cards and
|
|
4
|
+
usage summaries. The finder returns exact owners, relevant symbols and recipe
|
|
5
|
+
reads; declarations establish the current props. These components present
|
|
6
|
+
application data and never fetch or define a business metric.
|
|
7
|
+
|
|
8
|
+
## Select the subject owner
|
|
9
|
+
|
|
10
|
+
| Subject | Public owner | Frame and lifecycle |
|
|
11
|
+
| --- | --- | --- |
|
|
12
|
+
| One KPI with value, trend or sparkline | `Metric` from `themelia-react-ui/blocks/analytics` | `variant="card"` owns its Card; default/compact/minimal support lower-level composition. Has loading/error presentation. |
|
|
13
|
+
| Peer dashboard KPIs or revenue figures | `MetricGrid` from `themelia-react-ui/blocks/analytics` | Defaults to card metrics; owns gaps and columns responding to its parent. `columns` is a maximum. Has loading, while error/retry/empty remain app-owned. |
|
|
14
|
+
| Metrics sharing one strip and period action | `MetricBar` from `themelia-react-ui/blocks/analytics` | One strip from `MetricData[]`; period callback requests the current period value. App owns choosing/fetching periods and request states. |
|
|
15
|
+
| Current versus previous metric | `MetricComparison` from `themelia-react-ui/blocks/analytics` | Uses current/previous `MetricData`; app defines the comparison baseline. |
|
|
16
|
+
| Used/limit quotas with shares, daily values and period selection | `UsageCard` from `themelia-react-ui/blocks/analytics/usage-card` | Owns a Card and ready/loading/error/empty presentation with retry/period callbacks. No optional chart peer. |
|
|
17
|
+
| One plain label/value fact | `InlineStat` from `themelia-react-ui/blocks/data-display` | Card-free; app chooses whether this subject needs a Card. |
|
|
18
|
+
| Several facts about one record | `MetadataList` from `themelia-react-ui/blocks/data-display` | Card-free; value primitives own formatting. |
|
|
19
|
+
| Caller-owned chart series | `ChartCard` from `themelia-react-ui/blocks/analytics` | Card-free chart composition; caller supplies chart content and an optional Card boundary. |
|
|
20
|
+
|
|
21
|
+
Start with these subject owners before constructing a Card with a number and
|
|
22
|
+
supporting text. Reuse their formatting, hierarchy and relevant states when
|
|
23
|
+
the contract fits. A custom Card remains appropriate for a distinct subject
|
|
24
|
+
or task with content/coordination these owners do not represent; keep their
|
|
25
|
+
supported lower owners where useful. Do not put another Card around an owner
|
|
26
|
+
that already renders its own surface.
|
|
27
|
+
|
|
28
|
+
## Dashboard and revenue data
|
|
29
|
+
|
|
30
|
+
[Analytics recipe](../examples/analytics.tsx) exports `RevenueOverview`,
|
|
31
|
+
`RevenueMetric` and `PlainStatistic`. The overview accepts discriminated request
|
|
32
|
+
state: loading renders MetricGrid skeletons, error replaces data with retry,
|
|
33
|
+
and a ready empty array renders EmptyState. The parent supplies labels/IDs for
|
|
34
|
+
loading metrics, accepts server data, executes retry and ignores stale results.
|
|
35
|
+
It adds no implicit Card around the grid. The other exports show a standalone
|
|
36
|
+
Metric and a plain factual InlineStat.
|
|
37
|
+
|
|
38
|
+
`MetricData` requires stable `id`, `label` and `value`. Numeric currency values
|
|
39
|
+
use `valueType="currency"` plus `currency`; pass major currency units, rather
|
|
40
|
+
than a Money primitive's `unit="minor"` contract. Percentage values follow the
|
|
41
|
+
shared formatter's ratio contract (0.12 renders 12%). `null` is unavailable;
|
|
42
|
+
zero is real data. A string is already display data. `change.value` is caller
|
|
43
|
+
copy, `change.direction` describes movement, and `trend` can override whether
|
|
44
|
+
movement is positive, negative or neutral. A decline in churn can be positive.
|
|
45
|
+
Keep the selected period and baseline clear in application context.
|
|
46
|
+
|
|
47
|
+
`MetricGrid` forwards one `variant`, size and state recipe to its peers. Its
|
|
48
|
+
default `gap="xl"` and Card insets remain independent from text/media `size`.
|
|
49
|
+
Narrow parents reduce track count even on a wide viewport. Use `columns` and
|
|
50
|
+
the public variants rather than overriding its internal grid, Card padding,
|
|
51
|
+
value typography or sparkline geometry.
|
|
52
|
+
|
|
53
|
+
The analytics family declaration/runtime graph requires the optional `recharts`
|
|
54
|
+
peer even when a selected presentation hides its sparkline. Read the finder
|
|
55
|
+
result's peers and installed declarations. UsageCard has a focused leaf import;
|
|
56
|
+
its quota model differs from general MetricData.
|
|
57
|
+
|
|
58
|
+
## Usage, facts and verification
|
|
59
|
+
|
|
60
|
+
For `UsageCard` period/loading/error/retry and quota meaning, read
|
|
61
|
+
[usage workflow](workflows.md#task-summaries-usage-and-inline-editing) and its
|
|
62
|
+
[workspace summary recipe](../examples/planning-usage-edit.tsx).
|
|
63
|
+
For record facts, choose MetadataList and primitives through the
|
|
64
|
+
[detail recipe](../examples/detail.tsx), then decide Page and Card boundaries
|
|
65
|
+
using [composition](composition.md#compose-from-the-task).
|
|
66
|
+
|
|
67
|
+
Verify zero/unavailable values, loading/error/retry/empty, accepted period data,
|
|
68
|
+
long labels/amounts, narrow parent widths and light/dark surfaces. Run the app's
|
|
69
|
+
types and behavior checks; discovery and typechecking do not prove rendered
|
|
70
|
+
geometry, keyboard callbacks or business-data correctness.
|