themelia-react-ui 2.0.4 → 2.0.6
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 +211 -0
- package/MIGRATION.md +119 -0
- package/README.md +122 -20
- package/dist/{accordion-96o0pN62.js → accordion-0tQUZ20r.js} +13 -13
- package/dist/accordion-0tQUZ20r.js.map +1 -0
- package/dist/{action-menu-CHgs8vmj.js → action-menu-C0gjzLyE.js} +48 -45
- package/dist/action-menu-C0gjzLyE.js.map +1 -0
- package/dist/{affordance-geometry.generated-B8yGOr8-.js → affordance-geometry.generated-P-aVJisu.js} +36 -36
- package/dist/affordance-geometry.generated-P-aVJisu.js.map +1 -0
- package/dist/{ai-artifact-BZUGwBq6.js → ai-artifact-CGGpQryR.js} +281 -230
- package/dist/ai-artifact-CGGpQryR.js.map +1 -0
- package/dist/app-shell-EHuuRDGy.js +321 -0
- package/dist/app-shell-EHuuRDGy.js.map +1 -0
- package/dist/{attachment-DkoqHPPl.js → attachment-BCpA4e7i.js} +10 -10
- package/dist/{attachment-DkoqHPPl.js.map → attachment-BCpA4e7i.js.map} +1 -1
- package/dist/{auth-D2FVZ1MH.js → auth-B0girIk_.js} +49 -52
- package/dist/auth-B0girIk_.js.map +1 -0
- package/dist/{avatar-DWO_HHhB.js → avatar-B9Jnp-T-.js} +8 -8
- package/dist/avatar-B9Jnp-T-.js.map +1 -0
- package/dist/{badge-DErMA7ul.js → badge-wWauMgAt.js} +5 -5
- package/dist/{badge-DErMA7ul.js.map → badge-wWauMgAt.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/batch-action-bar.js +1 -1
- package/dist/base/buttons.js +1 -1
- package/dist/base/cards.js +2 -2
- package/dist/base/carousel.js +3 -3
- package/dist/base/cascader.js +2 -372
- 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 +2 -2
- package/dist/base/command.js +1 -1
- package/dist/base/copyable.js +1 -1
- package/dist/base/date-pickers.js +2 -2
- package/dist/base/display.js +6 -6
- 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 +10 -10
- package/dist/base/item.js +1 -1
- package/dist/base/media-gallery.js +1 -1
- package/dist/base/metadata-list.js +1 -1
- package/dist/base/navigation.js +7 -7
- 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 +200 -193
- package/dist/base/repeaters.js.map +1 -1
- package/dist/base/sheet.js +1 -1
- package/dist/base/sidebar.js +2 -2
- package/dist/base/signature-pad.js +8 -8
- package/dist/base/signature-pad.js.map +1 -1
- package/dist/base/skeleton.js +1 -1
- package/dist/base/spinner.js +6 -6
- package/dist/base/spinner.js.map +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 +36 -36
- 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/{batch-action-bar-CdfIkCsV.js → batch-action-bar-BoqWIIpV.js} +7 -7
- package/dist/batch-action-bar-BoqWIIpV.js.map +1 -0
- package/dist/blocks/admin.js +21 -21
- package/dist/blocks/admin.js.map +1 -1
- package/dist/blocks/ai.js +267 -247
- package/dist/blocks/ai.js.map +1 -1
- package/dist/blocks/analytics/usage-card.js +1 -1
- package/dist/blocks/analytics.js +537 -543
- package/dist/blocks/analytics.js.map +1 -1
- package/dist/blocks/collaboration.js +1 -1
- package/dist/blocks/commerce/receipt.js +1 -1
- package/dist/blocks/commerce.js +1330 -1250
- package/dist/blocks/commerce.js.map +1 -1
- package/dist/blocks/data-display.js +2 -2
- package/dist/blocks/onboarding.js +6 -6
- package/dist/blocks/onboarding.js.map +1 -1
- package/dist/blocks/planning.js +11 -11
- package/dist/blocks/timelines.js +1 -1
- package/dist/{breadcrumbs-B-WFKecD.js → breadcrumbs-Bp9Ke7kd.js} +7 -7
- package/dist/breadcrumbs-Bp9Ke7kd.js.map +1 -0
- package/dist/{button-DkmK-z8E.js → button-ChBovTx0.js} +3 -3
- package/dist/button-ChBovTx0.js.map +1 -0
- package/dist/{buttons-BbfzgczK.js → buttons-DeW0bQeK.js} +16 -16
- package/dist/buttons-DeW0bQeK.js.map +1 -0
- package/dist/cards-CNXnmvV5.js +69 -0
- package/dist/cards-CNXnmvV5.js.map +1 -0
- package/dist/cascader-CrAl9zD5.js +439 -0
- package/dist/cascader-CrAl9zD5.js.map +1 -0
- package/dist/chart-I7ROnsl8.js +162 -0
- package/dist/chart-I7ROnsl8.js.map +1 -0
- package/dist/{checkbox-CzYUTPeJ.js → checkbox-MoyHIAPs.js} +3 -3
- package/dist/{checkbox-CzYUTPeJ.js.map → checkbox-MoyHIAPs.js.map} +1 -1
- package/dist/choice-inputs-DHGtx0QV.js +789 -0
- package/dist/choice-inputs-DHGtx0QV.js.map +1 -0
- package/dist/{code-block-CGNaUtAE.js → code-block-BSJyq9e-.js} +9 -9
- package/dist/code-block-BSJyq9e-.js.map +1 -0
- package/dist/{collapsible-Do4G0zcC.js → collapsible-BzJ91LUG.js} +5 -5
- package/dist/{collapsible-Do4G0zcC.js.map → collapsible-BzJ91LUG.js.map} +1 -1
- package/dist/{collection-content-C0e8SsTm.js → collection-content-CSnwtOTH.js} +3 -3
- package/dist/{collection-content-C0e8SsTm.js.map → collection-content-CSnwtOTH.js.map} +1 -1
- package/dist/combobox-Bcvu5J8O.js +363 -0
- package/dist/combobox-Bcvu5J8O.js.map +1 -0
- package/dist/combobox-C2JiSQPc.js +915 -0
- package/dist/combobox-C2JiSQPc.js.map +1 -0
- package/dist/{command-D8NrBj-b.js → command-9e52NPgK.js} +11 -11
- package/dist/command-9e52NPgK.js.map +1 -0
- package/dist/{comments-Di4w0H_S.js → comments-BsgErEqd.js} +44 -39
- package/dist/comments-BsgErEqd.js.map +1 -0
- package/dist/components/base/action-menu/action-menu.d.ts +7 -1
- package/dist/components/base/buttons/button-group.recipes.d.ts +2 -2
- package/dist/components/base/cards/card.recipes.d.ts +6 -4
- package/dist/components/base/cards/partials/card-primitives.d.ts +9 -2
- package/dist/components/base/cards/partials/smart-card-header-row.d.ts +3 -1
- package/dist/components/base/cards/smart-card.types.d.ts +3 -4
- package/dist/components/base/cascader/cascader-panel.d.ts +76 -0
- package/dist/components/base/chart/chart.d.ts +6 -1
- package/dist/components/base/choice-inputs/choice-types.d.ts +5 -1
- package/dist/components/base/choice-inputs/pill-radio-group.d.ts +7 -6
- package/dist/components/base/combobox/combobox-field.d.ts +2 -2
- package/dist/components/base/combobox/index.d.ts +4 -2
- package/dist/components/base/date-pickers/date-picker-internals.d.ts +3 -1
- package/dist/components/base/date-pickers/datepicker.types.d.ts +10 -4
- package/dist/components/base/date-pickers/time-picker.d.ts +17 -3
- package/dist/components/base/feedback/alert.d.ts +1 -1
- package/dist/components/base/feedback/state-display.d.ts +5 -1
- package/dist/components/base/feedback/state-display.strings.d.ts +9 -0
- package/dist/components/base/forms/form-field.d.ts +7 -2
- package/dist/components/base/forms/form-sizing.d.ts +7 -7
- package/dist/components/base/forms/workflow.d.ts +7 -1
- package/dist/components/base/forms-numeric/coordinates-input.d.ts +8 -1
- package/dist/components/base/forms-numeric/decimal-input.d.ts +2 -2
- package/dist/components/base/forms-numeric/dimensions-input.d.ts +4 -1
- package/dist/components/base/forms-numeric/numeric-composite-field.d.ts +12 -0
- package/dist/components/base/forms-numeric/weight-input.d.ts +6 -1
- package/dist/components/base/metadata-list/metadata-list.d.ts +1 -1
- package/dist/components/base/navigation/dropdown-menu.d.ts +1 -1
- package/dist/components/base/navigation/language-switcher.d.ts +12 -4
- package/dist/components/base/navigation/page-header/page-header-commands.d.ts +14 -7
- package/dist/components/base/navigation/page-header/page-header.d.ts +10 -3
- package/dist/components/base/popover/popover.d.ts +3 -3
- package/dist/components/base/popover/popover.recipes.d.ts +10 -6
- package/dist/components/base/repeaters/key-value-editor.d.ts +2 -1
- package/dist/components/base/sheet/sheet.d.ts +2 -0
- package/dist/components/base/sidebar/index.d.ts +1 -1
- package/dist/components/base/sidebar/sidebar.d.ts +29 -5
- package/dist/components/base/toaster/index.d.ts +1 -0
- package/dist/components/base/upload/avatar-upload.d.ts +2 -1
- package/dist/components/base/upload/image-upload.d.ts +2 -1
- package/dist/components/blocks/ai/ai-citation/types.d.ts +2 -0
- package/dist/components/blocks/ai/ai-file-tree/types.d.ts +1 -1
- package/dist/components/blocks/ai/ai-reasoning/types.d.ts +2 -0
- package/dist/components/blocks/ai/ai-sources/types.d.ts +2 -0
- package/dist/components/blocks/ai/ai-tool-call/types.d.ts +5 -1
- package/dist/components/blocks/ai/ai.strings.d.ts +2 -0
- package/dist/components/blocks/analytics/metric/metric.d.ts +4 -0
- package/dist/components/blocks/analytics/metric-comparison/metric-comparison.d.ts +4 -0
- package/dist/components/blocks/analytics/metric-grid/metric-grid.d.ts +4 -5
- package/dist/components/blocks/analytics/types.d.ts +2 -2
- package/dist/components/blocks/analytics/usage-card/usage-card.strings.d.ts +2 -0
- package/dist/components/blocks/commerce/cart-summary/cart-summary.d.ts +1 -1
- package/dist/components/blocks/commerce/cart-summary/types.d.ts +3 -1
- package/dist/components/blocks/commerce/discount-stack/discount-stack.d.ts +1 -1
- package/dist/components/blocks/commerce/discount-stack/types.d.ts +3 -1
- package/dist/components/blocks/commerce/fulfillment-group/fulfillment-group.d.ts +1 -1
- package/dist/components/blocks/commerce/fulfillment-group/types.d.ts +11 -2
- package/dist/components/blocks/commerce/index.d.ts +7 -6
- package/dist/components/blocks/commerce/inventory-section/inventory-section.d.ts +1 -1
- package/dist/components/blocks/commerce/inventory-section/types.d.ts +7 -2
- package/dist/components/blocks/commerce/invoice-header/index.d.ts +2 -1
- package/dist/components/blocks/commerce/invoice-header/invoice-header.d.ts +1 -1
- package/dist/components/blocks/commerce/invoice-header/types.d.ts +20 -6
- package/dist/components/blocks/commerce/invoice-line-items/invoice-line-items.d.ts +1 -1
- package/dist/components/blocks/commerce/invoice-line-items/types.d.ts +24 -7
- package/dist/components/blocks/commerce/invoice-mini/index.d.ts +2 -1
- package/dist/components/blocks/commerce/invoice-mini/types.d.ts +7 -1
- package/dist/components/blocks/commerce/order-customer/order-customer.d.ts +1 -1
- package/dist/components/blocks/commerce/order-customer/types.d.ts +9 -1
- package/dist/components/blocks/commerce/order-status/types.d.ts +4 -0
- package/dist/components/blocks/commerce/refund-status/refund-status.d.ts +1 -1
- package/dist/components/blocks/commerce/refund-status/types.d.ts +3 -1
- package/dist/components/blocks/commerce/shipment-tracking/shipment-tracking.d.ts +1 -1
- package/dist/components/blocks/commerce/shipment-tracking/types.d.ts +3 -1
- package/dist/components/blocks/commerce/tax-breakdown/tax-breakdown.d.ts +1 -1
- package/dist/components/blocks/commerce/tax-breakdown/types.d.ts +3 -1
- package/dist/components/blocks/data-display/empty-state/empty-state.types.d.ts +4 -3
- package/dist/components/features/activities/activities.types.d.ts +26 -13
- package/dist/components/features/activities/hooks/use-activity-resources.d.ts +2 -1
- package/dist/components/features/activities/partials/activity-marker.d.ts +7 -3
- package/dist/components/features/activities/partials/activity-row.d.ts +24 -0
- package/dist/components/features/ai-chat/hooks/use-ai-chat-scroll.d.ts +1 -1
- package/dist/components/features/appointment-calendar/appointment-calendar.d.ts +1 -1
- package/dist/components/features/appointment-calendar/appointment-calendar.types.d.ts +4 -2
- package/dist/components/features/combobox/async-resource-combobox.d.ts +2 -2
- package/dist/components/features/combobox/combobox.d.ts +2 -2
- package/dist/components/features/combobox/hooks/use-combobox-core.d.ts +2 -1
- package/dist/components/features/combobox/hooks/use-combobox-state.d.ts +1 -0
- package/dist/components/features/combobox/hooks/use-load-more.d.ts +1 -0
- package/dist/components/features/combobox/types.d.ts +37 -8
- package/dist/components/features/email-composer/types.d.ts +3 -1
- package/dist/components/features/event-calendar/colors.d.ts +2 -2
- package/dist/components/features/event-calendar/event-calendar.types.d.ts +4 -0
- package/dist/components/features/filters/facets/date-facet.d.ts +4 -2
- package/dist/components/features/filters/facets/range-facet.d.ts +12 -0
- package/dist/components/features/filters/facets/select-facet.d.ts +2 -1
- package/dist/components/features/filters/filters.strings.d.ts +4 -0
- package/dist/components/features/filters/filters.types.d.ts +6 -3
- package/dist/components/features/filters/partials/date-filter-content.d.ts +3 -2
- package/dist/components/features/filters/partials/filter-editor-header.d.ts +16 -0
- package/dist/components/features/filters/partials/filter-popover-content.d.ts +5 -3
- package/dist/components/features/filters/partials/nested-filter-options.d.ts +21 -0
- package/dist/components/features/filters/partials/range-filter-content.d.ts +12 -0
- package/dist/components/features/filters/partials/regular-filter-content.d.ts +2 -1
- package/dist/components/features/filters/utils/filter-utils.d.ts +25 -3
- package/dist/components/features/global-search/global-search.types.d.ts +2 -0
- package/dist/components/features/global-search/partials/global-search-input.d.ts +10 -0
- package/dist/components/features/global-search/partials/global-search-result-row.d.ts +7 -1
- package/dist/components/features/media-library/hooks/use-media-library.d.ts +1 -1
- package/dist/components/features/media-library/media-library.d.ts +1 -1
- package/dist/components/features/media-library/media-library.strings.d.ts +8 -0
- package/dist/components/features/media-library/media-library.types.d.ts +50 -12
- package/dist/components/features/media-library/partials/media-library-partials.d.ts +4 -4
- package/dist/components/features/mentions/hooks/use-mentions.d.ts +16 -1
- package/dist/components/features/mentions/partials/mention-inline-suggestions.d.ts +5 -1
- package/dist/components/features/mentions/utils/split-html-by-mentions.d.ts +1 -7
- package/dist/components/features/overlays/hooks/use-overlay-visibility.d.ts +2 -2
- package/dist/components/features/products/components/product-options-matrix.d.ts +1 -1
- package/dist/components/features/products/components/product-variant-editor.d.ts +1 -1
- package/dist/components/features/products/components/product-variants-manager.d.ts +1 -1
- package/dist/components/features/products/products.strings.d.ts +9 -1
- package/dist/components/features/products/products.types.d.ts +45 -8
- package/dist/components/features/questionnaire/questionnaire.types.d.ts +3 -0
- package/dist/components/features/resource/resource.d.ts +6 -2
- package/dist/components/features/resource/resource.types.d.ts +14 -1
- package/dist/components/features/rich-text-editor/form-rich-text-editor.d.ts +1 -1
- package/dist/components/features/rich-text-editor/partials/caret-helpers.d.ts +1 -1
- package/dist/components/features/rich-text-editor/partials/editor-field-aria.d.ts +14 -0
- package/dist/components/features/rich-text-editor/partials/image-uploads.d.ts +1 -1
- package/dist/components/features/rich-text-editor/partials/rich-text-editor-toolbar.d.ts +3 -1
- package/dist/components/features/rich-text-editor/rich-text-editor.recipes.d.ts +12 -2
- package/dist/components/features/rich-text-editor/rich-text-editor.types.d.ts +17 -3
- package/dist/components/features/schema-form/hooks/use-schema-form.d.ts +5 -1
- package/dist/components/features/schema-form/partials/schema-form-field.d.ts +3 -1
- package/dist/components/features/schema-form/schema-form.utils.d.ts +1 -1
- package/dist/components/features/suggestions/suggestions.types.d.ts +1 -1
- package/dist/components/features/table/data-table.d.ts +1 -1
- package/dist/components/features/table/index.d.ts +1 -0
- package/dist/components/features/table/partials/resource-cell.d.ts +22 -5
- package/dist/components/features/table/table-body.d.ts +1 -1
- package/dist/components/features/table/table-helpers.d.ts +6 -3
- package/dist/components/features/table/table.strings.d.ts +3 -0
- package/dist/components/features/table/table.types.d.ts +18 -2
- package/dist/components/layout/app-shell/app-shell.types.d.ts +35 -6
- package/dist/components/layout/app-shell/index.d.ts +1 -1
- package/dist/components/layout/app-shell/shell-regions.d.ts +27 -0
- package/dist/components/layout/app-shell/sidebar-inset-layout.d.ts +1 -1
- package/dist/components/layout/app-shell/stacked-layout.d.ts +1 -1
- package/dist/components/layout/app-shell/topbar-sidebar-layout.d.ts +1 -1
- package/dist/components/layout/containers/two-column-layout.d.ts +2 -0
- package/dist/components/layout/header/header.recipes.d.ts +6 -0
- package/dist/components/layout/header/header.types.d.ts +9 -8
- package/dist/components/layout/layout.types.d.ts +5 -3
- package/dist/components/layout/navigation/section-nav/section-nav.d.ts +5 -0
- package/dist/components/layout/navigation/side-nav.d.ts +3 -2
- package/dist/components/layout/normalize-layout-path.d.ts +1 -0
- package/dist/components/layout/page/index.d.ts +2 -1
- package/dist/components/layout/page/page.d.ts +1 -0
- package/dist/components/layout/page/page.strings.d.ts +11 -0
- package/dist/components/layout/page/page.types.d.ts +69 -17
- package/dist/components/layout/page/partials/page-header.d.ts +1 -1
- package/dist/components/layout/settings/settings.d.ts +10 -3
- package/dist/components/layout/sidebar/app-sidebar.d.ts +1 -1
- package/dist/components/layout/sidebar/components/sidebar-grouped-navigation.d.ts +1 -1
- package/dist/components/layout/sidebar/components/sidebar-navigation.d.ts +1 -1
- package/dist/components/layout/sidebar/index.d.ts +2 -1
- package/dist/components/layout/sidebar/sidebar-navigation-rail.d.ts +38 -0
- package/dist/components/layout/sidebar/sidebar.context.d.ts +6 -7
- package/dist/components/layout/sidebar/sidebar.types.d.ts +50 -10
- package/dist/components/layout/sidebar/sidebar.utils.d.ts +9 -1
- package/dist/components/layout/workspace/workspace.types.d.ts +8 -1
- package/dist/components/primitives/link.d.ts +3 -2
- package/dist/components/primitives/money.d.ts +1 -1
- package/dist/components/primitives/number.d.ts +1 -1
- package/dist/components/typography/rich-text/rich-text-tree.d.ts +7 -5
- package/dist/components/ui/alert-dialog.d.ts +2 -2
- package/dist/components/ui/combobox.d.ts +1 -1
- package/dist/components/ui/dialog.d.ts +2 -2
- package/dist/components/ui/overlay-layer.d.ts +18 -0
- package/dist/components/ui/sheet.d.ts +5 -1
- package/dist/components/ui/sidebar-state.d.ts +82 -0
- package/dist/components/ui/sidebar.d.ts +5 -17
- package/dist/{containers-CRmHf7GP.js → containers-CSdc32h9.js} +26 -18
- package/dist/containers-CSdc32h9.js.map +1 -0
- package/dist/{control-group-recipes-DBXmfh2E.js → control-group-recipes-fMuFo0H7.js} +6 -6
- package/dist/control-group-recipes-fMuFo0H7.js.map +1 -0
- package/dist/{copyable-CnGCZdX4.js → copyable-3fdHfMR3.js} +7 -7
- package/dist/{copyable-CnGCZdX4.js.map → copyable-3fdHfMR3.js.map} +1 -1
- package/dist/{data-display-D4oujtx0.js → data-display-Cmj-xZYl.js} +271 -279
- package/dist/data-display-Cmj-xZYl.js.map +1 -0
- package/dist/{date-Q7jnXxpk.js → date-Br0FicVv.js} +5 -5
- package/dist/{date-Q7jnXxpk.js.map → date-Br0FicVv.js.map} +1 -1
- package/dist/date-picker-CyQlFYsP.js +1617 -0
- package/dist/date-picker-CyQlFYsP.js.map +1 -0
- package/dist/date-pickers-tj2MXmXd.js +185 -0
- package/dist/date-pickers-tj2MXmXd.js.map +1 -0
- package/dist/{display-BB4BL_-K.js → display-CT_N2a3w.js} +9 -9
- package/dist/{display-BB4BL_-K.js.map → display-CT_N2a3w.js.map} +1 -1
- package/dist/dropdown-menu-C08iIugv.js +194 -0
- package/dist/dropdown-menu-C08iIugv.js.map +1 -0
- package/dist/features/activities.js +388 -326
- package/dist/features/activities.js.map +1 -1
- package/dist/features/ai-chat.js +46 -32
- package/dist/features/ai-chat.js.map +1 -1
- package/dist/features/appointment-calendar.js +130 -130
- package/dist/features/appointment-calendar.js.map +1 -1
- package/dist/features/async-preview.js +11 -10
- 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 +13 -13
- package/dist/features/data-view.js.map +1 -1
- package/dist/features/email-composer.js +243 -239
- package/dist/features/email-composer.js.map +1 -1
- package/dist/features/event-calendar.js +197 -199
- package/dist/features/event-calendar.js.map +1 -1
- package/dist/features/filters.js +2 -2
- package/dist/features/global-search.js +168 -143
- package/dist/features/global-search.js.map +1 -1
- package/dist/features/kanban.js +19 -30
- package/dist/features/kanban.js.map +1 -1
- package/dist/features/map/style.css +15 -0
- package/dist/features/map.js +369 -343
- package/dist/features/map.js.map +1 -1
- package/dist/features/media-library.js +1202 -975
- package/dist/features/media-library.js.map +1 -1
- package/dist/features/mentions.js +2 -2
- package/dist/features/overlays.js +1 -1
- package/dist/features/products.js +1270 -1183
- package/dist/features/products.js.map +1 -1
- package/dist/features/questionnaire.js +160 -153
- package/dist/features/questionnaire.js.map +1 -1
- package/dist/features/resource-assignment.js +8 -8
- package/dist/features/resource.js +119 -113
- package/dist/features/resource.js.map +1 -1
- package/dist/features/rich-text-editor.js +28 -19
- package/dist/features/rich-text-editor.js.map +1 -1
- package/dist/features/schema-form.js +297 -256
- package/dist/features/schema-form.js.map +1 -1
- package/dist/features/suggestions.js +57 -50
- package/dist/features/suggestions.js.map +1 -1
- package/dist/features/sync.js +3 -3
- package/dist/features/table.js +1 -1
- package/dist/features/theme-tweaker.js +470 -470
- package/dist/features/theme-tweaker.js.map +1 -1
- package/dist/feedback-Dzo1xtAU.js +246 -0
- package/dist/feedback-Dzo1xtAU.js.map +1 -0
- package/dist/{field-affordance-recipes-DjwGx8eM.js → field-affordance-recipes-D6H7tVJi.js} +5 -5
- package/dist/field-affordance-recipes-D6H7tVJi.js.map +1 -0
- package/dist/field-control-attributes-B6i335wr.js +18 -0
- package/dist/field-control-attributes-B6i335wr.js.map +1 -0
- package/dist/{field-state-recipes-BVA2CWHo.js → field-state-recipes-7sza8QbC.js} +4 -2
- package/dist/{field-state-recipes-BVA2CWHo.js.map → field-state-recipes-7sza8QbC.js.map} +1 -1
- package/dist/filters-Dl80yYtN.js +2415 -0
- package/dist/filters-Dl80yYtN.js.map +1 -0
- package/dist/form-field-CAPdwdnZ.js +74 -0
- package/dist/form-field-CAPdwdnZ.js.map +1 -0
- package/dist/{form-sizing-NXgjkmBG.js → form-sizing-CgcrUbLU.js} +5 -5
- package/dist/form-sizing-CgcrUbLU.js.map +1 -0
- package/dist/{forms-BV5m5aQF.js → forms-B3W8CH7-.js} +17 -13
- package/dist/forms-B3W8CH7-.js.map +1 -0
- package/dist/forms-numeric-CwjQJe-O.js +991 -0
- package/dist/forms-numeric-CwjQJe-O.js.map +1 -0
- package/dist/{header-BA697l4a.js → header-ZIIsRKxP.js} +145 -141
- package/dist/header-ZIIsRKxP.js.map +1 -0
- package/dist/header.recipes-BigdJjw1.js +6 -0
- package/dist/header.recipes-BigdJjw1.js.map +1 -0
- package/dist/hooks/use-files.d.ts +2 -0
- package/dist/{hooks-BQ-L7Uu2.js → hooks-BitHSh-Y.js} +27 -15
- package/dist/hooks-BitHSh-Y.js.map +1 -0
- package/dist/{icon-badge-COWbCCWu.js → icon-badge-npxF1SLX.js} +4 -4
- package/dist/{icon-badge-COWbCCWu.js.map → icon-badge-npxF1SLX.js.map} +1 -1
- package/dist/index.js +4 -5
- package/dist/{input-Cdw4k0fb.js → input-7KAc7XQL.js} +9 -9
- package/dist/{input-Cdw4k0fb.js.map → input-7KAc7XQL.js.map} +1 -1
- package/dist/input-DIREVYHs.js +21 -0
- package/dist/input-DIREVYHs.js.map +1 -0
- package/dist/{interaction-recipes-XR9ZpVYL.js → interaction-recipes-4wZ2tvfb.js} +2 -2
- package/dist/{interaction-recipes-XR9ZpVYL.js.map → interaction-recipes-4wZ2tvfb.js.map} +1 -1
- package/dist/item-FfWnaYST.js +278 -0
- package/dist/item-FfWnaYST.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 +2 -2
- package/dist/layout/settings.js +1 -1
- package/dist/layout/sidebar.js +3 -3
- package/dist/layout/workspace.js +1 -1
- package/dist/layout.js +12 -12
- package/dist/layout.types-E_GAApzO.js +30 -0
- package/dist/layout.types-E_GAApzO.js.map +1 -0
- package/dist/lib/affordance-geometry.generated.d.ts +35 -35
- package/dist/lib/control-group-recipes.d.ts +5 -5
- package/dist/lib/field-affordance-recipes.d.ts +2 -2
- package/dist/lib/field-control-attributes.d.ts +11 -0
- package/dist/lib/field-state-recipes.d.ts +2 -0
- package/dist/lib/format.d.ts +1 -0
- package/dist/lib/motion-recipes.d.ts +3 -0
- package/dist/lib/navigation-row-recipes.d.ts +7 -7
- package/dist/lib/overlay-anatomy-recipes.d.ts +3 -3
- package/dist/lib/portal-recipes.d.ts +3 -0
- package/dist/lib/surface-recipes.d.ts +1 -1
- package/dist/lib/token-merge.generated.d.ts +18 -15
- package/dist/lib/utils.js +1 -1
- package/dist/map-demo-tile.svg +1 -1
- package/dist/{media-gallery-CSl5W1Fy.js → media-gallery-C81DAnKI.js} +6 -6
- package/dist/{media-gallery-CSl5W1Fy.js.map → media-gallery-C81DAnKI.js.map} +1 -1
- package/dist/{mentions-RKOQaaIB.js → mentions-qOnedSt4.js} +237 -168
- package/dist/mentions-qOnedSt4.js.map +1 -0
- package/dist/message-BJHnn43M.js +135 -0
- package/dist/message-BJHnn43M.js.map +1 -0
- package/dist/{metadata-list-qVV7AVxa.js → metadata-list-XkqZ_UXH.js} +64 -64
- package/dist/metadata-list-XkqZ_UXH.js.map +1 -0
- package/dist/{motion-recipes-ChBg4HBq.js → motion-recipes-DitYv6P2.js} +10 -2
- package/dist/motion-recipes-DitYv6P2.js.map +1 -0
- package/dist/navigation-BgtPJAhi.js +288 -0
- package/dist/navigation-BgtPJAhi.js.map +1 -0
- package/dist/navigation-Bt-v7rWP.js +261 -0
- package/dist/navigation-Bt-v7rWP.js.map +1 -0
- package/dist/{navigation-row-recipes-WZEs-hYo.js → navigation-row-recipes-BGVLvU_O.js} +9 -9
- package/dist/navigation-row-recipes-BGVLvU_O.js.map +1 -0
- package/dist/normalize-layout-path-BmEgg6fu.js +14 -0
- package/dist/normalize-layout-path-BmEgg6fu.js.map +1 -0
- package/dist/{number-E_OiIfJz.js → number-CYqBcrSj.js} +79 -87
- package/dist/number-CYqBcrSj.js.map +1 -0
- package/dist/overflow-tab-bar-BQCA2Zn2.js +172 -0
- package/dist/overflow-tab-bar-BQCA2Zn2.js.map +1 -0
- package/dist/overlays-CC8zI3Du.js +1017 -0
- package/dist/overlays-CC8zI3Du.js.map +1 -0
- package/dist/page-BoQ1VaFJ.js +331 -0
- package/dist/page-BoQ1VaFJ.js.map +1 -0
- package/dist/page-header-commands-DIKspJfx.js +193 -0
- package/dist/page-header-commands-DIKspJfx.js.map +1 -0
- package/dist/{pagination-Ch8X_47u.js → pagination-Br8TdV9A.js} +7 -7
- package/dist/{pagination-Ch8X_47u.js.map → pagination-Br8TdV9A.js.map} +1 -1
- package/dist/popover-k8TdUcAt.js +201 -0
- package/dist/popover-k8TdUcAt.js.map +1 -0
- package/dist/{popover-menu-BYaCdFhf.js → popover-menu-yn-o0kyA.js} +7 -7
- package/dist/{popover-menu-BYaCdFhf.js.map → popover-menu-yn-o0kyA.js.map} +1 -1
- package/dist/{popover.recipes-D3j8R8Yp.js → popover.recipes-DJ0AkUan.js} +19 -12
- package/dist/popover.recipes-DJ0AkUan.js.map +1 -0
- package/dist/portal-recipes-DyUXqUtD.js +9 -0
- package/dist/portal-recipes-DyUXqUtD.js.map +1 -0
- package/dist/{primitives-Du64iDbb.js → primitives-BkkQjYl7.js} +23 -18
- package/dist/primitives-BkkQjYl7.js.map +1 -0
- package/dist/primitives.js +4 -4
- package/dist/{progress-BvF2oCdV.js → progress-DZFXXzPs.js} +9 -9
- package/dist/{progress-BvF2oCdV.js.map → progress-DZFXXzPs.js.map} +1 -1
- package/dist/{receipt-D789Jwyy.js → receipt-C7LhOg7Q.js} +7 -7
- package/dist/receipt-C7LhOg7Q.js.map +1 -0
- package/dist/rich-text-BnTzZjIo.js +45 -0
- package/dist/rich-text-BnTzZjIo.js.map +1 -0
- package/dist/{rich-text-editor-Cm1dpUpQ.js → rich-text-editor-CAurDwT5.js} +501 -424
- package/dist/rich-text-editor-CAurDwT5.js.map +1 -0
- package/dist/rich-text-editor-toolbar-DbXig7Jk.js +99 -0
- package/dist/rich-text-editor-toolbar-DbXig7Jk.js.map +1 -0
- package/dist/rich-text-tree-BqyQ_7-R.js +66 -0
- package/dist/rich-text-tree-BqyQ_7-R.js.map +1 -0
- package/dist/{sanitize-html-DsQmI48u.js → sanitize-html-BWkH4dLM.js} +29 -16
- package/dist/sanitize-html-BWkH4dLM.js.map +1 -0
- package/dist/{scroll-area-La5RXsEk.js → scroll-area-Bj6CRUif.js} +2 -2
- package/dist/{scroll-area-La5RXsEk.js.map → scroll-area-Bj6CRUif.js.map} +1 -1
- package/dist/{separator-DAEV0w65.js → separator-B9ewiCGO.js} +2 -2
- package/dist/{separator-DAEV0w65.js.map → separator-B9ewiCGO.js.map} +1 -1
- package/dist/{separator-GNfPG-90.js → separator-DM6gs2vu.js} +3 -3
- package/dist/{separator-GNfPG-90.js.map → separator-DM6gs2vu.js.map} +1 -1
- package/dist/services/actions.js +1 -1
- package/dist/settings-DZPHgpx4.js +155 -0
- package/dist/settings-DZPHgpx4.js.map +1 -0
- package/dist/sheet-C4DHsgLk.js +250 -0
- package/dist/sheet-C4DHsgLk.js.map +1 -0
- package/dist/sidebar-C8BnDwTH.js +709 -0
- package/dist/sidebar-C8BnDwTH.js.map +1 -0
- package/dist/sidebar-CmD6a-HK.js +1004 -0
- package/dist/sidebar-CmD6a-HK.js.map +1 -0
- package/dist/skeleton-DDgdhmu9.js +265 -0
- package/dist/skeleton-DDgdhmu9.js.map +1 -0
- package/dist/smart-card-B6vLxqa_.js +617 -0
- package/dist/smart-card-B6vLxqa_.js.map +1 -0
- package/dist/{structure-C0V0_Fyf.js → structure-DZJ2wbAU.js} +2 -2
- package/dist/{structure-C0V0_Fyf.js.map → structure-DZJ2wbAU.js.map} +1 -1
- package/dist/style.css +1 -1
- package/dist/{surface-recipes-BKRVW8Os.js → surface-recipes-C8mNycaY.js} +2 -2
- package/dist/{surface-recipes-BKRVW8Os.js.map → surface-recipes-C8mNycaY.js.map} +1 -1
- package/dist/{table-DH7rozUv.js → table-CBonSdTp.js} +573 -519
- package/dist/table-CBonSdTp.js.map +1 -0
- package/dist/{table-CpvnzJn9.js → table-CXSPHH25.js} +75 -71
- package/dist/table-CXSPHH25.js.map +1 -0
- package/dist/tabs-C4Kr_hCr.js +192 -0
- package/dist/tabs-C4Kr_hCr.js.map +1 -0
- package/dist/{text-inputs-DXItiR0O.js → text-inputs-jdkS3ReG.js} +18 -18
- package/dist/text-inputs-jdkS3ReG.js.map +1 -0
- package/dist/theme.css +40 -37
- package/dist/{timelines-DmtztAY_.js → timelines-CoPwdJP0.js} +13 -12
- package/dist/timelines-CoPwdJP0.js.map +1 -0
- package/dist/tooltip-31NwIpTo.js +113 -0
- package/dist/tooltip-31NwIpTo.js.map +1 -0
- package/dist/{tree-CV11PURP.js → tree-CeYVzdFE.js} +9 -9
- package/dist/{tree-CV11PURP.js.map → tree-CeYVzdFE.js.map} +1 -1
- package/dist/typography/rich-text.js +1 -1
- package/dist/{typography-CSyJrh28.js → typography-C7-YMW1S.js} +12 -12
- package/dist/{typography-CSyJrh28.js.map → typography-C7-YMW1S.js.map} +1 -1
- package/dist/typography.js +1 -1
- package/dist/ui-provider-C-74NVLc.js +178 -0
- package/dist/ui-provider-C-74NVLc.js.map +1 -0
- package/dist/ui-provider.js +2 -3
- package/dist/{upload-C9SA0X-8.js → upload-Hdm5gObf.js} +309 -296
- package/dist/upload-Hdm5gObf.js.map +1 -0
- package/dist/{upload-queue-DhQJiSRc.js → upload-queue-D0sYPuqo.js} +16 -14
- package/dist/upload-queue-D0sYPuqo.js.map +1 -0
- package/dist/{usage-card-DVTRDmGz.js → usage-card-9s8hLDfn.js} +24 -17
- package/dist/usage-card-9s8hLDfn.js.map +1 -0
- package/dist/{utils-CF3c95Io.js → utils-DhuoqFy4.js} +255 -165
- package/dist/utils-DhuoqFy4.js.map +1 -0
- package/dist/value-inputs-D3aPgq9H.js +980 -0
- package/dist/value-inputs-D3aPgq9H.js.map +1 -0
- package/dist/{value-typography-ClupF0Gz.js → value-typography-uSzzG9Gf.js} +32 -26
- package/dist/value-typography-uSzzG9Gf.js.map +1 -0
- package/dist/{workspace-9EFVXUyk.js → workspace-CC8Vchiu.js} +51 -50
- package/dist/workspace-CC8Vchiu.js.map +1 -0
- package/docs/consumer-skill/SKILL.md +4 -3
- package/docs/consumer-skill/agents/themelia-ui-designer.md +96 -0
- package/docs/consumer-skill/examples/app-layout.tsx +52 -1
- package/docs/consumer-skill/examples/commerce-lines.tsx +271 -0
- package/docs/consumer-skill/examples/custom-composition.tsx +21 -0
- package/docs/consumer-skill/examples/detail.tsx +5 -4
- package/docs/consumer-skill/examples/edit.tsx +3 -3
- package/docs/consumer-skill/examples/editable-sections.tsx +38 -0
- package/docs/consumer-skill/examples/index-table.tsx +4 -4
- package/docs/consumer-skill/examples/manifest.json +38 -1
- package/docs/consumer-skill/examples/product-media.tsx +41 -0
- package/docs/consumer-skill/examples/product-parts.tsx +81 -0
- package/docs/consumer-skill/examples/rhf-edit-page.tsx +1 -1
- package/docs/consumer-skill/examples/rhf-overlay-form.tsx +24 -11
- package/docs/consumer-skill/examples/token-domain-structure.tsx +68 -0
- package/docs/consumer-skill/references/agents-md.md +21 -19
- package/docs/consumer-skill/references/analytics.md +33 -1
- package/docs/consumer-skill/references/commerce-composition.md +97 -0
- package/docs/consumer-skill/references/component-contracts.json +21249 -14205
- package/docs/consumer-skill/references/composition-mapping.md +17 -3
- package/docs/consumer-skill/references/composition.md +177 -32
- package/docs/consumer-skill/references/critique-rubric.md +98 -0
- package/docs/consumer-skill/references/custom-composition.md +261 -0
- package/docs/consumer-skill/references/data-reading.md +79 -0
- package/docs/consumer-skill/references/design-contract.md +12 -9
- package/docs/consumer-skill/references/discovery.md +27 -3
- package/docs/consumer-skill/references/domain-structures.md +124 -0
- package/docs/consumer-skill/references/installation.md +62 -8
- package/docs/consumer-skill/references/integration.md +59 -1
- package/docs/consumer-skill/references/product-composition.md +94 -0
- package/docs/consumer-skill/references/public-api.json +3044 -445
- package/docs/consumer-skill/references/review.md +87 -10
- package/docs/consumer-skill/references/rhf-workflows.md +79 -0
- package/docs/consumer-skill/references/screen-archetypes.md +19 -7
- package/docs/consumer-skill/references/screen-decisions.md +126 -0
- package/docs/consumer-skill/references/theming.md +24 -20
- package/docs/consumer-skill/references/tokens.json +9 -9
- package/docs/consumer-skill/references/view-craft.md +153 -0
- package/docs/consumer-skill/references/view-spec.md +73 -0
- package/docs/consumer-skill/references/workflows.md +7 -1
- package/docs/consumer-skill/scripts/composition-policy.mjs +176 -26
- package/docs/consumer-skill/scripts/composition-schema.mjs +1 -1
- package/docs/consumer-skill/scripts/composition.mjs +61 -5
- package/docs/consumer-skill/scripts/discovery.mjs +54 -0
- package/docs/consumer-skill/scripts/inspect-component.mjs +1 -1
- package/docs/consumer-skill/scripts/inspection.mjs +73 -18
- package/docs/consumer-skill/scripts/setup-skills.mjs +79 -7
- package/docs/consumer-skill/scripts/surface-policy.mjs +5 -5
- package/docs/consumer-skills/themelia-components/SKILL.md +14 -13
- package/docs/consumer-skills/themelia-composition/SKILL.md +16 -17
- package/docs/consumer-skills/themelia-design/SKILL.md +55 -0
- package/docs/consumer-skills/themelia-foundation/SKILL.md +2 -1
- package/docs/consumer-skills/themelia-tokenization/SKILL.md +24 -17
- package/package.json +4 -2
- package/templates/admin-shell-template.tsx +1 -2
- package/templates/customers-template.tsx +18 -16
- package/dist/accordion-96o0pN62.js.map +0 -1
- package/dist/action-menu-CHgs8vmj.js.map +0 -1
- package/dist/affordance-geometry.generated-B8yGOr8-.js.map +0 -1
- package/dist/ai-artifact-BZUGwBq6.js.map +0 -1
- package/dist/app-shell-D63ATkIK.js +0 -237
- package/dist/app-shell-D63ATkIK.js.map +0 -1
- package/dist/auth-D2FVZ1MH.js.map +0 -1
- package/dist/avatar-DWO_HHhB.js.map +0 -1
- package/dist/base/cascader.js.map +0 -1
- package/dist/batch-action-bar-CdfIkCsV.js.map +0 -1
- package/dist/breadcrumbs-B-WFKecD.js.map +0 -1
- package/dist/button-DkmK-z8E.js.map +0 -1
- package/dist/buttons-BbfzgczK.js.map +0 -1
- package/dist/cards-4JTWqvVe.js +0 -68
- package/dist/cards-4JTWqvVe.js.map +0 -1
- package/dist/chart-C19flDQb.js +0 -155
- package/dist/chart-C19flDQb.js.map +0 -1
- package/dist/choice-inputs-JLtij2y4.js +0 -776
- package/dist/choice-inputs-JLtij2y4.js.map +0 -1
- package/dist/code-block-CGNaUtAE.js.map +0 -1
- package/dist/combobox-CBJDs6w_.js +0 -877
- package/dist/combobox-CBJDs6w_.js.map +0 -1
- package/dist/combobox-hbhSS18O.js +0 -355
- package/dist/combobox-hbhSS18O.js.map +0 -1
- package/dist/command-D8NrBj-b.js.map +0 -1
- package/dist/comments-Di4w0H_S.js.map +0 -1
- package/dist/containers-CRmHf7GP.js.map +0 -1
- package/dist/control-group-recipes-DBXmfh2E.js.map +0 -1
- package/dist/data-display-D4oujtx0.js.map +0 -1
- package/dist/date-picker-zOt1oNss.js +0 -1542
- package/dist/date-picker-zOt1oNss.js.map +0 -1
- package/dist/date-pickers-cj8IXbDC.js +0 -179
- package/dist/date-pickers-cj8IXbDC.js.map +0 -1
- package/dist/dropdown-menu-CjY8Vt7W.js +0 -193
- package/dist/dropdown-menu-CjY8Vt7W.js.map +0 -1
- package/dist/feedback-DZNL5Lg1.js +0 -239
- package/dist/feedback-DZNL5Lg1.js.map +0 -1
- package/dist/field-affordance-recipes-DjwGx8eM.js.map +0 -1
- package/dist/filters-BcT-uoFy.js +0 -2209
- package/dist/filters-BcT-uoFy.js.map +0 -1
- package/dist/form-field-CsgRmdit.js +0 -63
- package/dist/form-field-CsgRmdit.js.map +0 -1
- package/dist/form-sizing-NXgjkmBG.js.map +0 -1
- package/dist/forms-BV5m5aQF.js.map +0 -1
- package/dist/forms-numeric-Cd33AKbD.js +0 -906
- package/dist/forms-numeric-Cd33AKbD.js.map +0 -1
- package/dist/header-BA697l4a.js.map +0 -1
- package/dist/hooks-BQ-L7Uu2.js.map +0 -1
- package/dist/input-DOPL5_QE.js +0 -21
- package/dist/input-DOPL5_QE.js.map +0 -1
- package/dist/item-BvZ2DR_x.js +0 -277
- package/dist/item-BvZ2DR_x.js.map +0 -1
- package/dist/layout.types-Cn7aUzJp.js +0 -20
- package/dist/layout.types-Cn7aUzJp.js.map +0 -1
- package/dist/mentions-RKOQaaIB.js.map +0 -1
- package/dist/message-INU2xsxu.js +0 -128
- package/dist/message-INU2xsxu.js.map +0 -1
- package/dist/metadata-list-qVV7AVxa.js.map +0 -1
- package/dist/motion-recipes-ChBg4HBq.js.map +0 -1
- package/dist/navigation-BQNcg1jT.js +0 -269
- package/dist/navigation-BQNcg1jT.js.map +0 -1
- package/dist/navigation-DLF3E1IC.js +0 -145
- package/dist/navigation-DLF3E1IC.js.map +0 -1
- package/dist/navigation-row-recipes-WZEs-hYo.js.map +0 -1
- package/dist/number-E_OiIfJz.js.map +0 -1
- package/dist/overflow-tab-bar-CrbqMteP.js +0 -284
- package/dist/overflow-tab-bar-CrbqMteP.js.map +0 -1
- package/dist/overlays-BlKynmde.js +0 -1004
- package/dist/overlays-BlKynmde.js.map +0 -1
- package/dist/page-CIwNUtGr.js +0 -227
- package/dist/page-CIwNUtGr.js.map +0 -1
- package/dist/page-header-commands-DFMlNYzN.js +0 -128
- package/dist/page-header-commands-DFMlNYzN.js.map +0 -1
- package/dist/popover-uwzX2vo7.js +0 -198
- package/dist/popover-uwzX2vo7.js.map +0 -1
- package/dist/popover.recipes-D3j8R8Yp.js.map +0 -1
- package/dist/primitives-Du64iDbb.js.map +0 -1
- package/dist/receipt-D789Jwyy.js.map +0 -1
- package/dist/rich-text-CLJEf76s.js +0 -78
- package/dist/rich-text-CLJEf76s.js.map +0 -1
- package/dist/rich-text-editor-Cm1dpUpQ.js.map +0 -1
- package/dist/rich-text-editor-toolbar-L__e4x47.js +0 -94
- package/dist/rich-text-editor-toolbar-L__e4x47.js.map +0 -1
- package/dist/safe-image-src-C6kQSMBZ.js +0 -17
- package/dist/safe-image-src-C6kQSMBZ.js.map +0 -1
- package/dist/sanitize-html-DsQmI48u.js.map +0 -1
- package/dist/settings-BA2iboic.js +0 -174
- package/dist/settings-BA2iboic.js.map +0 -1
- package/dist/sheet-DoAxTb2J.js +0 -213
- package/dist/sheet-DoAxTb2J.js.map +0 -1
- package/dist/sidebar-ByqKR_W5.js +0 -512
- package/dist/sidebar-ByqKR_W5.js.map +0 -1
- package/dist/sidebar-D2iSnGJ7.js +0 -619
- package/dist/sidebar-D2iSnGJ7.js.map +0 -1
- package/dist/skeleton-CUj8O5Bd.js +0 -264
- package/dist/skeleton-CUj8O5Bd.js.map +0 -1
- package/dist/smart-card-CqkzQsK-.js +0 -614
- package/dist/smart-card-CqkzQsK-.js.map +0 -1
- package/dist/table-CpvnzJn9.js.map +0 -1
- package/dist/table-DH7rozUv.js.map +0 -1
- package/dist/tabs-eqVsJZWO.js +0 -191
- package/dist/tabs-eqVsJZWO.js.map +0 -1
- package/dist/text-inputs-DXItiR0O.js.map +0 -1
- package/dist/theme-scope-BJ6eE2xt.js +0 -50
- package/dist/theme-scope-BJ6eE2xt.js.map +0 -1
- package/dist/timelines-DmtztAY_.js.map +0 -1
- package/dist/tooltip-B4hjKtoV.js +0 -111
- package/dist/tooltip-B4hjKtoV.js.map +0 -1
- package/dist/ui-provider-CQCuCBcy.js +0 -136
- package/dist/ui-provider-CQCuCBcy.js.map +0 -1
- package/dist/upload-C9SA0X-8.js.map +0 -1
- package/dist/upload-queue-DhQJiSRc.js.map +0 -1
- package/dist/usage-card-DVTRDmGz.js.map +0 -1
- package/dist/use-mobile-vaLKwgyf.js +0 -15
- package/dist/use-mobile-vaLKwgyf.js.map +0 -1
- package/dist/utils-CF3c95Io.js.map +0 -1
- package/dist/value-inputs-C0o70p-U.js +0 -980
- package/dist/value-inputs-C0o70p-U.js.map +0 -1
- package/dist/value-typography-ClupF0Gz.js.map +0 -1
- package/dist/workspace-9EFVXUyk.js.map +0 -1
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# View craft
|
|
2
|
+
|
|
3
|
+
Themelia already sets type, colour, spacing and surfaces. Craft is what remains:
|
|
4
|
+
deciding what a view shows, how much emphasis each part gets and how the parts
|
|
5
|
+
are arranged, so the user understands the screen at a glance. Each rule below is
|
|
6
|
+
a decision you can explain and check on the rendered result. Most improvements
|
|
7
|
+
remove something.
|
|
8
|
+
|
|
9
|
+
Start from the [data brief](data-reading.md#write-the-data-brief). Owner
|
|
10
|
+
selection, surfaces and inset ownership follow
|
|
11
|
+
[screen decisions](screen-decisions.md); this reference does not restate them.
|
|
12
|
+
|
|
13
|
+
## One focal point
|
|
14
|
+
|
|
15
|
+
Each view, and each region in it, has one thing the eye reaches first: the
|
|
16
|
+
figure that answers the question, the subject's identity and state, or the queue
|
|
17
|
+
of records that need action. Choose it from the brief. When two things compete,
|
|
18
|
+
demote one: a smaller text role, secondary tone, or a supporting region.
|
|
19
|
+
|
|
20
|
+
Check it by looking at a reduced screenshot: the focal point is still the
|
|
21
|
+
strongest mass. It sits in the first viewport at both 390 and 1440 wide.
|
|
22
|
+
|
|
23
|
+
## Spend emphasis on purpose
|
|
24
|
+
|
|
25
|
+
Emphasis works only by contrast, so it is a budget:
|
|
26
|
+
|
|
27
|
+
- **Commands.** One solid primary command per page or surface. Other commands
|
|
28
|
+
are outline or ghost, or sit in the same scope's overflow menu.
|
|
29
|
+
- **Text.** At most three levels in a region: title (`Heading`), body and values
|
|
30
|
+
(`Text`), supporting copy (`Text` secondary, smaller size). A fourth level
|
|
31
|
+
signals a hierarchy problem, not a missing style.
|
|
32
|
+
- **Tone.** `success`, `warning`, `destructive` and `info` mark a status that
|
|
33
|
+
changes what the user does. Kinds, categories and counts stay neutral. When
|
|
34
|
+
everything is coloured, nothing reads as status.
|
|
35
|
+
- **Size.** One hero figure size per region; peer figures share one size.
|
|
36
|
+
|
|
37
|
+
Adding emphasis in one place means removing it from another.
|
|
38
|
+
|
|
39
|
+
## Choose the encoding from the fact
|
|
40
|
+
|
|
41
|
+
| The fact | Encoding | Owner family (confirm with the finder and inspector) |
|
|
42
|
+
| --- | --- | --- |
|
|
43
|
+
| A figure the user must judge | Figure with its baseline delta; a sparkline when the path matters | `Metric`, `MetricTrendChip`, `MetricSparkline`; `MetricComparison` for current versus previous |
|
|
44
|
+
| Several peer figures for one period | One strip, not a grid of identical cards | `MetricBar`; `MetricGrid` with a quiet variant inside one surface |
|
|
45
|
+
| A series whose shape is the message | Chart with one emphasised series and minimal axes | `ChartCard` with Recharts children |
|
|
46
|
+
| Part of a whole, or use against a limit | Bar with the figure as its label | `Progress`, `UsageCard` |
|
|
47
|
+
| Facts about one record | Label and value list; one inline line for two to four short facts | `MetadataList` (inline or stacked), `InlineStat` |
|
|
48
|
+
| A lifecycle with a current stage | Steps with only the current stage emphasised | `StepsHorizontal`, `Timeline` |
|
|
49
|
+
| Events and history | Newest first, grouped by day | `Timeline`, `features/activities` |
|
|
50
|
+
| Many records compared on shared columns | Table whose columns are what users compare or sort | `DataTable`, `DataView` |
|
|
51
|
+
| Records that differ in shape | List rows: identity, one line of context, state, action | `Item`, `ItemGroup` |
|
|
52
|
+
| A money ledger | Right-aligned amounts, one rule above the grand total | `SummaryPanel` with `AmountRow`, `OrderSummary` |
|
|
53
|
+
| Nothing to show yet | What is missing and the next action | `EmptyState` |
|
|
54
|
+
|
|
55
|
+
Read [metrics and statistics](analytics.md) for the exact metric owner. A chart
|
|
56
|
+
must answer a question you can write in one sentence; otherwise show the figure.
|
|
57
|
+
Do not chart three values. Prefer a sparkline in a strip to a large chart that
|
|
58
|
+
repeats what the figures already say.
|
|
59
|
+
|
|
60
|
+
## Spend words carefully
|
|
61
|
+
|
|
62
|
+
- Label a value only when it is ambiguous. A ledger amount needs "Total"; an
|
|
63
|
+
order number in a header does not need "Order number".
|
|
64
|
+
- Do not repeat a column header inside its cells or a section title in each row.
|
|
65
|
+
- State a unit once, in the header or the value.
|
|
66
|
+
- A sentence fragment often reads better than three label and value pairs:
|
|
67
|
+
"2 of 3 shipped · 1 reserved at Plovdiv".
|
|
68
|
+
- Omit zero and not-applicable counters, or collapse them into one "Nothing
|
|
69
|
+
outstanding" line.
|
|
70
|
+
- Do not explain the interface on the page. A description states scope or
|
|
71
|
+
as-of time, not instructions.
|
|
72
|
+
|
|
73
|
+
## Density follows the audience
|
|
74
|
+
|
|
75
|
+
- **Queues** for operators: compact rows, more records per screen, identity,
|
|
76
|
+
state and amount; detail on open.
|
|
77
|
+
- **Overviews**: fewer, larger figures with room around them, each answering a
|
|
78
|
+
question.
|
|
79
|
+
- **Records**: the subject leads; evidence and history follow.
|
|
80
|
+
|
|
81
|
+
Change global density through the provider and density roots described in
|
|
82
|
+
[theming](theming.md). Do not shrink text roles to fit more data; remove
|
|
83
|
+
low-value content first.
|
|
84
|
+
|
|
85
|
+
## Rhythm groups content
|
|
86
|
+
|
|
87
|
+
- Gaps grow outward: within a group, between groups, between sections. Equal
|
|
88
|
+
gaps everywhere mean nothing groups. Use `Stack` and `Grid` gap roles.
|
|
89
|
+
- Few edges: peer regions share content start edges; numbers right-align on one
|
|
90
|
+
axis; labels share one axis.
|
|
91
|
+
- Few frames: one `Card` per independent subject. Continuous sections of one
|
|
92
|
+
subject share one surface and are separated by space, not rules or nested
|
|
93
|
+
boxes.
|
|
94
|
+
- Narrow widths keep the decision content first in reading order. Only data
|
|
95
|
+
tables that own horizontal scrolling may scroll sideways.
|
|
96
|
+
|
|
97
|
+
## Numbers and copy
|
|
98
|
+
|
|
99
|
+
- Numbers use tabular figures through the value primitives (`Money`, `Number`,
|
|
100
|
+
`Percent`, `Date`, `RelativeTime`) with one precision per column.
|
|
101
|
+
- Recency reads as relative time with the exact date available; documents show
|
|
102
|
+
absolute dates.
|
|
103
|
+
- A delta states direction and baseline: "↓ 0.9% vs September".
|
|
104
|
+
- Sentence case everywhere. Buttons are a verb and an object ("Record payment").
|
|
105
|
+
Empty states say what is missing and what to do. Errors say what happened and
|
|
106
|
+
how to recover.
|
|
107
|
+
|
|
108
|
+
## Modern patterns and their owners
|
|
109
|
+
|
|
110
|
+
- **Overview.** A header with the period control, one figure strip (three to
|
|
111
|
+
five figures with deltas or sparklines), one chart answering the main
|
|
112
|
+
question, and a "needs attention" list that links to records. Not a wall of
|
|
113
|
+
identical cards.
|
|
114
|
+
- **Index.** Search plus the work queues users actually work; rows lead with
|
|
115
|
+
identity and the deciding column; bulk actions appear with a selection;
|
|
116
|
+
export states how many rows match.
|
|
117
|
+
- **Record.** The page header carries identity, status badges in `titleSuffix`,
|
|
118
|
+
one metadata line (date · channel · customer) and the primary command. The
|
|
119
|
+
main column holds the subject's working content, an aside holds context
|
|
120
|
+
(customer, payment, notes) and history comes last.
|
|
121
|
+
- **Editing.** `InlineEdit` for one field; `ActionDrawer` for a focused
|
|
122
|
+
multi-field edit that keeps the record visible; `ActionDialog` for short
|
|
123
|
+
creation; `ConfirmDialog` for destructive commands.
|
|
124
|
+
- **Progressive disclosure.** `Collapsible` or `Accordion` for evidence and
|
|
125
|
+
technical detail; overflow menus for rare commands.
|
|
126
|
+
- **Loading.** Owners' loading states and `Skeleton` shaped like the content,
|
|
127
|
+
not spinners in empty boxes.
|
|
128
|
+
|
|
129
|
+
Inspect each owner's declaration before using it; a pattern names a direction,
|
|
130
|
+
not a prop list.
|
|
131
|
+
|
|
132
|
+
## Anti-patterns seen in trials
|
|
133
|
+
|
|
134
|
+
- A grid of identical metric cards whose figures have no baseline.
|
|
135
|
+
- A facts card that repeats the header's identifier, status and date.
|
|
136
|
+
- Every lifecycle counter on every line, zeros included.
|
|
137
|
+
- Column headers repeated in cells; units on every value.
|
|
138
|
+
- Filler cards added to balance a column's whitespace.
|
|
139
|
+
- Decorative icons on titles, rows or badges; tinted icon tiles.
|
|
140
|
+
- Status tones on kinds or categories; three badges on one row saying related
|
|
141
|
+
things.
|
|
142
|
+
- A storefront hero image inside an operational editor.
|
|
143
|
+
- A framed box inside a card for sub-content that is not a distinct object.
|
|
144
|
+
- A chart of three values, or a chart whose question cannot be stated.
|
|
145
|
+
- Prose explaining what the screen does.
|
|
146
|
+
|
|
147
|
+
## When an owner limits the view
|
|
148
|
+
|
|
149
|
+
When an owner cannot express the hierarchy the data needs, compose its public
|
|
150
|
+
parts or app markup with token-backed utilities
|
|
151
|
+
([domain structures](domain-structures.md)) and report the gap by owner and
|
|
152
|
+
prop. Never override anatomy classes, add colours or add tokens to make a view
|
|
153
|
+
look designed.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# View spec
|
|
2
|
+
|
|
3
|
+
Write this before JSX for a new view or a substantial redesign. Keep it short
|
|
4
|
+
enough to read in a minute; it is a working note, not an approval document. Every
|
|
5
|
+
line should change a later decision. Save it beside the app's other design notes
|
|
6
|
+
so a reviewer can compare the result with the intent.
|
|
7
|
+
|
|
8
|
+
```md
|
|
9
|
+
# <View name> (<route>)
|
|
10
|
+
|
|
11
|
+
## Decision
|
|
12
|
+
<who> decides <what>, <how often>. Success: <what they can do faster or with more confidence>.
|
|
13
|
+
|
|
14
|
+
## Data brief
|
|
15
|
+
<the data brief from data-reading.md>
|
|
16
|
+
|
|
17
|
+
## Ranked information
|
|
18
|
+
- Must (first viewport at 390 and 1440): …
|
|
19
|
+
- Should (visible without interaction): …
|
|
20
|
+
- Could (behind disclosure, overflow or a detail view): …
|
|
21
|
+
- Omit: … (why: zero, not applicable, duplicated elsewhere, not used for this decision)
|
|
22
|
+
|
|
23
|
+
## Focal point
|
|
24
|
+
<the one element the eye reaches first, and why>
|
|
25
|
+
|
|
26
|
+
## Wireframes
|
|
27
|
+
1440:
|
|
28
|
+
┌──────────────────────────────────────────────┐
|
|
29
|
+
│ Title · status [secondary] [Primary]│
|
|
30
|
+
│ meta · meta · meta │
|
|
31
|
+
├──────────────────────────────┬───────────────┤
|
|
32
|
+
│ main subject │ context │
|
|
33
|
+
│ … │ … │
|
|
34
|
+
└──────────────────────────────┴───────────────┘
|
|
35
|
+
|
|
36
|
+
390:
|
|
37
|
+
┌────────────────────┐
|
|
38
|
+
│ Title · status │
|
|
39
|
+
│ [Primary] [⋯] │
|
|
40
|
+
│ main subject │
|
|
41
|
+
│ context │
|
|
42
|
+
└────────────────────┘
|
|
43
|
+
|
|
44
|
+
## Encodings
|
|
45
|
+
| Fact | Encoding | Why |
|
|
46
|
+
| --- | --- | --- |
|
|
47
|
+
|
|
48
|
+
## Owners
|
|
49
|
+
| Region | Owner | Exact import | Verified with |
|
|
50
|
+
| --- | --- | --- | --- |
|
|
51
|
+
(found with find-components.mjs and map-composition.mjs; props checked with inspect-component.mjs)
|
|
52
|
+
|
|
53
|
+
## Commands
|
|
54
|
+
<command: scope, emphasis (primary, secondary, overflow), eligibility and disabled reason>
|
|
55
|
+
|
|
56
|
+
## States
|
|
57
|
+
Loading: … Empty: … Error and retry: … Accepted: … Long text and narrow parent: …
|
|
58
|
+
|
|
59
|
+
## Open questions and data gaps
|
|
60
|
+
…
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Notes
|
|
64
|
+
|
|
65
|
+
- Draw wireframes in text so they survive any editor and diff. Boxes show
|
|
66
|
+
regions and order, not pixel sizes.
|
|
67
|
+
- The ranked list is where most quality comes from. If "must" has more than
|
|
68
|
+
five items, the decision is not specific enough yet.
|
|
69
|
+
- Fill "Owners" only after running the finder and inspector. An owner that does
|
|
70
|
+
not fit is recorded with the reason, and the region becomes app markup over
|
|
71
|
+
public parts.
|
|
72
|
+
- After building, score the result with the [critique rubric](critique-rubric.md)
|
|
73
|
+
and note any departure from this spec with its reason.
|
|
@@ -124,7 +124,13 @@ back navigation, content bounds, commands and section tabs. Pass the record's
|
|
|
124
124
|
main command as `header.primaryAction`, supporting commands as
|
|
125
125
|
`header.secondaryActions` and separately selected/routed sections as `header.tabs`;
|
|
126
126
|
continuous sections can stay in the body. One status badge goes in
|
|
127
|
-
`header.
|
|
127
|
+
`header.slots.titleSuffix` as a composed Badge. Place supporting facts in
|
|
128
|
+
`header.slots.afterDescription` as a MetadataList when useful. The four header
|
|
129
|
+
slots (`beforeTitle`, `titleSuffix`, `afterDescription`, `actions`) accept content
|
|
130
|
+
or a callback receiving `{ renderLink, defaultContent }`; an actions callback
|
|
131
|
+
can wrap or return `defaultContent` to retain responsive commands. A replacement
|
|
132
|
+
owns its behavior. Below 40rem of actual header width, all commands, including
|
|
133
|
+
primary, share one More actions trigger. `PageHeader` serves a custom shell; `PageActions` is
|
|
128
134
|
deprecated. The [layout recipe](../examples/app-layout.tsx) demonstrates that
|
|
129
135
|
route boundary; the [detail recipe](../examples/detail.tsx) demonstrates the
|
|
130
136
|
record route and an independently framed subject with MetadataList and value
|
|
@@ -44,6 +44,8 @@ export function analyzeComposition(text, { filename, index, ts }) {
|
|
|
44
44
|
const families = new Map(index.families.map(owner => [owner.import, owner]));
|
|
45
45
|
const bindings = new Map();
|
|
46
46
|
const namespaces = new Map();
|
|
47
|
+
const portalBindings = new Set();
|
|
48
|
+
const portalNamespaces = new Set();
|
|
47
49
|
const declarations = new Map();
|
|
48
50
|
const findings = [];
|
|
49
51
|
const unresolved = [];
|
|
@@ -135,14 +137,23 @@ export function analyzeComposition(text, { filename, index, ts }) {
|
|
|
135
137
|
if (names && ts.isNamespaceImport(names)) namespaces.set(symbolFor(names.name), specifier);
|
|
136
138
|
}
|
|
137
139
|
function gather(node) {
|
|
140
|
+
if (ts.isImportDeclaration(node) && ts.isStringLiteralLike(node.moduleSpecifier) && node.moduleSpecifier.text === 'react-dom') {
|
|
141
|
+
const names = node.importClause?.namedBindings;
|
|
142
|
+
if (names && ts.isNamedImports(names)) for (const item of names.elements) if ((item.propertyName ?? item.name).text === 'createPortal') portalBindings.add(symbolFor(item.name));
|
|
143
|
+
if (names && ts.isNamespaceImport(names)) portalNamespaces.add(symbolFor(names.name));
|
|
144
|
+
if (node.importClause?.name) portalNamespaces.add(symbolFor(node.importClause.name));
|
|
145
|
+
}
|
|
138
146
|
if (ts.isImportDeclaration(node) && ts.isStringLiteralLike(node.moduleSpecifier) && importsModal(node, ts)) add(node, 'raw-overlay-primitive', 'warning', `${node.moduleSpecifier.text} builds a second dialog system. ${overlayRemedy}`);
|
|
139
147
|
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.initializer) declarations.set(symbolFor(node.name), node.initializer);
|
|
148
|
+
if (ts.isFunctionDeclaration(node) && node.name && node.body) declarations.set(symbolFor(node.name), node);
|
|
140
149
|
if ((ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) && node.moduleSpecifier && ts.isStringLiteralLike(node.moduleSpecifier)) importOwner(node, node.moduleSpecifier.text);
|
|
141
150
|
if (ts.isImportTypeNode(node) && ts.isLiteralTypeNode(node.argument) && ts.isStringLiteralLike(node.argument.literal)) importOwner(node, node.argument.literal.text);
|
|
142
151
|
if (ts.isCallExpression(node) && node.expression.kind === ts.SyntaxKind.ImportKeyword && ts.isStringLiteralLike(node.arguments[0])) importOwner(node, node.arguments[0].text);
|
|
143
152
|
ts.forEachChild(node, gather);
|
|
144
153
|
}
|
|
145
154
|
gather(source);
|
|
155
|
+
const portalCall = node => ts.isCallExpression(node) && (ts.isIdentifier(node.expression) && portalBindings.has(symbolFor(node.expression))
|
|
156
|
+
|| ts.isPropertyAccessExpression(node.expression) && node.expression.name.text === 'createPortal' && ts.isIdentifier(node.expression.expression) && portalNamespaces.has(symbolFor(node.expression.expression)));
|
|
146
157
|
for (const diagnostic of source.parseDiagnostics) add(source, 'syntax', 'error', ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'));
|
|
147
158
|
const ownerFor = tag => {
|
|
148
159
|
if (ts.isIdentifier(tag)) return bindings.get(symbolFor(tag));
|
|
@@ -157,16 +168,23 @@ export function analyzeComposition(text, { filename, index, ts }) {
|
|
|
157
168
|
const expression = ts.isJsxExpression(attribute.initializer) ? attribute.initializer.expression : attribute.initializer;
|
|
158
169
|
return [[attribute.name.getText(source), expression]];
|
|
159
170
|
});
|
|
171
|
+
const unknownSpread = (expression, visiting = new Set()) => {
|
|
172
|
+
const value = resolve(expression);
|
|
173
|
+
if (!value || !ts.isObjectLiteralExpression(value) || visiting.has(value)) return true;
|
|
174
|
+
const next = new Set(visiting).add(value);
|
|
175
|
+
return value.properties.some(property => ts.isSpreadAssignment(property) && unknownSpread(property.expression, next));
|
|
176
|
+
};
|
|
160
177
|
const isOwner = (owner, suffix, names) => owner?.import === `${index.package}/${suffix}` && names.includes(owner.symbol);
|
|
161
178
|
const framedOwner = (owner, props) => {
|
|
162
|
-
if (literal(props.get('surface')) === 'flat') return false;
|
|
163
|
-
if (isOwner(owner, 'base/cards', ['Card', 'SmartCard']) || isOwner(owner, 'features/table', ['DataTable']) || isOwner(owner, 'features/data-view', ['DataView'])) return true;
|
|
179
|
+
if (props.has('surface') && (literal(props.get('surface')) === undefined || literal(props.get('surface')) === 'flat')) return false;
|
|
180
|
+
if (isOwner(owner, 'base/cards', ['Card', 'SmartCard']) || isOwner(owner, 'base/forms', ['FormSection']) || isOwner(owner, 'features/table', ['DataTable']) || isOwner(owner, 'features/data-view', ['DataView'])) return true;
|
|
181
|
+
if (isOwner(owner, 'blocks/analytics', ['ChartCard']) || isOwner(owner, 'base/display', ['ContentBlock'])) return props.has('surface');
|
|
164
182
|
if (isOwner(owner, 'blocks/analytics', ['Metric'])) return literal(props.get('variant')) === 'card';
|
|
165
183
|
if (isOwner(owner, 'blocks/analytics', ['MetricGrid'])) return !props.has('variant') || literal(props.get('variant')) === 'card';
|
|
166
184
|
return isOwner(owner, 'blocks/analytics/usage-card', ['UsageCard']) || isOwner(owner, 'blocks/analytics', ['UsageCard']) || isOwner(owner, 'blocks/planning', ['TaskCard']);
|
|
167
185
|
};
|
|
168
186
|
// Examine lexical JSX only. Names ending in Card are not evidence of framing;
|
|
169
|
-
// ChartCard is card-free; Receipt's
|
|
187
|
+
// ChartCard is card-free by default; Receipt's paper has no ordinary Card frame.
|
|
170
188
|
const contentElements = element => {
|
|
171
189
|
const found = [];
|
|
172
190
|
function collect(child) {
|
|
@@ -184,6 +202,25 @@ export function analyzeComposition(text, { filename, index, ts }) {
|
|
|
184
202
|
if (ts.isJsxElement(element.parent)) element.parent.children.forEach(collect);
|
|
185
203
|
return found;
|
|
186
204
|
};
|
|
205
|
+
// Static region children only: inspect known passive wrappers and providers,
|
|
206
|
+
// never assume an opaque app component renders its lexical children.
|
|
207
|
+
const regionElements = (opening, deep = false) => {
|
|
208
|
+
const found = [];
|
|
209
|
+
const collect = (child, scope = opening, subject) => {
|
|
210
|
+
if (ts.isJsxFragment(child)) { child.children.forEach(item => collect(item, scope, subject)); return; }
|
|
211
|
+
if (ts.isJsxExpression(child)) { const value = resolve(child.expression); if (value) collect(value, scope, subject); return; }
|
|
212
|
+
const node = ts.isJsxElement(child) ? child.openingElement : ts.isJsxSelfClosingElement(child) ? child : undefined;
|
|
213
|
+
if (!node) return;
|
|
214
|
+
const owner = ownerFor(node.tagName);
|
|
215
|
+
found.push({node, owner, tag: node.tagName.getText(source), scope, subject});
|
|
216
|
+
const provider = isOwner(owner, 'features/filters', ['FilterProvider']);
|
|
217
|
+
const card = isOwner(owner, 'base/cards', ['Card', 'SmartCard']);
|
|
218
|
+
// Cards delimit independent subjects; providers delimit query state.
|
|
219
|
+
if (deep && ts.isJsxElement(child) && (/^(div|section|form)$/.test(node.tagName.getText(source)) || isOwner(owner, 'base/structure', ['Stack', 'Grid', 'AdaptiveGrid', 'GridCell']) || card || provider)) child.children.forEach(item => collect(item, provider ? node : scope, card ? node : subject));
|
|
220
|
+
};
|
|
221
|
+
if (ts.isJsxElement(opening.parent)) opening.parent.children.forEach(child => collect(child));
|
|
222
|
+
return found;
|
|
223
|
+
};
|
|
187
224
|
const renderedText = element => ts.isJsxElement(element) ? element.children.map(child => ts.isJsxText(child) ? child.text : ts.isJsxExpression(child) ? literal(child.expression) ?? '' : '').join(' ').trim() : '';
|
|
188
225
|
const slotBadge = expression => {
|
|
189
226
|
const node = resolve(expression);
|
|
@@ -241,25 +278,43 @@ export function analyzeComposition(text, { filename, index, ts }) {
|
|
|
241
278
|
};
|
|
242
279
|
// tone="primary" is solid unless a buttonStyle says otherwise; untoned Buttons are neutral.
|
|
243
280
|
const solidPrimary = (opening, owner) => {
|
|
244
|
-
|
|
281
|
+
const submit = isOwner(owner, 'base/forms', ['SubmitStateButton']);
|
|
282
|
+
if (!submit && !isOwner(owner, 'base/buttons', ['Button'])) return false;
|
|
245
283
|
const props = new Map(attributes(opening));
|
|
246
284
|
const style = props.has('buttonStyle') ? literal(props.get('buttonStyle')) : 'solid';
|
|
247
|
-
return literal(props.get('tone')) === 'primary' && style === 'solid';
|
|
285
|
+
return (literal(props.get('tone')) ?? (submit && !props.has('tone') ? 'primary' : undefined)) === 'primary' && style === 'solid';
|
|
286
|
+
};
|
|
287
|
+
const formRoot = opening => {
|
|
288
|
+
if (opening.tagName.getText(source) === 'form') return true;
|
|
289
|
+
const render = resolve(new Map(attributes(opening)).get('render'));
|
|
290
|
+
return render && (ts.isJsxElement(render) ? render.openingElement : ts.isJsxSelfClosingElement(render) ? render : undefined)?.tagName.getText(source) === 'form';
|
|
248
291
|
};
|
|
249
|
-
//
|
|
292
|
+
// A form owns its submit command; overlays and exclusive branches are not
|
|
293
|
+
// simultaneously competing page commands. Follow same-file slot values only.
|
|
250
294
|
const solidPrimaryCount = root => {
|
|
251
|
-
|
|
252
|
-
|
|
295
|
+
const count = (expression, visiting = new Set()) => {
|
|
296
|
+
if (!expression) return 0;
|
|
297
|
+
const child = resolve(expression) ?? expression;
|
|
298
|
+
if (visiting.has(child)) return 0;
|
|
299
|
+
const next = new Set(visiting).add(child);
|
|
300
|
+
if (portalCall(child)) return 0;
|
|
301
|
+
if (ts.isConditionalExpression(child)) return Math.max(count(child.whenTrue, next), count(child.whenFalse, next));
|
|
302
|
+
if (ts.isBinaryExpression(child) && [ts.SyntaxKind.BarBarToken, ts.SyntaxKind.QuestionQuestionToken].includes(child.operatorToken.kind)) return Math.max(count(child.left, next), count(child.right, next));
|
|
253
303
|
if (ts.isJsxElement(child) || ts.isJsxSelfClosingElement(child)) {
|
|
254
304
|
const opening = ts.isJsxElement(child) ? child.openingElement : child;
|
|
255
305
|
const owner = ownerFor(opening.tagName);
|
|
256
|
-
if (isOwner(owner, 'features/overlays', overlayOwners)) return;
|
|
257
|
-
|
|
306
|
+
if (isOwner(owner, 'features/overlays', overlayOwners) || formRoot(opening) || !owner && /^[A-Z]/.test(opening.tagName.getText(source))) return 0;
|
|
307
|
+
const props = new Map(attributes(opening));
|
|
308
|
+
if (resolve(props.get('hidden'))?.kind === ts.SyntaxKind.TrueKeyword || props.has('hidden') && props.get('hidden') === undefined) return 0;
|
|
309
|
+
const children = ts.isJsxElement(child) ? child.children.reduce((total, item) => total + count(item, next), 0) : 0;
|
|
310
|
+
const slots = [...props].filter(([name]) => !['header', 'render'].includes(name)).reduce((total, [, value]) => total + count(value, next), 0);
|
|
311
|
+
return Number(solidPrimary(opening, owner)) + children + slots;
|
|
258
312
|
}
|
|
259
|
-
|
|
313
|
+
let total = 0;
|
|
314
|
+
ts.forEachChild(child, item => { total += count(item, next); });
|
|
315
|
+
return total;
|
|
260
316
|
};
|
|
261
|
-
|
|
262
|
-
return count;
|
|
317
|
+
return count(root);
|
|
263
318
|
};
|
|
264
319
|
const peerCards = element => {
|
|
265
320
|
if (!ts.isJsxElement(element.parent)) return new Set();
|
|
@@ -303,18 +358,78 @@ export function analyzeComposition(text, { filename, index, ts }) {
|
|
|
303
358
|
return smallPeerGaps.has(row ?? gap) || smallPeerGaps.has(column ?? gap);
|
|
304
359
|
});
|
|
305
360
|
};
|
|
306
|
-
|
|
361
|
+
const separateRegion = owner => isOwner(owner, 'features/overlays', overlayOwners)
|
|
362
|
+
|| isOwner(owner, 'base/popover', ['PopoverContent'])
|
|
363
|
+
|| isOwner(owner, 'base/navigation', ['DropdownMenuContent', 'DropdownMenuSubContent', 'ContextMenuContent', 'ContextMenuSubContent'])
|
|
364
|
+
|| isOwner(owner, 'base/combobox', ['ComboboxContent', 'ComboboxPopup'])
|
|
365
|
+
|| isOwner(owner, 'base/choice-inputs', ['SelectPopupContent']);
|
|
366
|
+
function regionParents(element, parents, context, slot) {
|
|
367
|
+
if (slot === 'render') return parents;
|
|
368
|
+
if (separateRegion(context?.owner) || !context && /^[A-Z]/.test(element.tagName.getText(source))) parents = [];
|
|
369
|
+
return context ? [...parents, { ...context, slot }] : parents;
|
|
370
|
+
}
|
|
371
|
+
function visitValue(value, parents, visiting) {
|
|
372
|
+
if (value) visit(resolve(value) ?? value, parents, visiting);
|
|
373
|
+
}
|
|
374
|
+
function visit(node, parents = [], visiting = new Set()) {
|
|
375
|
+
if (visiting.has(node)) return;
|
|
376
|
+
const next = new Set(visiting).add(node);
|
|
307
377
|
if (ts.isJsxElement(node)) {
|
|
308
378
|
const element = node.openingElement;
|
|
309
379
|
const context = inspect(element, parents);
|
|
310
|
-
for (const child of node.children) visit(child,
|
|
311
|
-
|
|
312
|
-
|
|
380
|
+
for (const child of node.children) visit(child, regionParents(element, parents, context, 'children'), next);
|
|
381
|
+
for (const [slot, value] of attributes(element)) visitValue(value, regionParents(element, parents, context, slot), next);
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
if (ts.isJsxSelfClosingElement(node)) {
|
|
385
|
+
const context = inspect(node, parents);
|
|
386
|
+
for (const [slot, value] of attributes(node)) visitValue(value, regionParents(node, parents, context, slot), next);
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
if (ts.isJsxExpression(node)) { visitValue(node.expression, parents, next); return; }
|
|
390
|
+
if (ts.isPropertyAssignment(node) || ts.isShorthandPropertyAssignment(node) || ts.isMethodDeclaration(node)) {
|
|
391
|
+
const member = ts.isIdentifier(node.name) || ts.isStringLiteralLike(node.name) ? node.name.text : undefined;
|
|
392
|
+
// columns contains header/footer renderers as well as cells. Only a cell
|
|
393
|
+
// owns the table-row height addressed by heavy-cell-disclosure.
|
|
394
|
+
const nextParents = parents.map(parent => parent.slot === 'columns' && ['cell', 'header', 'footer'].includes(member) ? {...parent, member} : parent);
|
|
395
|
+
if (ts.isMethodDeclaration(node)) { if (node.body) visit(node.body, nextParents, next); }
|
|
396
|
+
else visitValue(ts.isShorthandPropertyAssignment(node) ? node.name : node.initializer, nextParents, next);
|
|
313
397
|
return;
|
|
314
398
|
}
|
|
315
|
-
if (
|
|
316
|
-
|
|
399
|
+
if (portalCall(node)) {
|
|
400
|
+
for (const [index, value] of node.arguments.entries()) visitValue(value, index === 0 ? [] : parents, next);
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
ts.forEachChild(node, child => visit(child, parents, next));
|
|
317
404
|
}
|
|
405
|
+
const surfaceOwner = owner => isOwner(owner, 'base/cards', ['Card', 'SmartCard', 'CardFooter']) || isOwner(owner, 'base/forms', ['FormSection']) || isOwner(owner, 'blocks/analytics', ['ChartCard']) || isOwner(owner, 'base/display', ['ContentBlock']);
|
|
406
|
+
const footerRegion = parent => surfaceOwner(parent.owner) && (['footerSlot', 'footer'].includes(parent.slot) || parent.owner.symbol === 'CardFooter');
|
|
407
|
+
const paddedRegion = parent => {
|
|
408
|
+
if (!surfaceOwner(parent.owner) || parent.unknownProps) return false;
|
|
409
|
+
if (parent.props.has('padding')) {
|
|
410
|
+
const padding = literal(parent.props.get('padding'));
|
|
411
|
+
return padding !== undefined && padding !== 'none';
|
|
412
|
+
}
|
|
413
|
+
// Flat removes the frame, not Card/FormSection's ordinary region insets.
|
|
414
|
+
// ChartCard and ContentBlock instead default to no inset when card-free.
|
|
415
|
+
return isOwner(parent.owner, 'base/cards', ['Card', 'SmartCard', 'CardFooter']) || isOwner(parent.owner, 'base/forms', ['FormSection']) || parent.framed;
|
|
416
|
+
};
|
|
417
|
+
const remoteSubmit = expression => {
|
|
418
|
+
const calls = new Set();
|
|
419
|
+
const walk = (node, visiting = new Set()) => {
|
|
420
|
+
if (!node) return;
|
|
421
|
+
const value = resolve(node) ?? node;
|
|
422
|
+
if (visiting.has(value)) return;
|
|
423
|
+
const next = new Set(visiting).add(value);
|
|
424
|
+
if (ts.isCallExpression(value) && ts.isPropertyAccessExpression(value.expression)) {
|
|
425
|
+
if (value.expression.name.text === 'requestSubmit') calls.add('submit');
|
|
426
|
+
if (value.expression.name.text === 'getElementById' && value.expression.expression.getText(source) === 'document' && !symbolFor(value.expression.expression)) calls.add('lookup');
|
|
427
|
+
}
|
|
428
|
+
ts.forEachChild(value, child => walk(child, next));
|
|
429
|
+
};
|
|
430
|
+
walk(expression);
|
|
431
|
+
return calls.size === 2;
|
|
432
|
+
};
|
|
318
433
|
// A native element passed as a package owner's `render` is that owner's root, such as
|
|
319
434
|
// an Item row rendered as a button; the owner keeps its focus, hover and row anatomy.
|
|
320
435
|
const renderRoots = new Set();
|
|
@@ -342,7 +457,7 @@ export function analyzeComposition(text, { filename, index, ts }) {
|
|
|
342
457
|
if (modalRole || scrim) add(node, 'raw-overlay-primitive', 'warning', `A hand-rolled ${modalRole ? 'dialog' : 'full-screen layer'} must own focus, dismissal, pending state and theming itself. ${overlayRemedy}`);
|
|
343
458
|
if (/^(?:input|textarea)$/.test(node.tagName.getText(source))) {
|
|
344
459
|
const props = new Map(attributes(node));
|
|
345
|
-
if (props.has('className') && classStrings(props.get('className')).flatMap(value=>value.split(/\s+/)).some(value=>replacesSharedRadius(value,'
|
|
460
|
+
if (props.has('className') && classStrings(props.get('className')).flatMap(value=>value.split(/\s+/)).some(value=>replacesSharedRadius(value,'radius'))) add(node,'shared-radius','error','Native editable controls follow bounded rounded-radius; change the global theme root, not per-field corners.');
|
|
346
461
|
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.');
|
|
347
462
|
}
|
|
348
463
|
if (nativeDisplayNames.test(node.tagName.getText(source))) {
|
|
@@ -356,9 +471,10 @@ export function analyzeComposition(text, { filename, index, ts }) {
|
|
|
356
471
|
add(node, 'public-symbol', 'error', `${owner.import} does not export ${owner.symbol}.`);
|
|
357
472
|
return;
|
|
358
473
|
}
|
|
359
|
-
const unresolvedBeforeProps = unresolved.length;
|
|
360
474
|
const props = new Map(attributes(node));
|
|
361
|
-
|
|
475
|
+
// Other reviews can have already disclosed this spread. Deduplication of
|
|
476
|
+
// unresolved output must not turn an unknown value into a known default.
|
|
477
|
+
const unknownProps = node.attributes.properties.some(attribute => ts.isJsxSpreadAttribute(attribute) && unknownSpread(attribute.expression));
|
|
362
478
|
const family = owner.import.split('/base/')[1];
|
|
363
479
|
const anatomy = surfaceParts[family]?.test(owner.symbol);
|
|
364
480
|
const forwarder = surfaceForwarders[family] === owner.symbol;
|
|
@@ -375,7 +491,7 @@ export function analyzeComposition(text, { filename, index, ts }) {
|
|
|
375
491
|
const focusDrift = focusRingDrift(tokens);
|
|
376
492
|
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.`);
|
|
377
493
|
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.`);
|
|
378
|
-
if ((name === 'className' && (control || sharedCorners) || name === 'contentClassName' && forwarder) && classes.some(value=>replacesSharedRadius(value, control && name === 'className' ? '
|
|
494
|
+
if ((name === 'className' && (control || sharedCorners) || name === 'contentClassName' && forwarder) && classes.some(value=>replacesSharedRadius(value, control && name === 'className' ? 'radius' : cornerRole(family,owner.symbol)))) add(node,'shared-radius','error',`${owner.symbol}: outer shells use rounded-surface; controls and collection rows use bounded rounded-radius. Preserve the owning role and joined-edge resets.`);
|
|
379
495
|
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.`);
|
|
380
496
|
if (textContent && name === 'className' && tokens.some(token=>fadedText(token)||textOpacityDrift(token))) add(node,'faded-text','error',`${owner.symbol}: use its semantic type instead of adding an opacity tier to the text. Presence endpoints and shared disabled state remain valid.`);
|
|
381
497
|
if ((control || family === 'buttons' && owner.symbol === 'TextButton') && name === 'className' && focusDrift.length) add(node, 'focus-ring-recipe', 'error', `${owner.symbol}: keep the shared focus indicator (a ring-3 halo of ring-ring/50 around a full-strength ring edge); ${[...new Set(focusDrift)].join(', ')} redraws it.`);
|
|
@@ -391,7 +507,7 @@ export function analyzeComposition(text, { filename, index, ts }) {
|
|
|
391
507
|
if ((isOwner(owner, 'base/cards', ['Card', 'SmartCard']) || isOwner(owner, 'base/display', ['ContentBlock'])) && props.get('icon')) add(node, 'decorative-icon', 'warning', `${owner.symbol}: a title icon is decoration unless it encodes state or a brand; let the title name the subject.`);
|
|
392
508
|
const facts = isOwner(owner, 'base/metadata-list', ['MetadataList']) || isOwner(owner, 'blocks/data-display', ['MetadataList']) ? resolve(props.get('items')) : undefined;
|
|
393
509
|
if (facts && ts.isArrayLiteralExpression(facts) && facts.elements.filter(item => properties(item, false).some(([name]) => name === 'icon')).length > 1) add(node, 'decorative-icon', 'warning', 'MetadataList: an icon on every fact repeats what its label says; keep labels and drop the icons.');
|
|
394
|
-
const framed = framedOwner(owner, props);
|
|
510
|
+
const framed = !unknownProps && framedOwner(owner, props);
|
|
395
511
|
if (isOwner(owner, 'base/cards', ['Card', 'SmartCard'])) {
|
|
396
512
|
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'}.`);
|
|
397
513
|
const contents = contentElements(node);
|
|
@@ -404,6 +520,37 @@ export function analyzeComposition(text, { filename, index, ts }) {
|
|
|
404
520
|
}
|
|
405
521
|
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.');
|
|
406
522
|
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.');
|
|
523
|
+
if (isOwner(owner, 'base/forms', ['FormActionsBar'])) {
|
|
524
|
+
const footer = parents.findLast(footerRegion);
|
|
525
|
+
const padded = parents.findLast(paddedRegion);
|
|
526
|
+
if (footer || padded) add(node, 'form-actions-bar-placement', 'warning', `FormActionsBar owns a divider, background and inset; ${footer ? `${footer.owner.symbol}.${footer.slot} already owns footer geometry` : `${padded.owner.symbol} already owns body padding`}. Put action buttons directly in the footer slot, or place the bar at the end of the form inside Card padding="none" with flat FormSection siblings. Review intentional custom hosts.`);
|
|
527
|
+
}
|
|
528
|
+
if (isOwner(owner, 'features/table', ['DataTable']) || isOwner(owner, 'base/table', ['Table'])) {
|
|
529
|
+
const footer = parents.findLast(footerRegion);
|
|
530
|
+
const padded = parents.findLast(paddedRegion);
|
|
531
|
+
if (footer || padded) add(node, 'uncontained-table-in-card', 'warning', `${owner.symbol} is inside ${footer ? `${footer.owner.symbol}.${footer.slot}` : `a padded ${padded.owner.symbol}`}. Keep substantial tables in a body or peer region; a deliberate Card host uses padding="none" with a flat table. Review the actual surface and inset ownership.`);
|
|
532
|
+
}
|
|
533
|
+
if ((isOwner(owner, 'base/accordion', ['Accordion', 'SmartAccordion']) || isOwner(owner, 'features/table', ['DataTable']) || isOwner(owner, 'base/code-block', ['CodeBlock'])) && parents.some(parent => isOwner(parent.owner, 'features/table', ['DataTable']) && parent.slot === 'columns' && parent.member === 'cell')) {
|
|
534
|
+
add(node, 'heavy-cell-disclosure', 'warning', `${owner.symbol} in a DataTable cell can disrupt row scanning. Prefer a compact summary with rowActions opening an ActionDrawer, ActionDialog or detail route; retain an intentional inline disclosure after checking expanded rows and keyboard access.`);
|
|
535
|
+
}
|
|
536
|
+
if (isOwner(owner, 'base/choice-inputs', ['CardCheckboxGroup', 'CardRadioGroup', 'ListRadioGroup', 'PillRadioGroup'])) {
|
|
537
|
+
const options = resolve(props.get('options'));
|
|
538
|
+
if (options && ts.isArrayLiteralExpression(options) && options.elements.length === 1 && !ts.isSpreadElement(options.elements[0])) add(node, 'single-option-choice-group', 'warning', `${owner.symbol} has one static option. For a boolean setting prefer Checkbox, Switch, ToggleField or SwitchCard; retain a genuine choice set whose available options happen to contain one item.`);
|
|
539
|
+
}
|
|
540
|
+
const routeOwner = isOwner(owner, 'layout/page', ['Page']) || isOwner(owner, 'layout', ['Page']);
|
|
541
|
+
if (routeOwner) {
|
|
542
|
+
for (const name of ['narrow', 'maxWidth']) {
|
|
543
|
+
const value = resolve(props.get(name));
|
|
544
|
+
if (value && (ts.isConditionalExpression(value) || ts.isBinaryExpression(value) || ts.isPrefixUnaryExpression(value))) add(props.get(name), 'dynamic-page-measure', 'warning', `Page ${name} depends on an expression and may resize the header and tabs when sections change. Keep the route measure stable and constrain a focused tab panel with Container maxWidth="md" gutter="none"; responsive route sizing can be intentional.`);
|
|
545
|
+
}
|
|
546
|
+
const children = regionElements(node);
|
|
547
|
+
const contents = regionElements(node, true);
|
|
548
|
+
const tables = contents.filter(child => isOwner(child.owner, 'features/table', ['DataTable']));
|
|
549
|
+
for (const child of contents) if (isOwner(child.owner, 'features/filters', ['FilterLayout']) && tables.some(table => table.scope === child.scope && (!child.subject || table.subject === child.subject))) add(child.node, 'detached-filter-layout', 'warning', 'Pass FilterLayout into DataTable topbarContent with variant="compact", or use DataView so filters and table chrome share one surface.');
|
|
550
|
+
const hasAsideSlot = properties(props.get('slots'), false).some(([name]) => name === 'aside');
|
|
551
|
+
const onlyForms = children.length > 0 && children.every(child => child.tag === 'form' || isOwner(child.owner, 'base/forms', ['FormSection']));
|
|
552
|
+
if (onlyForms && !unknownProps && !['narrow', 'maxWidth', 'aside'].some(name => props.has(name)) && !hasAsideSlot) add(node, 'wide-single-column-form', 'warning', 'Review this single-column form measure: a focused form can use Page narrow (48rem centered), an explicit maxWidth, or a supporting aside. In a mixed/tabbed route, keep Page stable and constrain only the form panel with Container maxWidth="md" gutter="none".');
|
|
553
|
+
}
|
|
407
554
|
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.');
|
|
408
555
|
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.');
|
|
409
556
|
const peers = parents.findLast(parent => parent.structure);
|
|
@@ -411,6 +558,8 @@ export function analyzeComposition(text, { filename, index, ts }) {
|
|
|
411
558
|
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.`);
|
|
412
559
|
const header = properties(props.get('header'), false);
|
|
413
560
|
const pageOwner = owner.import === `${index.package}/layout/page` || owner.import === `${index.package}/layout`;
|
|
561
|
+
const headerValue = resolve(props.get('header'));
|
|
562
|
+
if (routeOwner && props.has('header') && headerValue && !ts.isObjectLiteralExpression(headerValue)) unknown(props.get('header'));
|
|
414
563
|
// Every header owner takes role-based commands; its free-form regions hold
|
|
415
564
|
// non-command controls only.
|
|
416
565
|
const commandHeader = (pageOwner && owner.symbol === 'PageHeader') || isOwner(owner, 'base/navigation', ['PageHeading']) || isOwner(owner, 'features/resource', ['ResourceHeader', 'ResourceIndexShell', 'ResourceShowShell', 'TabbedResourceShell']) || isOwner(owner, 'layout/settings', ['SettingsShell', 'AsideNavShell']) || isOwner(owner, 'layout', ['SettingsShell', 'AsideNavShell']) || isOwner(owner, 'layout/workspace', ['WorkspaceRecordHeader']);
|
|
@@ -418,11 +567,12 @@ export function analyzeComposition(text, { filename, index, ts }) {
|
|
|
418
567
|
const elementSecondary = isOwner(owner, 'layout/workspace', ['WorkspaceRecordHeader']) ? props.get('secondaryActions') : undefined;
|
|
419
568
|
if (pageOwner && owner.symbol === 'Page') {
|
|
420
569
|
const primaries = solidPrimaryCount(ts.isJsxSelfClosingElement(node) ? node : node.parent) + (new Map(header).has('primaryAction') ? 1 : 0);
|
|
421
|
-
if (primaries > 1) add(node, 'multiple-primary-commands', 'warning', `Page has ${primaries} solid primary commands. Keep one
|
|
570
|
+
if (primaries > 1) add(node, 'multiple-primary-commands', 'warning', `Page has ${primaries} solid primary commands in the same task scope. Keep one leading command per task/surface; forms keep their local SubmitStateButton or FormActionsBar. Use header.primaryAction for route-level commands and secondaryActions for supporting route commands.`);
|
|
422
571
|
}
|
|
423
572
|
if ((headerActions && commandButtons(headerActions)) || (elementSecondary && commandButtons(elementSecondary))) add(node, 'page-command-roles', 'warning', `${owner.symbol}: buttons, command rows and menus in the header actions region choose their own emphasis, order and overflow. Pass commands as primaryAction (one) and ordered secondaryActions; keep actions for non-command controls.`);
|
|
424
573
|
const headerProps = pageOwner && owner.symbol === 'Page' ? new Map(header) : pageOwner && owner.symbol === 'PageHeader' ? props : undefined;
|
|
425
574
|
if (headerProps) {
|
|
575
|
+
for (const name of ['primaryAction', 'secondaryActions']) if (headerProps.has(name) && remoteSubmit(headerProps.get(name))) add(headerProps.get(name), 'remote-header-form-submit', 'warning', `${owner.symbol}: ${name} submits a form through document.getElementById(...).requestSubmit(). Keep task-local submission beside its fields or in the form footer. A single full-page editor can deliberately own a header submit; preserve native validation and avoid duplicate commands.`);
|
|
426
576
|
if (headerProps.has('titleIcon') && !headerProps.has('titleIconHref') && !headerProps.has('onTitleIconClick')) add(headerProps.get('titleIcon') ?? node, 'decorative-icon', 'warning', `${owner.symbol}: titleIcon decorates the page title; let the title name the page, or link the icon with titleIconHref.`);
|
|
427
577
|
const hasIcon = action => properties(action, false).some(([name]) => name === 'icon');
|
|
428
578
|
const secondary = resolve(headerProps.get('secondaryActions'));
|
|
@@ -432,7 +582,7 @@ export function analyzeComposition(text, { filename, index, ts }) {
|
|
|
432
582
|
const title = literal(props.get('title')) ?? literal(new Map(header).get('title'));
|
|
433
583
|
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.`);
|
|
434
584
|
const structure = owner.import === `${index.package}/base/structure` && Object.hasOwn(structureDefaults, owner.symbol);
|
|
435
|
-
return { framed, title, structure, cards: structure ? peerCards(node) : new Set(), smallGap: structure ? smallGap(props, owner.symbol, unknownProps) : false };
|
|
585
|
+
return { owner, props, unknownProps, framed, title, structure, cards: structure ? peerCards(node) : new Set(), smallGap: structure ? smallGap(props, owner.symbol, unknownProps) : false };
|
|
436
586
|
}
|
|
437
587
|
visit(source);
|
|
438
588
|
return { findings, unresolved };
|
|
@@ -4,7 +4,7 @@ const name = value => typeof value === 'string' && /^[A-Za-z][A-Za-z0-9]*$/.test
|
|
|
4
4
|
const uniqueList = (value, valid, maximum) => Array.isArray(value) && value.length <= maximum && value.every(valid) && new Set(value).size === value.length;
|
|
5
5
|
const scalar = value => value === null || typeof value === 'boolean' || (typeof value === 'string' && value.length <= 500) || (typeof value === 'number' && Number.isFinite(value));
|
|
6
6
|
const kinds = ['shell', 'page', 'layout', 'surface', 'content', 'workflow'];
|
|
7
|
-
const placements = ['region', 'cell', 'overlay'];
|
|
7
|
+
const placements = ['region', 'toolbar', 'cell', 'overlay'];
|
|
8
8
|
const surfaces = ['none', 'parent', 'self', 'variant'];
|
|
9
9
|
|
|
10
10
|
/** One literal metadata shape shared by authored catalogue and copied tools. */
|