themelia-react-ui 1.0.1 → 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 +137 -0
- package/README.md +59 -13
- package/dist/{accordion-B-5Focs8.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-B5tPpXnS.js → ai-artifact-DLVdK0Py.js} +151 -155
- package/dist/ai-artifact-DLVdK0Py.js.map +1 -0
- package/dist/{app-shell-at8Kt4l_.js → app-shell-C_fKpljx.js} +11 -10
- package/dist/app-shell-C_fKpljx.js.map +1 -0
- package/dist/{attachment-BO2R47wn.js → attachment-DbjUWsP0.js} +12 -12
- package/dist/{attachment-BO2R47wn.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-Bpzty83c.js → avatar-Bu2HhitA.js} +6 -6
- package/dist/{avatar-Bpzty83c.js.map → avatar-Bu2HhitA.js.map} +1 -1
- 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 +2 -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 -4
- package/dist/base/forms-numeric.js +1 -1
- package/dist/base/forms.js +2 -2
- package/dist/base/inline-edit.js +40 -43
- package/dist/base/inline-edit.js.map +1 -1
- 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 +1 -1
- package/dist/blocks/analytics.js +510 -472
- 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 +36 -36
- package/dist/blocks/planning.js.map +1 -1
- 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-Cum56XOF.js → cards-qGSErLw_.js} +12 -12
- package/dist/{cards-Cum56XOF.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-BavDRjF7.js → checkbox-BQNDjUCh.js} +3 -3
- 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-xHKbAJDj.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-DEbdr-3u.js → combobox-BFnbJJp3.js} +18 -18
- package/dist/combobox-BFnbJJp3.js.map +1 -0
- package/dist/{combobox-xv3yJbzl.js → combobox-hozNwUcc.js} +313 -316
- package/dist/combobox-hozNwUcc.js.map +1 -0
- package/dist/{command-C0xe7u9B.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 +1 -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/navigation/tabs.d.ts +3 -5
- package/dist/components/base/popover/popover.recipes.d.ts +3 -3
- 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/types.d.ts +1 -1
- 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/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-6s-ucRQQ.js → containers-DqB-bSYE.js} +33 -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-cWIRdeaf.js → data-display-Bihs9Ven.js} +545 -332
- 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-CA6ogMQB.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-CFM5myut.js → display-CS6Hbk18.js} +8 -8
- package/dist/{display-CFM5myut.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 +1209 -1209
- package/dist/features/products.js.map +1 -1
- package/dist/features/questionnaire.js +52 -52
- 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-DWUkgEjR.js → feedback-CJkUAapr.js} +29 -29
- 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-BhsUtsxW.js → filters-D6FF8L6s.js} +715 -720
- package/dist/filters-D6FF8L6s.js.map +1 -0
- package/dist/{form-field-Bn7ZH1rA.js → form-field-CZwrkP7m.js} +17 -9
- package/dist/form-field-CZwrkP7m.js.map +1 -0
- package/dist/{form-sizing-BWs70_a2.js → form-sizing-QP8aIRaW.js} +8 -5
- package/dist/form-sizing-QP8aIRaW.js.map +1 -0
- package/dist/{forms-B7pzS25o.js → forms-B5NCbkSC.js} +35 -35
- package/dist/{forms-B7pzS25o.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-C59QZyxV.js → header-kxruN3RM.js} +53 -49
- package/dist/header-kxruN3RM.js.map +1 -0
- package/dist/{hooks-CM1Vp9Pe.js → hooks-BrlnCwQd.js} +2 -2
- package/dist/{hooks-CM1Vp9Pe.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 +40 -9
- 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-DhDRgnVZ.js → media-gallery-DLp3HAz0.js} +75 -74
- package/dist/media-gallery-DLp3HAz0.js.map +1 -0
- package/dist/{mentions-B8Ko-fhS.js → mentions-Cl0Kt_Pd.js} +52 -50
- package/dist/{mentions-B8Ko-fhS.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-DBEu4POU.js → navigation-DnQSNMT0.js} +64 -55
- package/dist/navigation-DnQSNMT0.js.map +1 -0
- package/dist/{navigation-BUIn2Qxx.js → navigation-DyytsLRB.js} +37 -37
- package/dist/navigation-DyytsLRB.js.map +1 -0
- package/dist/{navigation-row-recipes-GVh11KiT.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-BV6ioQg3.js → page-hGmT4nWK.js} +75 -64
- package/dist/page-hGmT4nWK.js.map +1 -0
- package/dist/{page-header-DQRa0jug.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-CoLDEg19.js → popover-CghIYdQf.js} +23 -22
- package/dist/popover-CghIYdQf.js.map +1 -0
- package/dist/{popover-menu-GLIQTJTx.js → popover-menu-B4PoWhRl.js} +6 -6
- package/dist/{popover-menu-GLIQTJTx.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-BOe8l_FZ.js → progress-BroqrAyV.js} +10 -9
- package/dist/progress-BroqrAyV.js.map +1 -0
- package/dist/{receipt-BM8xsGFy.js → receipt-BuJynLgf.js} +8 -8
- package/dist/{receipt-BM8xsGFy.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-BnCyyPOJ.js → settings-DOTOzeZ2.js} +10 -9
- package/dist/{settings-BnCyyPOJ.js.map → settings-DOTOzeZ2.js.map} +1 -1
- package/dist/{sheet-B-q914Ad.js → sheet-BFhrNehm.js} +11 -11
- package/dist/sheet-BFhrNehm.js.map +1 -0
- package/dist/{sidebar-DPR7fmqN.js → sidebar-CyR4XKwR.js} +219 -200
- package/dist/sidebar-CyR4XKwR.js.map +1 -0
- package/dist/{sidebar-C_2p3Tfj.js → sidebar-SvGJ0Zwi.js} +63 -58
- package/dist/sidebar-SvGJ0Zwi.js.map +1 -0
- package/dist/{skeleton-CmT1ppqb.js → skeleton-3F0uhYn3.js} +4 -4
- package/dist/{skeleton-CmT1ppqb.js.map → skeleton-3F0uhYn3.js.map} +1 -1
- package/dist/{smart-card-CYLn46e6.js → smart-card-DjGVV2xr.js} +171 -165
- package/dist/smart-card-DjGVV2xr.js.map +1 -0
- package/dist/{spinner-BY9HbUEh.js → spinner-Cpf7oRkF.js} +5 -5
- package/dist/{spinner-BY9HbUEh.js.map → spinner-Cpf7oRkF.js.map} +1 -1
- package/dist/{structure-MvKVq-oL.js → structure-CRdqVawd.js} +2 -2
- package/dist/{structure-MvKVq-oL.js.map → structure-CRdqVawd.js.map} +1 -1
- 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-B9ICkQcV.js → timelines-D1pkt3se.js} +84 -78
- package/dist/timelines-D1pkt3se.js.map +1 -0
- package/dist/{tree-BdWSaoFT.js → tree-BtmYyMZV.js} +8 -8
- package/dist/{tree-BdWSaoFT.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-D8Za5x_c.js → upload-CDbYw1WN.js} +326 -323
- package/dist/upload-CDbYw1WN.js.map +1 -0
- package/dist/{upload-queue-hIIYBLS7.js → upload-queue-CNd_hH_a.js} +25 -25
- package/dist/upload-queue-CNd_hH_a.js.map +1 -0
- package/dist/{usage-card-DnmnJ58D.js → usage-card-VyJLUwRr.js} +53 -54
- 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-C1PZmk8L.js → workspace-CcR8r-Nt.js} +115 -122
- package/dist/workspace-CcR8r-Nt.js.map +1 -0
- package/docs/consumer-skill/SKILL.md +110 -119
- 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 +20 -4
- package/docs/consumer-skill/examples/manifest.json +13 -1
- 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 +116 -2
- package/docs/consumer-skill/references/design-contract.md +33 -7
- package/docs/consumer-skill/references/discovery.md +76 -5
- package/docs/consumer-skill/references/integration.md +14 -0
- package/docs/consumer-skill/references/public-api.json +2023 -218
- package/docs/consumer-skill/references/review.md +55 -3
- 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 +32 -0
- package/docs/consumer-skill/scripts/check-composition.mjs +1 -1
- package/docs/consumer-skill/scripts/composition-policy.mjs +179 -17
- package/docs/consumer-skill/scripts/discovery.mjs +61 -9
- package/docs/consumer-skill/scripts/surface-policy.mjs +44 -0
- package/package.json +7 -4
- package/dist/accordion-B-5Focs8.js.map +0 -1
- package/dist/action-menu-Cx3SdfbN.js.map +0 -1
- package/dist/affordance-geometry.generated-D8Jcfb0G.js +0 -32
- package/dist/affordance-geometry.generated-D8Jcfb0G.js.map +0 -1
- package/dist/ai-artifact-B5tPpXnS.js.map +0 -1
- package/dist/app-shell-at8Kt4l_.js.map +0 -1
- package/dist/auth-OFwWSAap.js +0 -704
- package/dist/auth-OFwWSAap.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/checkbox-BavDRjF7.js.map +0 -1
- package/dist/choice-inputs-CC7XqPQO.js +0 -619
- package/dist/choice-inputs-CC7XqPQO.js.map +0 -1
- package/dist/code-block-xHKbAJDj.js.map +0 -1
- package/dist/combobox-DEbdr-3u.js.map +0 -1
- package/dist/combobox-xv3yJbzl.js.map +0 -1
- package/dist/command-C0xe7u9B.js.map +0 -1
- package/dist/comments-DviPLnwy.js +0 -1132
- package/dist/comments-DviPLnwy.js.map +0 -1
- package/dist/containers-6s-ucRQQ.js.map +0 -1
- package/dist/data-display-cWIRdeaf.js.map +0 -1
- package/dist/date-picker-CA6ogMQB.js.map +0 -1
- package/dist/date-pickers-BPIKLdsD.js +0 -224
- package/dist/date-pickers-BPIKLdsD.js.map +0 -1
- package/dist/feedback-DWUkgEjR.js.map +0 -1
- package/dist/field-affordance-recipes-IjzPrCTw.js +0 -17
- package/dist/field-affordance-recipes-IjzPrCTw.js.map +0 -1
- package/dist/field-state-recipes-CBTRt9Bt.js.map +0 -1
- package/dist/filters-BhsUtsxW.js.map +0 -1
- package/dist/form-field-Bn7ZH1rA.js.map +0 -1
- package/dist/form-sizing-BWs70_a2.js.map +0 -1
- package/dist/forms-numeric-BUBxELBv.js +0 -867
- package/dist/forms-numeric-BUBxELBv.js.map +0 -1
- package/dist/header-C59QZyxV.js.map +0 -1
- package/dist/http-CLTVJc5I.js.map +0 -1
- package/dist/input-WwYQZJzG.js +0 -202
- package/dist/input-WwYQZJzG.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-DhDRgnVZ.js.map +0 -1
- package/dist/message-COsdEvXT.js +0 -108
- package/dist/message-COsdEvXT.js.map +0 -1
- package/dist/navigation-BUIn2Qxx.js.map +0 -1
- package/dist/navigation-DBEu4POU.js.map +0 -1
- package/dist/navigation-row-recipes-GVh11KiT.js.map +0 -1
- package/dist/overlays-B11wZka6.js +0 -982
- package/dist/overlays-B11wZka6.js.map +0 -1
- package/dist/page-BV6ioQg3.js.map +0 -1
- package/dist/page-header-DQRa0jug.js.map +0 -1
- package/dist/pagination-C29vvt3I.js.map +0 -1
- package/dist/popover-CoLDEg19.js.map +0 -1
- package/dist/popover.recipes-zgBhMlUu.js.map +0 -1
- package/dist/primitives-DKPOGVpj.js.map +0 -1
- package/dist/progress-BOe8l_FZ.js.map +0 -1
- package/dist/rich-text-editor-CoVrTiSv.js +0 -575
- package/dist/rich-text-editor-CoVrTiSv.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-B-q914Ad.js.map +0 -1
- package/dist/sidebar-C_2p3Tfj.js.map +0 -1
- package/dist/sidebar-DPR7fmqN.js.map +0 -1
- package/dist/smart-card-CYLn46e6.js.map +0 -1
- package/dist/surface-recipes-CQfRr-VL.js.map +0 -1
- package/dist/table-BS39xnlq.js +0 -1424
- package/dist/table-BS39xnlq.js.map +0 -1
- package/dist/table-DnlAJ-xR.js.map +0 -1
- package/dist/tabs-B5cNMWiP.js +0 -187
- package/dist/tabs-B5cNMWiP.js.map +0 -1
- package/dist/text-inputs-Dh9XGyiS.js +0 -331
- package/dist/text-inputs-Dh9XGyiS.js.map +0 -1
- package/dist/text.styles-BwB7vAF2.js.map +0 -1
- package/dist/timelines-B9ICkQcV.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-D8Za5x_c.js.map +0 -1
- package/dist/upload-queue-hIIYBLS7.js.map +0 -1
- package/dist/usage-card-DnmnJ58D.js.map +0 -1
- package/dist/utils-C2EKeIw3.js +0 -72
- package/dist/utils-C2EKeIw3.js.map +0 -1
- package/dist/value-inputs-DX2dbxjj.js +0 -824
- package/dist/value-inputs-DX2dbxjj.js.map +0 -1
- package/dist/workspace-C1PZmk8L.js.map +0 -1
|
@@ -1,14 +1,33 @@
|
|
|
1
|
-
import { surfaceParts, surfaceForwarders, paddingClass, paddingProperty, utility } from './surface-policy.mjs';
|
|
1
|
+
import { surfaceParts, surfaceForwarders, paddingClass, paddingProperty, utility, attenuatedFocusRing, sharedCornerParts, displayNames, nativeDisplayNames, marginProperty, radiusProperty, replacesSharedRadius, cornerRole, addsCopyMargin } from './surface-policy.mjs';
|
|
2
2
|
|
|
3
|
-
const controlNames = /^(?:Base)?(?:Button|ButtonLink|IconButton)$|^(Input|InputGroupInput|Textarea|SelectTrigger|ComboboxTrigger)$/;
|
|
3
|
+
const controlNames = /^(?:Base)?(?:Button|ButtonLink|IconButton)$|^(Input|InputGroup|InputGroupInput|InputGroupTextarea|Textarea|PasswordInput|Select|SelectTrigger|ComboboxInput|ComboboxInputTrigger|ComboboxTrigger)$/;
|
|
4
4
|
const controlFamilies = new Set(['buttons', 'text-inputs', 'choice-inputs', 'combobox']);
|
|
5
5
|
const fixedControlClass = /^(?:h|min-h|size|p[xytrblse]?)-|^rounded-(?:xs|sm|md|lg|xl|[2-9]xl|\[)|^text-(?:xs|sm|base|lg|xl|[2-9]xl|\[(?:length:|[\d.]+(?:px|rem|em)))|^(?:font|leading|tracking)-/;
|
|
6
|
-
const controlStyle = /^(height|minHeight|fontSize|fontWeight|lineHeight|letterSpacing|borderRadius)$/;
|
|
6
|
+
const controlStyle = /^(height|minHeight|fontSize|fontWeight|fontFamily|lineHeight|letterSpacing|borderRadius)$/;
|
|
7
|
+
const fixedTextClass = /^text-(?:xs|sm|base|lg|xl|[2-9]xl|\[(?:length:|[\d.]+(?:px|rem|em)))|^(?:font|leading|tracking)-/;
|
|
8
|
+
const textStyle = /^(fontSize|fontWeight|fontFamily|lineHeight|letterSpacing)$/;
|
|
9
|
+
const smallPeerGaps = new Set(['none', 'normal', 'dense', '2xs', 'xs', 'sm', 'md']);
|
|
10
|
+
const structureDefaults = { Stack: 'md', Grid: 'xl', AdaptiveGrid: 'xl' };
|
|
11
|
+
const breakpoints = ['base', 'sm', 'md', 'lg', 'xl', '2xl'];
|
|
12
|
+
|
|
13
|
+
/** Bind this source only; never resolve imports, read libraries or run app code. */
|
|
14
|
+
export function sourceBindings(source, ts) {
|
|
15
|
+
const options = { noResolve: true, noLib: true, allowJs: true, jsx: ts.JsxEmit.Preserve };
|
|
16
|
+
const host = ts.createCompilerHost(options);
|
|
17
|
+
host.getSourceFile = filename => filename === source.fileName ? source : undefined;
|
|
18
|
+
const checker = ts.createProgram([source.fileName], options, host).getTypeChecker();
|
|
19
|
+
return node => {
|
|
20
|
+
if (!node) return undefined;
|
|
21
|
+
if (ts.isIdentifier(node) && ts.isShorthandPropertyAssignment(node.parent) && node.parent.name === node) return checker.getShorthandAssignmentValueSymbol(node.parent);
|
|
22
|
+
return checker.getSymbolAtLocation(node);
|
|
23
|
+
};
|
|
24
|
+
}
|
|
7
25
|
|
|
8
26
|
/** Small static review: TypeScript is supplied by the app, never a runtime peer. */
|
|
9
27
|
export function analyzeComposition(text, { filename, index, ts }) {
|
|
10
28
|
const kind = /\.jsx?$/.test(filename) ? ts.ScriptKind.JSX : filename.endsWith('.tsx') ? ts.ScriptKind.TSX : ts.ScriptKind.TS;
|
|
11
29
|
const source = ts.createSourceFile(filename, text, ts.ScriptTarget.Latest, true, kind);
|
|
30
|
+
const symbolFor = sourceBindings(source, ts);
|
|
12
31
|
const families = new Map(index.families.map(owner => [owner.import, owner]));
|
|
13
32
|
const bindings = new Map();
|
|
14
33
|
const namespaces = new Map();
|
|
@@ -33,7 +52,7 @@ export function analyzeComposition(text, { filename, index, ts }) {
|
|
|
33
52
|
const resolve = (node, visiting = new Set()) => {
|
|
34
53
|
if (!node || visiting.has(node)) return undefined;
|
|
35
54
|
visiting.add(node);
|
|
36
|
-
if (ts.isIdentifier(node)) return resolve(declarations.get(node
|
|
55
|
+
if (ts.isIdentifier(node)) return resolve(declarations.get(symbolFor(node)), visiting);
|
|
37
56
|
if (ts.isParenthesizedExpression(node) || ts.isAsExpression(node) || ts.isSatisfiesExpression(node)) return resolve(node.expression, visiting);
|
|
38
57
|
return node;
|
|
39
58
|
};
|
|
@@ -60,6 +79,20 @@ export function analyzeComposition(text, { filename, index, ts }) {
|
|
|
60
79
|
if (!node || visited.has(node)) { if (expression) unknown(expression); return []; }
|
|
61
80
|
visited.add(node);
|
|
62
81
|
if (ts.isStringLiteralLike(node)) return [node.text];
|
|
82
|
+
if (ts.isTemplateExpression(node)) {
|
|
83
|
+
// Keep complete static class tokens. A token split by a dynamic span is
|
|
84
|
+
// unresolved rather than an invented class from one of its fragments.
|
|
85
|
+
const chunks = [node.head.text];
|
|
86
|
+
for (const span of node.templateSpans) {
|
|
87
|
+
const resolved = resolve(span.expression);
|
|
88
|
+
if (resolved && (ts.isStringLiteralLike(resolved) || ts.isNumericLiteral(resolved))) chunks[chunks.length - 1] += resolved.text + span.literal.text;
|
|
89
|
+
else { unknown(span.expression); chunks.push(span.literal.text); }
|
|
90
|
+
}
|
|
91
|
+
return chunks.map((chunk, index) => {
|
|
92
|
+
const value = index > 0 ? chunk.replace(/^\S*/, '') : chunk;
|
|
93
|
+
return index < chunks.length - 1 ? value.replace(/\S*$/, '') : value;
|
|
94
|
+
});
|
|
95
|
+
}
|
|
63
96
|
if (ts.isConditionalExpression(node)) return [...classStrings(node.whenTrue, visited), ...classStrings(node.whenFalse, visited)];
|
|
64
97
|
if (ts.isBinaryExpression(node) && [ts.SyntaxKind.AmpersandAmpersandToken, ts.SyntaxKind.BarBarToken, ts.SyntaxKind.QuestionQuestionToken].includes(node.operatorToken.kind)) return classStrings(node.right, visited);
|
|
65
98
|
if (ts.isArrayLiteralExpression(node)) return node.elements.flatMap(item => classStrings(item, visited));
|
|
@@ -83,12 +116,12 @@ export function analyzeComposition(text, { filename, index, ts }) {
|
|
|
83
116
|
for (const item of elements) {
|
|
84
117
|
const symbol = (item.propertyName ?? item.name).text;
|
|
85
118
|
if (!family.symbols.includes(symbol)) add(item, 'public-symbol', 'error', `${specifier} does not export ${symbol}; inspect its declaration.`);
|
|
86
|
-
if (ts.isImportDeclaration(node)) bindings.set(item.name
|
|
119
|
+
if (ts.isImportDeclaration(node)) bindings.set(symbolFor(item.name), { symbol, import: specifier });
|
|
87
120
|
}
|
|
88
|
-
if (names && ts.isNamespaceImport(names)) namespaces.set(names.name
|
|
121
|
+
if (names && ts.isNamespaceImport(names)) namespaces.set(symbolFor(names.name), specifier);
|
|
89
122
|
}
|
|
90
123
|
function gather(node) {
|
|
91
|
-
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.initializer) declarations.set(node.name
|
|
124
|
+
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.initializer) declarations.set(symbolFor(node.name), node.initializer);
|
|
92
125
|
if ((ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) && node.moduleSpecifier && ts.isStringLiteralLike(node.moduleSpecifier)) importOwner(node, node.moduleSpecifier.text);
|
|
93
126
|
if (ts.isImportTypeNode(node) && ts.isLiteralTypeNode(node.argument) && ts.isStringLiteralLike(node.argument.literal)) importOwner(node, node.argument.literal.text);
|
|
94
127
|
if (ts.isCallExpression(node) && node.expression.kind === ts.SyntaxKind.ImportKeyword && ts.isStringLiteralLike(node.arguments[0])) importOwner(node, node.arguments[0].text);
|
|
@@ -97,10 +130,11 @@ export function analyzeComposition(text, { filename, index, ts }) {
|
|
|
97
130
|
gather(source);
|
|
98
131
|
for (const diagnostic of source.parseDiagnostics) add(source, 'syntax', 'error', ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'));
|
|
99
132
|
const ownerFor = tag => {
|
|
100
|
-
if (
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
133
|
+
if (ts.isIdentifier(tag)) return bindings.get(symbolFor(tag));
|
|
134
|
+
if (ts.isPropertyAccessExpression(tag) && ts.isIdentifier(tag.expression)) {
|
|
135
|
+
const specifier = namespaces.get(symbolFor(tag.expression));
|
|
136
|
+
return specifier ? { symbol: tag.name.text, import: specifier } : undefined;
|
|
137
|
+
}
|
|
104
138
|
};
|
|
105
139
|
const attributes = node => node.attributes.properties.flatMap(attribute => {
|
|
106
140
|
if (ts.isJsxSpreadAttribute(attribute)) return properties(attribute.expression);
|
|
@@ -108,6 +142,91 @@ export function analyzeComposition(text, { filename, index, ts }) {
|
|
|
108
142
|
const expression = ts.isJsxExpression(attribute.initializer) ? attribute.initializer.expression : attribute.initializer;
|
|
109
143
|
return [[attribute.name.getText(source), expression]];
|
|
110
144
|
});
|
|
145
|
+
const isOwner = (owner, suffix, names) => owner?.import === `${index.package}/${suffix}` && names.includes(owner.symbol);
|
|
146
|
+
const framedOwner = (owner, props) => {
|
|
147
|
+
if (literal(props.get('surface')) === 'flat') return false;
|
|
148
|
+
if (isOwner(owner, 'base/cards', ['Card', 'SmartCard']) || isOwner(owner, 'features/table', ['DataTable']) || isOwner(owner, 'features/data-view', ['DataView'])) return true;
|
|
149
|
+
if (isOwner(owner, 'blocks/analytics', ['Metric'])) return literal(props.get('variant')) === 'card';
|
|
150
|
+
if (isOwner(owner, 'blocks/analytics', ['MetricGrid'])) return !props.has('variant') || literal(props.get('variant')) === 'card';
|
|
151
|
+
return isOwner(owner, 'blocks/analytics/usage-card', ['UsageCard']) || isOwner(owner, 'blocks/analytics', ['UsageCard']) || isOwner(owner, 'blocks/planning', ['TaskCard']);
|
|
152
|
+
};
|
|
153
|
+
// Examine lexical JSX only. Names ending in Card are not evidence of framing;
|
|
154
|
+
// ChartCard is card-free; Receipt's flat paper has no ordinary Card frame.
|
|
155
|
+
const contentElements = element => {
|
|
156
|
+
const found = [];
|
|
157
|
+
function collect(child) {
|
|
158
|
+
if (ts.isJsxElement(child) || ts.isJsxSelfClosingElement(child)) {
|
|
159
|
+
const opening = ts.isJsxElement(child) ? child.openingElement : child;
|
|
160
|
+
const owner = ownerFor(opening.tagName);
|
|
161
|
+
found.push({ opening, owner, props: new Map(attributes(opening)), element: child });
|
|
162
|
+
if (isOwner(owner, 'base/cards', ['Card', 'SmartCard'])) return;
|
|
163
|
+
if (ts.isJsxElement(child)) child.children.forEach(collect);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (ts.isJsxFragment(child)) child.children.forEach(collect);
|
|
167
|
+
else if (ts.isJsxExpression(child) && child.expression) { const resolved = resolve(child.expression); if (resolved) collect(resolved); }
|
|
168
|
+
}
|
|
169
|
+
if (ts.isJsxElement(element.parent)) element.parent.children.forEach(collect);
|
|
170
|
+
return found;
|
|
171
|
+
};
|
|
172
|
+
const renderedText = element => ts.isJsxElement(element) ? element.children.map(child => ts.isJsxText(child) ? child.text : ts.isJsxExpression(child) ? literal(child.expression) ?? '' : '').join(' ').trim() : '';
|
|
173
|
+
const slotBadge = expression => {
|
|
174
|
+
const node = resolve(expression);
|
|
175
|
+
if (!node) return false;
|
|
176
|
+
if (ts.isJsxElement(node) || ts.isJsxSelfClosingElement(node)) {
|
|
177
|
+
const opening = ts.isJsxElement(node) ? node.openingElement : node;
|
|
178
|
+
const owner = ownerFor(opening.tagName);
|
|
179
|
+
if (isOwner(owner, 'base/badge', ['Badge'])) return true;
|
|
180
|
+
if (owner?.import === `${index.package}/base/buttons` || /^(button|a)$/.test(opening.tagName.getText(source))) return false;
|
|
181
|
+
if (!/^(div|span)$/.test(opening.tagName.getText(source)) && !isOwner(owner, 'base/structure', ['Stack', 'Grid'])) return false;
|
|
182
|
+
return ts.isJsxElement(node) && node.children.some(slotBadge);
|
|
183
|
+
}
|
|
184
|
+
if (ts.isJsxFragment(node)) return node.children.some(slotBadge);
|
|
185
|
+
if (ts.isJsxExpression(node)) return slotBadge(node.expression);
|
|
186
|
+
return false;
|
|
187
|
+
};
|
|
188
|
+
const peerCards = element => {
|
|
189
|
+
if (!ts.isJsxElement(element.parent)) return new Set();
|
|
190
|
+
const cards = [];
|
|
191
|
+
function collect(child) {
|
|
192
|
+
if (ts.isJsxFragment(child)) { child.children.forEach(collect); return; }
|
|
193
|
+
const opening = ts.isJsxElement(child) ? child.openingElement : ts.isJsxSelfClosingElement(child) ? child : undefined;
|
|
194
|
+
if (!opening) return;
|
|
195
|
+
const owner = ownerFor(opening.tagName);
|
|
196
|
+
if (framedOwner(owner, new Map(attributes(opening)))) cards.push(opening);
|
|
197
|
+
else if (owner?.symbol === 'GridCell' && owner.import === `${index.package}/base/structure` && ts.isJsxElement(child)) child.children.forEach(collect);
|
|
198
|
+
}
|
|
199
|
+
element.parent.children.forEach(collect);
|
|
200
|
+
return new Set(cards);
|
|
201
|
+
};
|
|
202
|
+
const gapEntries = (expression, fallback) => {
|
|
203
|
+
if (!expression) return { base: fallback };
|
|
204
|
+
const node = resolve(expression);
|
|
205
|
+
if (node && ts.isStringLiteralLike(node)) return { base: node.text };
|
|
206
|
+
if (node && ts.isObjectLiteralExpression(node)) return { base: fallback, ...Object.fromEntries(properties(node).filter(([key]) => breakpoints.includes(key)).map(([key, value]) => {
|
|
207
|
+
const gap = literal(value);
|
|
208
|
+
if (gap === undefined && value) unknown(value);
|
|
209
|
+
return [key, gap];
|
|
210
|
+
})) };
|
|
211
|
+
if (node && node.kind === ts.SyntaxKind.NullKeyword || ts.isIdentifier(expression) && expression.text === 'undefined' && !symbolFor(expression)) return { base: fallback };
|
|
212
|
+
unknown(expression);
|
|
213
|
+
return { base: undefined };
|
|
214
|
+
};
|
|
215
|
+
const smallGap = (props, symbol, unknownProps) => {
|
|
216
|
+
// Unknown spread props may replace a missing gap. Report them as unresolved
|
|
217
|
+
// instead of treating the live default as a proven effective value.
|
|
218
|
+
if (!props.has('gap') && unknownProps) return false;
|
|
219
|
+
const gaps = gapEntries(props.get('gap'), structureDefaults[symbol]);
|
|
220
|
+
const rows = symbol === 'Stack' ? {} : gapEntries(props.get('rowGap'));
|
|
221
|
+
const columns = symbol === 'Stack' ? {} : gapEntries(props.get('columnGap'));
|
|
222
|
+
let gap; let row; let column;
|
|
223
|
+
return breakpoints.some(breakpoint => {
|
|
224
|
+
if (Object.hasOwn(gaps, breakpoint)) gap = gaps[breakpoint];
|
|
225
|
+
if (Object.hasOwn(rows, breakpoint)) row = rows[breakpoint];
|
|
226
|
+
if (Object.hasOwn(columns, breakpoint)) column = columns[breakpoint];
|
|
227
|
+
return smallPeerGaps.has(row ?? gap) || smallPeerGaps.has(column ?? gap);
|
|
228
|
+
});
|
|
229
|
+
};
|
|
111
230
|
function visit(node, parents = []) {
|
|
112
231
|
if (ts.isJsxElement(node)) {
|
|
113
232
|
const element = node.openingElement;
|
|
@@ -121,34 +240,77 @@ export function analyzeComposition(text, { filename, index, ts }) {
|
|
|
121
240
|
ts.forEachChild(node, child => visit(child, parents));
|
|
122
241
|
}
|
|
123
242
|
function inspect(node, parents) {
|
|
124
|
-
const owner = ownerFor(node.tagName
|
|
125
|
-
if (!owner)
|
|
243
|
+
const owner = ownerFor(node.tagName);
|
|
244
|
+
if (!owner) {
|
|
245
|
+
if (node.tagName.getText(source) === 'div' && literal(new Map(attributes(node)).get('role')) === 'dialog') add(node, 'raw-overlay-primitive', 'warning', 'A custom dialog needs focus, dismissal and pending-state ownership. Compare ActionDialog/ConfirmDialog/ActionDrawer from features/overlays before maintaining that lifecycle.');
|
|
246
|
+
if (/^(?:input|textarea)$/.test(node.tagName.getText(source))) {
|
|
247
|
+
const props = new Map(attributes(node));
|
|
248
|
+
if (props.has('className') && classStrings(props.get('className')).flatMap(value=>value.split(/\s+/)).some(value=>replacesSharedRadius(value,'inner'))) add(node,'shared-radius','error','Native editable controls follow bounded rounded-inner; change the global theme root, not per-field corners.');
|
|
249
|
+
if (props.has('style') && properties(props.get('style')).some(([name])=>radiusProperty.test(name))) add(node,'shared-radius','error','Native editable corners belong to the global radius root, not inline styles.');
|
|
250
|
+
}
|
|
251
|
+
if (nativeDisplayNames.test(node.tagName.getText(source))) {
|
|
252
|
+
const props = new Map(attributes(node));
|
|
253
|
+
if (props.has('className') && classStrings(props.get('className')).flatMap(value=>value.split(/\s+/)).some(addsCopyMargin)) add(node,'copy-margin','error','Display copy is margin-free; use the surrounding structure for copy gaps.');
|
|
254
|
+
if (props.has('style') && properties(props.get('style')).some(([name,value])=>marginProperty.test(name)&&!/^['"]?0(?:px|rem|em|%)?['"]?$/.test(resolve(value)?.getText(source)??''))) add(node,'copy-margin','error','Display copy is margin-free; use the surrounding structure for copy gaps.');
|
|
255
|
+
}
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
126
258
|
if (!families.get(owner.import)?.symbols.includes(owner.symbol)) {
|
|
127
259
|
add(node, 'public-symbol', 'error', `${owner.import} does not export ${owner.symbol}.`);
|
|
128
260
|
return;
|
|
129
261
|
}
|
|
262
|
+
const unresolvedBeforeProps = unresolved.length;
|
|
130
263
|
const props = new Map(attributes(node));
|
|
264
|
+
const unknownProps = unresolved.length !== unresolvedBeforeProps;
|
|
131
265
|
const family = owner.import.split('/base/')[1];
|
|
132
266
|
const anatomy = surfaceParts[family]?.test(owner.symbol);
|
|
133
267
|
const forwarder = surfaceForwarders[family] === owner.symbol;
|
|
134
268
|
const control = controlFamilies.has(family) && controlNames.test(owner.symbol);
|
|
135
|
-
|
|
269
|
+
const sharedCorners = sharedCornerParts[family]?.test(owner.symbol);
|
|
270
|
+
const display = owner.import === `${index.package}/typography` && displayNames.test(owner.symbol);
|
|
271
|
+
const fixedText = owner.import === `${index.package}/typography` && owner.symbol === 'DisplayLabel' || family === 'badge' && owner.symbol === 'Badge';
|
|
272
|
+
const badge = family === 'badge' && owner.symbol === 'Badge';
|
|
273
|
+
for (const name of ['className', 'headerClassName', 'contentClassName', 'footerClassName', 'subHeadingClassName']) {
|
|
136
274
|
if (!props.has(name)) continue;
|
|
137
275
|
const classes = classStrings(props.get(name)).flatMap(value => value.split(/\s+/)).map(utility);
|
|
138
276
|
if ((anatomy || forwarder && name === 'contentClassName') && classes.some(value => paddingClass.test(value))) add(node, 'surface-padding', 'error', `${owner.symbol}: use inset/type/density and public regions; padding overrides replace owned anatomy.`);
|
|
139
277
|
if (control && name === 'className' && classes.some(value => fixedControlClass.test(value))) add(node, 'control-anatomy', 'error', `${owner.symbol}: use its size/variant props; preserve shared control height, inset, corners and typography.`);
|
|
278
|
+
if ((name === 'className' && (control || sharedCorners) || name === 'contentClassName' && forwarder) && classes.some(value=>replacesSharedRadius(value, control && name === 'className' ? 'inner' : cornerRole(family,owner.symbol)))) add(node,'shared-radius','error',`${owner.symbol}: outer shells use rounded-radius; controls and collection rows use bounded rounded-inner. Preserve the owning role and joined-edge resets.`);
|
|
279
|
+
if (display && classes.some(addsCopyMargin)) add(node,'copy-margin','error',`${owner.symbol}: typography is margin-free; use textGap on the headed owner or gap on Stack/Grid.`);
|
|
280
|
+
if ((control || family === 'buttons' && owner.symbol === 'TextButton') && name === 'className' && classes.some(attenuatedFocusRing)) add(node, 'focus-ring-contrast', 'error', `${owner.symbol}: keep the shared ring-ring/sidebar-ring focus color at full strength; numeric opacity weakens its tested contrast.`);
|
|
281
|
+
if (fixedText && name === 'className' && classes.some(value => fixedTextClass.test(value) || badge && /^rounded(?:-|$)/.test(value))) add(node, 'fixed-text-role', 'error', `${owner.symbol}: preserve its shared typography${badge ? ' and radius' : ''}; use its public variants and className for placement.`);
|
|
140
282
|
}
|
|
141
|
-
if (props.has('style')) for (const [name] of properties(props.get('style'))) {
|
|
283
|
+
if (props.has('style')) for (const [name,value] of properties(props.get('style'))) {
|
|
142
284
|
if (anatomy && paddingProperty.test(name)) add(node, 'surface-padding', 'error', `${owner.symbol}: ${name} replaces the region inset; use its public surface props.`);
|
|
143
285
|
if (control && (paddingProperty.test(name) || controlStyle.test(name))) add(node, 'control-anatomy', 'error', `${owner.symbol}: ${name} belongs to shared control geometry/typography.`);
|
|
286
|
+
if ((control || sharedCorners) && radiusProperty.test(name)) add(node,'shared-radius','error',`${owner.symbol}: corners follow the global radius theme root, not inline styles.`);
|
|
287
|
+
if (display && marginProperty.test(name) && !/^['"]?0(?:px|rem|em|%)?['"]?$/.test(resolve(value)?.getText(source)??'')) add(node,'copy-margin','error',`${owner.symbol}: typography is margin-free; the surrounding structure owns its copy gap.`);
|
|
288
|
+
if (fixedText && (textStyle.test(name) || badge && /^border.*Radius$/.test(name))) add(node, 'fixed-text-role', 'error', `${owner.symbol}: ${name} replaces its shared text/radius recipe.`);
|
|
144
289
|
}
|
|
145
290
|
if (['SmartCard', 'ContentBlock'].includes(owner.symbol)) add(node, 'deprecated-owner', 'warning', `${owner.symbol} is a migration owner; prefer Card for new compositions.`);
|
|
146
|
-
const framed =
|
|
291
|
+
const framed = framedOwner(owner, props);
|
|
292
|
+
if (isOwner(owner, 'base/cards', ['Card', 'SmartCard'])) {
|
|
293
|
+
for (const slot of ['headerAction', 'headerStart']) if (slotBadge(props.get(slot))) add(node, 'card-badge-placement', 'error', `${owner.symbol}: put status/count/version badges in titleSuffix; ${slot} owns ${slot === 'headerAction' ? 'commands' : 'pre-title context'}.`);
|
|
294
|
+
const contents = contentElements(node);
|
|
295
|
+
const role = (item, names) => isOwner(item.owner, 'typography', names);
|
|
296
|
+
const valueHeading = contents.some(item => role(item, ['Heading']) && /[$€£¥]|\d/.test(renderedText(item.element)));
|
|
297
|
+
if (valueHeading && contents.some(item => role(item, ['Text', 'DisplayLabel'])) && contents.some(item => isOwner(item.owner, 'base/badge', ['Badge']) && /[%+−-]|\d/.test(renderedText(item.element)))) add(node, 'reinvented-metric-card', 'warning', 'This label/value/change composition resembles a KPI. Compare Metric/MetricGrid from blocks/analytics or InlineStat from blocks/data-display; retain a custom subject when their metric lifecycle does not fit.');
|
|
298
|
+
const factRows = contents.filter(item => isOwner(item.owner, 'base/structure', ['Stack']) && literal(item.props.get('direction')) === 'horizontal' && literal(item.props.get('justify')) === 'between' && contentElements(item.opening).filter(child => role(child, ['Text', 'DisplayLabel'])).length >= 2);
|
|
299
|
+
if (factRows.length >= 2) add(node, 'reinvented-metadata-list', 'warning', 'Repeated label/value rows resemble record facts. Compare MetadataList or InlineStat from blocks/data-display; preserve custom rows when they own distinct interactions or content.');
|
|
300
|
+
if (contents.some(item => role(item, ['Heading']) && /^(?:no\b|nothing\b|empty\b)/i.test(renderedText(item.element))) && contents.some(item => isOwner(item.owner, 'base/structure', ['Stack']) && literal(item.props.get('align')) === 'center') && contents.some(item => isOwner(item.owner, 'base/buttons', ['Button', 'ButtonLink']))) add(node, 'reinvented-empty-state', 'warning', 'This centered empty region may fit EmptyState from blocks/data-display, with media, title, description and actions. Review the product state before choosing the complete owner.');
|
|
301
|
+
}
|
|
302
|
+
if (isOwner(owner, 'base/feedback', ['Empty'])) add(node, 'reinvented-empty-state', 'warning', 'Empty exposes lower-level anatomy. Compare EmptyState from blocks/data-display for a routine no-data/no-results region; keep Empty when custom anatomy is required.');
|
|
303
|
+
if (isOwner(owner, 'base/sheet', ['Sheet', 'SheetContent']) || isOwner(owner, 'base/display', ['Dialog', 'DialogContent', 'AlertDialog', 'AlertDialogContent'])) add(node, 'raw-overlay-primitive', 'warning', 'This lower-level modal needs application lifecycle coordination. Prefer ActionDialog, ConfirmDialog or ActionDrawer from features/overlays when their workflow fits.');
|
|
304
|
+
if (owner.symbol === 'Page' && literal(props.get('gutter')) === 'none' && !parents.some(parent => parent.framed)) add(node, 'page-gutter', 'warning', 'Page gutter="none" delegates inline padding to a real parent. PageViewport owns scrolling, not padding; verify the parent inset.');
|
|
305
|
+
if (owner.symbol === 'Card' && framed && literal(props.get('padding')) === 'sm' && !parents.some(parent => parent.framed)) add(node, 'compact-card', 'warning', 'Standalone Card padding="sm" halves the normal inset. Omit padding for ordinary subjects; retain sm only for an intentional compact composition.');
|
|
306
|
+
const peers = parents.findLast(parent => parent.structure);
|
|
307
|
+
if (framed && (!props.has('surface') || literal(props.get('surface')) === 'framed') && peers?.cards.size > 1 && peers.cards.has(node) && peers.smallGap) add(node, 'card-peer-gap', 'warning', 'Small peer gaps can be consumed by framed Card rings. Use lg/xl for independent surfaces and inspect visible edge clearance; tighter grouping needs an intentional surface policy.');
|
|
147
308
|
if (framed && parents.some(parent => parent.framed)) add(node, 'nested-surface', 'warning', `${owner.symbol} is inside a framed owner. Review subject boundaries; use surface="flat" when the parent owns the frame.`);
|
|
148
309
|
const header = properties(props.get('header'), false);
|
|
149
310
|
const title = literal(props.get('title')) ?? literal(new Map(header).get('title'));
|
|
150
311
|
if (title && parents.some(parent => parent.title === title)) add(node, 'duplicate-heading', 'warning', `The heading "${title}" repeats its ancestor. Keep one route/subject title unless a distinct task warrants repetition.`);
|
|
151
|
-
|
|
312
|
+
const structure = owner.import === `${index.package}/base/structure` && Object.hasOwn(structureDefaults, owner.symbol);
|
|
313
|
+
return { framed, title, structure, cards: structure ? peerCards(node) : new Set(), smallGap: structure ? smallGap(props, owner.symbol, unknownProps) : false };
|
|
152
314
|
}
|
|
153
315
|
visit(source);
|
|
154
316
|
return { findings, unresolved };
|
|
@@ -3,6 +3,10 @@ const requireFormat = (condition, message) => { if (!condition) throw new Error(
|
|
|
3
3
|
const stringList = value => Array.isArray(value) && value.every(item => typeof item === 'string');
|
|
4
4
|
const text = value => typeof value === 'string' && value.trim().length > 0;
|
|
5
5
|
const normalized = value => value.toLowerCase();
|
|
6
|
+
const words = value => value.replace(/([a-z0-9])([A-Z])/g, '$1 $2').replace(/([A-Z])([A-Z][a-z])/g, '$1 $2').toLowerCase().split(/[^a-z0-9]+/).filter(Boolean);
|
|
7
|
+
const symbolKey = value => words(value).join('');
|
|
8
|
+
const searchable = value => words(value).join(' ');
|
|
9
|
+
const containsTerms = (value, terms) => { const tokens = new Set(words(value)); return terms.every(term => tokens.has(term)); };
|
|
6
10
|
const compare = (a, b) => a < b ? -1 : a > b ? 1 : 0;
|
|
7
11
|
|
|
8
12
|
export function validateIndex(index) {
|
|
@@ -17,7 +21,17 @@ export function validateIndex(index) {
|
|
|
17
21
|
requireFormat(text(family.declaration) && /^dist\/[\w./-]+\.d\.ts$/.test(family.declaration) && !family.declaration.split('/').includes('..'), `invalid declaration ${family.declaration}`);
|
|
18
22
|
requireFormat(layers.includes(family.layer) && text(family.responsibility), `missing layer/responsibility for ${family.import}`);
|
|
19
23
|
for (const field of ['symbols', 'jobs', 'tags', 'aliases', 'sections', 'optionalPeers']) requireFormat(stringList(family[field]), `invalid ${field} for ${family.import}`);
|
|
24
|
+
if (family.references !== undefined) requireFormat(stringList(family.references) && family.references.every(file => /^references\/[\w/-]+\.md(?:#[\w-]+)?$/.test(file) && !file.split('/').includes('..')), `invalid focused references for ${family.import}`);
|
|
20
25
|
requireFormat(family.optionalPeers.every(peer => index.peers?.some(owner => owner.name === peer && owner.optional)), `unknown optional peer for ${family.import}`);
|
|
26
|
+
if (family.recipes !== undefined) {
|
|
27
|
+
requireFormat(Array.isArray(family.recipes), `invalid recipes for ${family.import}`);
|
|
28
|
+
for (const recipe of family.recipes) {
|
|
29
|
+
requireFormat(text(recipe?.file) && /^examples\/[\w/-]+\.tsx$/.test(recipe.file) && !recipe.file.split('/').includes('..'), 'invalid recipe file');
|
|
30
|
+
requireFormat(stringList(recipe.exports) && recipe.exports.length > 0 && stringList(recipe.symbols) && recipe.symbols.every(symbol => family.symbols.includes(symbol)), `unknown recipe symbol for ${family.import}`);
|
|
31
|
+
requireFormat(stringList(recipe.references) && recipe.references.every(file => /^references\/[\w/-]+\.md(?:#[\w-]+)?$/.test(file) && !file.split('/').includes('..')), 'invalid recipe references');
|
|
32
|
+
if (recipe.optionalPeers !== undefined) requireFormat(stringList(recipe.optionalPeers) && recipe.optionalPeers.every(peer => index.peers?.some(owner => owner.name === peer && owner.optional)), 'invalid recipe optional peers');
|
|
33
|
+
}
|
|
34
|
+
}
|
|
21
35
|
requireFormat(Array.isArray(family.guidance), `invalid guidance for ${family.import}`);
|
|
22
36
|
for (const guide of family.guidance) {
|
|
23
37
|
requireFormat(text(guide?.title) && typeof guide.description === 'string' && typeof guide.section === 'string', 'invalid guidance title/description/section');
|
|
@@ -56,28 +70,66 @@ export function parseArguments(args) {
|
|
|
56
70
|
return { query, ...options };
|
|
57
71
|
}
|
|
58
72
|
|
|
59
|
-
const guideText = guide =>
|
|
73
|
+
const guideText = guide => searchable([guide.title, guide.description, ...Object.values(guide.browse), ...guide.jobs, ...guide.tags, ...guide.aliases, ...guide.chooseWhen, ...guide.appOwned, ...guide.sections.flatMap(section => [section.title, ...section.symbols])].join(' '));
|
|
74
|
+
const guideSymbols = (guide, family) => [...new Set(guide.sections.flatMap(section => section.symbols))].filter(symbol => family.symbols.includes(symbol));
|
|
75
|
+
|
|
76
|
+
function relevantGuidance(family, needle, terms, matchedSymbols, exactImport) {
|
|
77
|
+
const ranked = family.guidance.map(guide => {
|
|
78
|
+
const haystack = guideText(guide);
|
|
79
|
+
const count = terms.filter(term => containsTerms(haystack, [term])).length;
|
|
80
|
+
const symbol = matchedSymbols.some(value => guideSymbols(guide, family).includes(value));
|
|
81
|
+
const alias = guide.aliases.some(value => normalized(value) === needle);
|
|
82
|
+
const complete = count === terms.length;
|
|
83
|
+
const score = Number(alias) * 10000 + Number(symbol) * 1000 + Number(complete) * 100 + count;
|
|
84
|
+
return { guide, score, symbol, alias, complete };
|
|
85
|
+
}).sort((a, b) => b.score - a.score || Number(guideSymbols(b.guide, family).length > 0) - Number(guideSymbols(a.guide, family).length > 0) || compare(a.guide.title, b.guide.title));
|
|
86
|
+
// Exact owner and curated task matches supply their own narrow reading path.
|
|
87
|
+
// Generic intent can still combine terms across fields/family guidance.
|
|
88
|
+
const selected = ranked.filter(item => ranked.some(item => item.alias) ? item.alias : matchedSymbols.length ? item.symbol : ranked.some(item => item.complete) ? item.complete : item.score > 0);
|
|
89
|
+
return (selected.length || !exactImport ? selected : ranked).slice(0, 3).map(item => item.guide);
|
|
90
|
+
}
|
|
60
91
|
|
|
61
92
|
export function findComponents(index, { query, layer = null, limit = 5 }) {
|
|
62
93
|
validateIndex(index);
|
|
63
94
|
const needle = normalized(query);
|
|
64
|
-
const terms = [...new Set(
|
|
95
|
+
const terms = [...new Set(words(query))];
|
|
96
|
+
const key = symbolKey(query);
|
|
97
|
+
// Cased API names and explicit imports request a precise contract. Ordinary
|
|
98
|
+
// nouns such as table/empty remain task searches with richer alternatives.
|
|
99
|
+
const exactOwners = index.families.filter(family => (!layer || layer === family.layer) && (normalized(family.import) === needle || family.symbols.includes(query.trim())));
|
|
65
100
|
const ranked = [];
|
|
66
101
|
for (const family of index.families) {
|
|
67
102
|
if (layer && layer !== family.layer) continue;
|
|
103
|
+
if (exactOwners.length && !exactOwners.includes(family)) continue;
|
|
68
104
|
const exactImport = normalized(family.import) === needle;
|
|
69
|
-
const matchedSymbols = family.symbols.filter(symbol =>
|
|
70
|
-
const
|
|
105
|
+
const matchedSymbols = family.symbols.filter(symbol => symbolKey(symbol) === key);
|
|
106
|
+
const documented = new Set(family.guidance.flatMap(guide => guideSymbols(guide, family)));
|
|
107
|
+
const focusedSymbols = [...documented].filter(symbol => containsTerms(symbol, terms));
|
|
108
|
+
const haystack = searchable([family.import, family.responsibility, ...documented, ...family.jobs, ...family.tags, ...family.aliases, ...family.sections, ...family.guidance.map(guideText)].join(' '));
|
|
71
109
|
// AND matching prevents a familiar term from inventing results for an
|
|
72
110
|
// otherwise unknown query. Avoidance/alternatives do not recommend owners.
|
|
73
|
-
if (!exactImport && !matchedSymbols.length && !
|
|
111
|
+
if (!exactImport && !matchedSymbols.length && !containsTerms(haystack, terms)) continue;
|
|
74
112
|
// A dedicated, documented owner precedes an aggregate re-export of the
|
|
75
113
|
// same symbol. Explicit import queries still select the requested family.
|
|
76
|
-
const documentedSymbol =
|
|
114
|
+
const documentedSymbol = matchedSymbols.some(symbol => documented.has(symbol));
|
|
115
|
+
const exactFamily = searchable(family.import.split('/').at(-1)) === terms.join(' ');
|
|
77
116
|
const exactIntent = family.aliases.some(alias => normalized(alias) === needle);
|
|
78
|
-
const score = exactImport ? 10000 : matchedSymbols.length ? 9000 + Number(documentedSymbol) : exactIntent ? 8000 : terms.reduce((sum, term) => sum + (family.guidance.some(guide =>
|
|
79
|
-
const
|
|
80
|
-
|
|
117
|
+
const score = exactImport ? 10000 : matchedSymbols.length ? 9000 + Number(documentedSymbol) : exactFamily ? 8500 : exactIntent ? 8000 : focusedSymbols.length ? 7100 + 1 / Math.min(...focusedSymbols.map(symbol => words(symbol).length)) : terms.reduce((sum, term) => sum + (family.guidance.some(guide => containsTerms(guide.title, [term])) ? 20 : family.tags.some(tag => containsTerms(tag, [term])) ? 10 : 1), 0);
|
|
118
|
+
const selectedSymbols = matchedSymbols.length ? matchedSymbols : focusedSymbols;
|
|
119
|
+
const guidance = relevantGuidance(family, needle, terms, exactOwners.length ? selectedSymbols : [], exactImport);
|
|
120
|
+
const relevantSymbols = exactImport ? family.symbols : exactOwners.length || matchedSymbols.length ? selectedSymbols : [...new Set([...selectedSymbols, ...guidance.flatMap(guide => guideSymbols(guide, family))])];
|
|
121
|
+
const candidates = (family.recipes ?? []).filter(recipe => recipe.symbols.some(symbol => relevantSymbols.includes(symbol)));
|
|
122
|
+
const recipeText = recipe => normalized([recipe.file, ...recipe.exports, ...recipe.references].join(' ')).replace(/[-/#]/g, ' ');
|
|
123
|
+
const taskRecipes = matchedSymbols.length || exactImport ? [] : candidates.filter(recipe => terms.every(term => recipeText(recipe).includes(term)));
|
|
124
|
+
const aliases = guidance.flatMap(guide => guide.aliases.map(alias => normalized(alias).split(/\s+/)));
|
|
125
|
+
const aliasRecipes = matchedSymbols.length || exactImport ? [] : candidates.filter(recipe => aliases.some(intent => intent.every(term => recipeText(recipe).includes(term))));
|
|
126
|
+
const recipes = taskRecipes.length ? taskRecipes : aliasRecipes.length ? aliasRecipes : candidates;
|
|
127
|
+
const nextReads = {
|
|
128
|
+
declaration: family.declaration,
|
|
129
|
+
references: [...new Set([...(family.references ?? []), ...recipes.flatMap(recipe => recipe.references)])].sort(compare),
|
|
130
|
+
examples: recipes.map(({ file, exports, symbols, optionalPeers = [] }) => ({ file, exports, symbols: symbols.filter(symbol => relevantSymbols.includes(symbol)), optionalPeers })),
|
|
131
|
+
};
|
|
132
|
+
ranked.push({ score, import: family.import, declaration: family.declaration, layer: family.layer, responsibility: family.responsibility, optionalPeers: family.optionalPeers, match: exactImport ? 'import' : matchedSymbols.length ? 'symbol' : 'intent', matchedSymbols, relevantSymbols, nextReads, guidance });
|
|
81
133
|
}
|
|
82
134
|
ranked.sort((a, b) => b.score - a.score || compare(a.import, b.import));
|
|
83
135
|
return { package: index.package, version: index.version, query, layer, limit, total: ranked.length, results: ranked.slice(0, limit) };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// One public anatomy vocabulary, shared by repository and opt-in consumer checks.
|
|
2
2
|
export const surfaceParts = {
|
|
3
|
+
cards: /^Card(?:Header|Content|Footer)?$/,
|
|
3
4
|
popover: /^(PopoverContent|PopoverHeader|PopoverFooter)$/,
|
|
4
5
|
command: /^Command(Input|List|Group|Item|Empty|Separator)?$/,
|
|
5
6
|
navigation: /^DropdownMenu(Content|SubContent|Label|Item|LinkItem|SubTrigger|CheckboxItem|RadioItem|Separator)$/,
|
|
@@ -10,6 +11,41 @@ export const surfaceForwarders = { 'choice-inputs': 'Select', 'popover-menu': 'P
|
|
|
10
11
|
export const paddingClass = /^(?:p[xytrblse]?|p(?:bs|be)|padding)-|^\[padding/;
|
|
11
12
|
export const paddingProperty = /^padding(?:Inline|Block)?(?:Start|End)?$|^padding(?:Top|Right|Bottom|Left)$|^padding-(?:(?:inline|block)(?:-(?:start|end))?|top|right|bottom|left)$/;
|
|
12
13
|
|
|
14
|
+
// One root, two owned roles: outer shells and inner controls/collection rows.
|
|
15
|
+
// Circular shapes and joined-edge resets retain their explicit mechanics.
|
|
16
|
+
export const sharedCornerParts = {
|
|
17
|
+
cards: /^Card$/,
|
|
18
|
+
popover: /^PopoverContent$/,
|
|
19
|
+
command: /^Command(?:Item)?$/,
|
|
20
|
+
navigation: /^(?:DropdownMenu(?:Content|SubContent|Item|LinkItem|SubTrigger|CheckboxItem|RadioItem)|TabsList|TabsTrigger)$/,
|
|
21
|
+
'choice-inputs': /^SelectPopup(?:Content|Item)$/,
|
|
22
|
+
item: /^Item$/,
|
|
23
|
+
combobox: /^Combobox(?:Popup|Content|Item)$/,
|
|
24
|
+
display: /^(?:DialogContent|AlertDialogContent)$/,
|
|
25
|
+
sheet: /^SheetContent$/,
|
|
26
|
+
};
|
|
27
|
+
export const displayNames = /^(?:Text|Heading|DisplayLabel|Label|TextLink)$/;
|
|
28
|
+
export const nativeDisplayNames = /^(?:p|h[1-6])$/;
|
|
29
|
+
export const marginProperty = /^margin(?:Inline|Block)?(?:Start|End)?$|^margin(?:Top|Right|Bottom|Left)$|^margin-(?:(?:inline|block)(?:-(?:start|end))?|top|right|bottom|left)$/;
|
|
30
|
+
export const radiusProperty = /^border(?:(?:Top|Bottom)(?:Left|Right)|(?:Start|End)(?:Start|End))?Radius$|^border-(?:(?:top|bottom)-(?:left|right)-|(?:start|end)-(?:start|end)-)?radius$/;
|
|
31
|
+
|
|
32
|
+
export function cornerRole(family, symbol) {
|
|
33
|
+
if (family === 'item' && symbol === 'Item' || family === 'navigation' && /^(?:TabsList|TabsTrigger)$/.test(symbol)) return 'inner';
|
|
34
|
+
return sharedCornerParts[family]?.test(symbol) && /(?:Item|SubTrigger)$/.test(symbol) ? 'inner' : 'radius';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function replacesSharedRadius(token, role = 'radius') {
|
|
38
|
+
const value = utility(token);
|
|
39
|
+
if (new RegExp(`^rounded(?:-[trblse]{1,2})?-(?:${role}|none)$`).test(value)) return false;
|
|
40
|
+
return /^rounded(?:-|$)/.test(value) || /^\[border-(?:(?:top|bottom)-(?:left|right)-|(?:start|end)-(?:start|end)-)?radius:/.test(value);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function addsCopyMargin(token) {
|
|
44
|
+
const value = utility(token);
|
|
45
|
+
const match = value.match(/^-?m(?:[xytrblse]|bs|be)?-(.+)$|^\[margin[^:]*:(.+)\]$/);
|
|
46
|
+
return !!match && !/^(?:0(?:px|rem|em|%)?|\[0(?:px|rem|em|%)?\])$/.test(match[1] ?? match[2]);
|
|
47
|
+
}
|
|
48
|
+
|
|
13
49
|
export function utility(token) {
|
|
14
50
|
let depth = 0;
|
|
15
51
|
let start = 0;
|
|
@@ -20,3 +56,11 @@ export function utility(token) {
|
|
|
20
56
|
}
|
|
21
57
|
return token.slice(start).replace(/^!|!$/g, '');
|
|
22
58
|
}
|
|
59
|
+
|
|
60
|
+
/** Shared focus roles are contrast-tested at full strength, unlike status tints. */
|
|
61
|
+
export function attenuatedFocusRing(token) {
|
|
62
|
+
const match = utility(token).match(/^ring-(?:ring|sidebar-ring)\/(?:(\d+(?:\.\d+)?|\.\d+)|\[(\d+(?:\.\d+)?|\.\d+)(%)?\])$/);
|
|
63
|
+
if (!match) return false;
|
|
64
|
+
const opacity = Number(match[1] ?? match[2]);
|
|
65
|
+
return opacity < (match[1] !== undefined || match[3] ? 100 : 1);
|
|
66
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "themelia-react-ui",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "A composable React UI library for modern admin applications, built on Base UI and Tailwind with shadcn-compatible themes, shared design tokens, reusable layouts, blocks and workflows.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
@@ -447,7 +447,7 @@
|
|
|
447
447
|
"test:browser": "npm run build:preview && node scripts/run-browser.mjs",
|
|
448
448
|
"check:package": "node scripts/check-package.mjs",
|
|
449
449
|
"check": "npm run check:contract && npm run check:preview && npm run check:docs && npm run lint && npm run check:design-lint && npm run typecheck && npm test && npm run build && npm run check:skill && npm run check:maps && npm run check:package && npm run build:preview",
|
|
450
|
-
"check:contract": "node --test scripts/test-runtime-ownership.mjs scripts/test-primitive-geometry.mjs scripts/test-source-entrypoints.mjs && node scripts/check-contract.mjs",
|
|
450
|
+
"check:contract": "node --test scripts/test-runtime-ownership.mjs scripts/test-primitive-geometry.mjs scripts/test-source-entrypoints.mjs scripts/test-utility-vocabulary.mjs scripts/test-theme-contrast.mjs && node scripts/check-contract.mjs",
|
|
451
451
|
"lint": "node scripts/generate-utilities.mjs && oxlint src/components src/lib src/preview docs/consumer-skill/examples --deny-warnings",
|
|
452
452
|
"check:design-lint": "node scripts/generate-utilities.mjs && node scripts/check-design-lint.mjs",
|
|
453
453
|
"check:preview": "node scripts/check-preview.mjs",
|
|
@@ -516,6 +516,8 @@
|
|
|
516
516
|
"@mdx-js/rollup": "^3.1.1",
|
|
517
517
|
"@playwright/test": "^1.63.0",
|
|
518
518
|
"@shadcn/lint": "0.2.0",
|
|
519
|
+
"@tailwindcss/node": "^4.3.3",
|
|
520
|
+
"@tailwindcss/oxide": "^4.3.3",
|
|
519
521
|
"@tailwindcss/vite": "^4.3.3",
|
|
520
522
|
"@tanstack/react-table": "^8.21.3",
|
|
521
523
|
"@testing-library/jest-dom": "^6.0.0",
|
|
@@ -540,7 +542,9 @@
|
|
|
540
542
|
"leaflet-draw": "^1.0.4",
|
|
541
543
|
"leaflet.fullscreen": "^5.3.1",
|
|
542
544
|
"leaflet.markercluster": "^1.5.3",
|
|
545
|
+
"lightningcss": "^1.33.0",
|
|
543
546
|
"lucide-react": "^1.14.0",
|
|
547
|
+
"magic-string": "^0.30.21",
|
|
544
548
|
"oxlint": "1.87.0",
|
|
545
549
|
"qrcode": "^1.5.4",
|
|
546
550
|
"react": "^19.2.5",
|
|
@@ -556,8 +560,7 @@
|
|
|
556
560
|
"tw-animate-css": "^1.4.0",
|
|
557
561
|
"typescript": "^5.9.3",
|
|
558
562
|
"vite": "^8.0.0",
|
|
559
|
-
"vitest": "^5.0.3"
|
|
560
|
-
"magic-string": "^0.30.21"
|
|
563
|
+
"vitest": "^5.0.3"
|
|
561
564
|
},
|
|
562
565
|
"engines": {
|
|
563
566
|
"node": ">=22.12.0"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"accordion-B-5Focs8.js","names":["Accordion","AccordionPrimitive","AccordionItem","AccordionTrigger","AccordionContent","Accordion","React","PrimitiveAccordion","PrimitiveAccordionItem","PrimitiveAccordionTrigger","PrimitiveAccordionContent","Accordion","Text","motionRecipes","Stack","DisclosurePanelElement","IconBadge","React$1","Accordion$2","props","Accordion","cn","className","AccordionItem$1","AccordionTrigger$1","children","ChevronDownIcon","AccordionContent$1","panelProps","Accordion$1","AccordionItem","AccordionTrigger","isSimpleText","AccordionContent","ACCORDION_ROOT_VARIANT_CLASS","ACCORDION_ITEM_VARIANT_CLASS","ACCORDION_TRIGGER_BASE","ACCORDION_CONTENT_PADDING","defaultSmartAccordionStrings","SmartAccordion","forwardRef","stringsProp","strings","useStrings","hasIconColumn","iconStyle","items","item","contentPadding","triggerGridClass","onValueChange","next","variant","itemClassName","triggerClassName","SmartAccordionIcon","isSimpleContent","contentClassName","content","reserveSpace","icon"],"sources":["../src/components/ui/accordion.tsx","../src/components/base/accordion/accordion.tsx","../src/components/base/accordion/accordion-variants.ts","../src/components/base/accordion/accordion.strings.ts","../src/components/base/accordion/smart-accordion.tsx"],"sourcesContent":["import { DisclosurePanelElement } from './disclosure-panel';\nimport { motionRecipes } from '../../lib/motion-recipes';\nimport { Accordion as AccordionPrimitive } from \"@base-ui/react/accordion\"\n\nimport { cn } from \"../../lib/utils\"\nimport { ChevronDownIcon } from \"lucide-react\"\n\nfunction Accordion({ className, ...props }: AccordionPrimitive.Root.Props) {\n return (\n <AccordionPrimitive.Root\n data-slot=\"accordion\"\n className={cn(\"border-border accordion--component flex w-full flex-col border box-border overflow-hidden\", className)}\n {...props}\n />\n )\n}\n\nfunction AccordionItem({ className, ...props }: AccordionPrimitive.Item.Props) {\n return (\n <AccordionPrimitive.Item\n data-slot=\"accordion-item\"\n className={cn(\"border-border accordion-item--component border-b last:border-b-0\", className)}\n {...props}\n />\n )\n}\n\nfunction AccordionTrigger({\n className,\n children,\n ...props\n}: AccordionPrimitive.Trigger.Props) {\n return (\n <AccordionPrimitive.Header className=\"accordion-header m-0\">\n <AccordionPrimitive.Trigger\n data-slot=\"accordion-trigger\"\n className={cn(\"accordion-trigger--component flex w-full items-center justify-between border-0 bg-transparent outline-none cursor-pointer box-border\", className)}\n {...props}\n >\n {children}\n <ChevronDownIcon data-slot=\"accordion-trigger-icon\" className={cn(\"accordion-trigger--icon size-icon text-muted-foreground shrink-0 [[aria-expanded=true]_&]:rotate-180\", motionRecipes.chevron)} />\n </AccordionPrimitive.Trigger>\n </AccordionPrimitive.Header>\n )\n}\n\nfunction AccordionContent({\n className,\n children,\n render,\n ...props\n}: AccordionPrimitive.Panel.Props) {\n return (\n <AccordionPrimitive.Panel\n data-slot=\"accordion-content\"\n className={cn(\"accordion-content--component box-border text-foreground h-(--accordion-panel-height)\", motionRecipes.disclosure, className)}\n {...props}\n render={(panelProps, state) => <DisclosurePanelElement props={panelProps} state={state} render={render} heightVariable=\"--accordion-panel-height\" />}\n >\n {children}\n </AccordionPrimitive.Panel>\n )\n}\n\nexport { Accordion, AccordionItem, AccordionTrigger, AccordionContent }\n\n","/**\n * Accordion — tokenized base wrapper around the shadcn/Base UI primitive.\n *\n * The internal primitive intentionally keeps shadcn's roomy defaults. This\n * public layer calibrates them for admin surfaces: radius tokens, 12px row\n * insets, density-aware vertical rhythm, quiet hover/focus treatments, and\n * matching trigger/content columns. Consumers retain the complete compound\n * API and can override any treatment with `className`.\n */\nimport * as React from 'react';\n\nimport {\n\tAccordion as PrimitiveAccordion,\n\tAccordionContent as PrimitiveAccordionContent,\n\tAccordionItem as PrimitiveAccordionItem,\n\tAccordionTrigger as PrimitiveAccordionTrigger,\n} from '../../ui/accordion';\nimport { Text } from '../../typography';\nimport { cn } from '../../../lib/utils';\n\nexport type AccordionProps = React.ComponentPropsWithoutRef<typeof PrimitiveAccordion>;\nexport type AccordionItemProps = React.ComponentPropsWithoutRef<typeof PrimitiveAccordionItem>;\nexport type AccordionTriggerProps = React.ComponentPropsWithoutRef<typeof PrimitiveAccordionTrigger>;\nexport type AccordionContentProps = React.ComponentPropsWithoutRef<typeof PrimitiveAccordionContent>;\n\nconst Accordion = React.forwardRef<React.ElementRef<typeof PrimitiveAccordion>, AccordionProps>(\n\tfunction Accordion({ className, ...props }, ref) {\n\t\treturn (\n\t\t\t<PrimitiveAccordion\n\t\t\t\tref={ref}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'accordion--component rounded-radius-lg border-border bg-card',\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t);\n\t},\n);\nAccordion.displayName = 'Accordion';\n\nconst AccordionItem = React.forwardRef<React.ElementRef<typeof PrimitiveAccordionItem>, AccordionItemProps>(\n\tfunction AccordionItem({ className, ...props }, ref) {\n\t\treturn (\n\t\t\t<PrimitiveAccordionItem\n\t\t\t\tref={ref}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'accordion-item--component border-border data-open:bg-muted/30',\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t);\n\t},\n);\nAccordionItem.displayName = 'AccordionItem';\n\nconst AccordionTrigger = React.forwardRef<React.ElementRef<typeof PrimitiveAccordionTrigger>, AccordionTriggerProps>(\n\tfunction AccordionTrigger({ className, children, ...props }, ref) {\n\t\tconst isSimpleText = typeof children === 'string' || typeof children === 'number' || typeof children === 'bigint';\n\t\treturn (\n\t\t\t<PrimitiveAccordionTrigger\n\t\t\t\tref={ref}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'accordion-trigger--component min-h-action items-center gap-space-lg px-row-x py-row-y',\n\t\t\t\t\t'text-left text-sm font-medium transition-colors hover:bg-muted/40 hover:no-underline',\n\t\t\t\t\t'focus-visible:z-10 focus-visible:ring-2 focus-visible:ring-ring/50',\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{isSimpleText ? (\n\t\t\t\t\t<Text tag=\"span\" size=\"inherit\" weight=\"medium\" lineHeight=\"tight\" className=\"text-inherit\">\n\t\t\t\t\t\t{children}\n\t\t\t\t\t</Text>\n\t\t\t\t) : children}\n\t\t\t</PrimitiveAccordionTrigger>\n\t\t);\n\t},\n);\nAccordionTrigger.displayName = 'AccordionTrigger';\n\nconst AccordionContent = React.forwardRef<React.ElementRef<typeof PrimitiveAccordionContent>, AccordionContentProps>(\n\tfunction AccordionContent({ className, children, ...props }, ref) {\n\t\tconst isSimpleText = typeof children === 'string' || typeof children === 'number' || typeof children === 'bigint';\n\t\treturn (\n\t\t\t<PrimitiveAccordionContent\n\t\t\t\tref={ref}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'accordion-content--component px-row-x pb-space-lg text-sm',\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{isSimpleText ? (\n\t\t\t\t\t<Text tag=\"div\" size=\"inherit\" lineHeight=\"relaxed\" className=\"text-inherit\">\n\t\t\t\t\t\t{children}\n\t\t\t\t\t</Text>\n\t\t\t\t) : children}\n\t\t\t</PrimitiveAccordionContent>\n\t\t);\n\t},\n);\nAccordionContent.displayName = 'AccordionContent';\n\nexport {\n\tAccordion,\n\tAccordionItem,\n\tAccordionTrigger,\n\tAccordionContent,\n};\n","/**\n * Shared accordion-shell variant classes — used by both `SmartAccordion`\n * and any blocks surface that builds on `base/accordion` directly\n * (e.g. `blocks/onboarding/checklist`).\n *\n * Exported because two consumers already keep it in lockstep; a third\n * one will copy this exact map. Centralising means a future tweak\n * (e.g. tighten `card` items to `border-border/70`) propagates.\n *\n * Padding tokens for trigger / content live alongside so the rhythm\n * is shared too:\n *\n * - Trigger: `gap-space-lg px-row-x py-row-y` — density-driven,\n * `<UIProvider>`\n * override flows through.\n * - Content padding accounts for the base panel's `px-row-x`.\n * Medallion and inline rows use shared media/spacing tokens, and\n * no-icon rows add no extra left padding so body copy tracks the\n * trigger text column instead of drifting.\n */\nimport type { DisclosureSurface } from '../../../lib/component-vocabulary';\n\nexport type AccordionShellVariant = DisclosureSurface;\n\nexport const ACCORDION_ROOT_VARIANT_CLASS: Record<AccordionShellVariant, string> = {\n\tcard: 'gap-space-md border-0 rounded-none bg-transparent overflow-visible',\n\tbordered: 'rounded-radius-lg border border-border bg-card overflow-hidden',\n\tflat: 'border-0 rounded-none bg-transparent overflow-visible',\n};\n\nexport const ACCORDION_ITEM_VARIANT_CLASS: Record<AccordionShellVariant, string> = {\n\tcard: 'border border-border bg-card rounded-radius data-open:bg-muted/25',\n\tbordered: 'bg-transparent not-last:border-b border-border data-open:bg-muted/30',\n\tflat: 'border-0 not-last:border-b-0 bg-transparent data-open:bg-muted/30 rounded-radius',\n};\n\nexport const ACCORDION_TRIGGER_BASE =\n\t'items-center gap-space-lg px-row-x py-row-y text-left hover:no-underline';\n\n/**\n * Content-padding presets keyed off the leading-icon width. Use\n * `withMedallion` when the trigger renders a default `IconBadge`\n * plus the shared row gap so body text aligns under the title at every\n * consumer density.\n */\nexport const ACCORDION_CONTENT_PADDING = {\n\twithMedallion: 'pl-[calc(var(--spacing-row-x)+var(--spacing-avatar)+var(--spacing-space-lg))] pr-row-x pt-0',\n\twithInline: 'pl-[calc(var(--spacing-row-x)+var(--spacing-icon-lg)+var(--spacing-space-lg))] pr-row-x pt-0',\n\twithoutIcon: 'px-row-x pt-0',\n} as const;\n","/**\n * Strings for `SmartAccordion`. There aren't many — Radix handles the\n * trigger ARIA states automatically, so the only library-owned copy is\n * the optional landmark label on the wrapping nav region. Consumers\n * override per-item `title` / `badge` / `content` directly via\n * `SmartAccordionItem` props (the strings live in the data, not here).\n */\nexport interface SmartAccordionStrings {\n\t/**\n\t * Sets `aria-label` on the wrapping element so screen readers can name\n\t * the accordion region. Optional — when absent, no aria-label is set.\n\t */\n\tregionAriaLabel?: string;\n}\n\nexport const defaultSmartAccordionStrings: SmartAccordionStrings = {\n\tregionAriaLabel: undefined,\n};\n","/**\n * SmartAccordion — the canonical \"icon + title + optional badge + body\"\n * accordion pattern, with three visual variants for the surface chrome\n * (`card` | `bordered` | `flat`) and three icon framings (`medallion` |\n * `inline` | `none`).\n *\n * Composes the wrapped `base/accordion` parts (rule 2 — blocks-style\n * convenience built from re-exports, not the raw shadcn primitive).\n *\n * For richer rows (multi-line metadata, custom layouts), drop down to\n * the compound API:\n *\n * import { Accordion, AccordionItem, AccordionTrigger, AccordionContent }\n * from '.';\n */\nimport { forwardRef, type ReactNode } from 'react';\n\nimport { IconBadge } from '../display/icon-badge';\nimport { Stack } from '../structure';\nimport { Text } from '../../typography';\nimport { useStrings } from '../../../lib/strings';\nimport { cn } from '../../../lib/utils';\n\nimport { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from './accordion';\nimport {\n\tACCORDION_CONTENT_PADDING,\n\tACCORDION_ITEM_VARIANT_CLASS,\n\tACCORDION_ROOT_VARIANT_CLASS,\n\tACCORDION_TRIGGER_BASE,\n} from './accordion-variants';\nimport { defaultSmartAccordionStrings } from './accordion.strings';\nimport type {\n\tSmartAccordionIconStyle,\n\tSmartAccordionProps,\n} from './accordion.types';\n\n/**\n * Bounded accordion composition for repeated icon, title, description, badge,\n * and body sections. Use the compound Accordion parts when row structure or\n * per-item presentation differs.\n */\nexport const SmartAccordion = forwardRef<HTMLDivElement, SmartAccordionProps>(function SmartAccordion({\n\titems,\n\tmultiple = false,\n\tdefaultValue,\n\tvalue,\n\tonValueChange,\n\tvariant = 'bordered',\n\ticonStyle = 'inline',\n\tclassName,\n\titemClassName,\n\ttriggerClassName,\n\tcontentClassName,\n\tstrings: stringsProp,\n}, ref) {\n\tconst strings = useStrings(defaultSmartAccordionStrings, stringsProp);\n\tconst hasIconColumn = iconStyle !== 'none' && items.some((item) => item.icon != null);\n\tconst contentPadding =\n\t\t!hasIconColumn\n\t\t\t? ACCORDION_CONTENT_PADDING.withoutIcon\n\t\t\t: iconStyle === 'medallion'\n\t\t\t? ACCORDION_CONTENT_PADDING.withMedallion\n\t\t\t: ACCORDION_CONTENT_PADDING.withInline;\n\tconst triggerGridClass = !hasIconColumn\n\t\t? 'grid-cols-[minmax(0,1fr)]'\n\t\t: 'grid-cols-[auto_minmax(0,1fr)]';\n\treturn (\n\t\t<Accordion\n\t\t\tref={ref}\n\t\t\tmultiple={multiple}\n\t\t\tdefaultValue={defaultValue}\n\t\t\tvalue={value}\n\t\t\tonValueChange={\n\t\t\t\tonValueChange\n\t\t\t\t\t? (next) => onValueChange(next as string[])\n\t\t\t\t\t: undefined\n\t\t\t}\n\t\t\taria-label={strings.regionAriaLabel}\n\t\t\tdata-variant={variant}\n\t\t\tdata-icon-style={iconStyle}\n\t\t\tclassName={cn('smart-accordion--component', ACCORDION_ROOT_VARIANT_CLASS[variant], className)}\n\t\t>\n\t\t\t{items.map((item) => (\n\t\t\t\t<AccordionItem\n\t\t\t\t\tkey={item.value}\n\t\t\t\t\tvalue={item.value}\n\t\t\t\t\tclassName={cn('smart-accordion--item', ACCORDION_ITEM_VARIANT_CLASS[variant], itemClassName)}\n\t\t\t\t>\n\t\t\t\t\t<AccordionTrigger\n\t\t\t\t\t\tclassName={cn('smart-accordion--trigger', ACCORDION_TRIGGER_BASE, triggerClassName)}\n\t\t\t\t\t\tdisabled={item.disabled}\n\t\t\t\t\t>\n\t\t\t\t\t\t<div className={cn('grid min-w-0 flex-1 items-center gap-x-space-lg', triggerGridClass)}>\n\t\t\t\t\t\t\t<SmartAccordionIcon\n\t\t\t\t\t\t\t\ticonStyle={iconStyle}\n\t\t\t\t\t\t\t\ticon={item.icon}\n\t\t\t\t\t\t\t\treserveSpace={hasIconColumn}\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t<Stack render={<span />} gap=\"dense\" className=\"smart-accordion--heading flex-1\">\n\t\t\t\t\t\t\t\t<span className=\"flex min-w-0 flex-wrap items-center gap-x-space-md gap-y-space-xs\">\n\t\t\t\t\t\t\t\t\t{isSimpleContent(item.title) ? (\n\t\t\t\t\t\t\t\t\t\t<Text tag=\"span\" weight=\"semibold\" className=\"smart-accordion--title min-w-0\">\n\t\t\t\t\t\t\t\t\t\t\t{item.title}\n\t\t\t\t\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t\t\t\t) : item.title}\n\t\t\t\t\t\t\t\t\t{item.badge != null && (\n\t\t\t\t\t\t\t\t\t\t<span className=\"smart-accordion--badge inline-flex shrink-0\">{item.badge}</span>\n\t\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t{!!item.description && (\n\t\t\t\t\t\t\t\t\tisSimpleContent(item.description) ? (\n\t\t\t\t\t\t\t\t\t\t<Text tag=\"span\" type=\"secondary\" className=\"smart-accordion--description min-w-0\">\n\t\t\t\t\t\t\t\t\t\t\t{item.description}\n\t\t\t\t\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t\t\t\t) : item.description\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t\t</Stack>\n\t\t\t\t\t\t</div>\n\t\t\t\t\t</AccordionTrigger>\n\t\t\t\t\t<AccordionContent\n\t\t\t\t\t\tclassName={cn(\n\t\t\t\t\t\t\t'smart-accordion--content',\n\t\t\t\t\t\t\tcontentPadding,\n\t\t\t\t\t\t\tcontentClassName,\n\t\t\t\t\t\t)}\n\t\t\t\t\t>\n\t\t\t\t\t\t{isSimpleContent(item.content) ? (\n\t\t\t\t\t\t\t<Text tag=\"div\" type=\"secondary\" lineHeight=\"relaxed\">\n\t\t\t\t\t\t\t\t{item.content}\n\t\t\t\t\t\t\t</Text>\n\t\t\t\t\t\t) : item.content}\n\t\t\t\t\t</AccordionContent>\n\t\t\t\t</AccordionItem>\n\t\t\t))}\n\t\t</Accordion>\n\t);\n});\n\nSmartAccordion.displayName = 'SmartAccordion';\n\nfunction isSimpleContent(content: ReactNode): content is string | number | bigint {\n\treturn typeof content === 'string' || typeof content === 'number' || typeof content === 'bigint';\n}\n\nfunction SmartAccordionIcon({\n\ticonStyle,\n\ticon,\n\treserveSpace,\n}: {\n\ticonStyle: SmartAccordionIconStyle;\n\ticon?: ReactNode;\n\treserveSpace: boolean;\n}) {\n\tif (iconStyle === 'none' || !reserveSpace) return null;\n\tif (!icon) {\n\t\treturn (\n\t\t\t<span\n\t\t\t\taria-hidden=\"true\"\n\t\t\t\tclassName={cn(\n\t\t\t\t\t'smart-accordion--icon inline-flex shrink-0',\n\t\t\t\t\ticonStyle === 'inline' ? 'size-icon-lg' : 'size-avatar',\n\t\t\t\t)}\n\t\t\t/>\n\t\t);\n\t}\n\tif (iconStyle === 'inline') {\n\t\treturn (\n\t\t\t<span\n\t\t\t\taria-hidden=\"true\"\n\t\t\t\tclassName=\"smart-accordion--icon inline-flex size-icon-lg shrink-0 self-center text-muted-foreground [&>svg]:size-icon\"\n\t\t\t>\n\t\t\t\t{icon}\n\t\t\t</span>\n\t\t);\n\t}\n\treturn (\n\t\t<IconBadge size=\"md\" tone=\"neutral\" shape=\"circle\" aria-hidden=\"true\" className=\"smart-accordion--icon self-center\">\n\t\t\t{icon}\n\t\t</IconBadge>\n\t);\n}\n"],"mappings":"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"}
|