@kerfjs/ui 5.0.0-beta.8 → 5.0.0-beta.81
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/README.md +546 -139
- package/ai/application-ui-diagnostic-ids-v1.json +113 -0
- package/ai/application-ui-profile-sync.cjs +548 -0
- package/ai/application-ui-profile.d.mts +1 -0
- package/ai/application-ui-profile.d.ts +106 -0
- package/ai/application-ui-profile.defaults.json +96 -0
- package/ai/application-ui-profile.mjs +653 -0
- package/ai/application-ui-profile.schema.json +140 -0
- package/ai/catalog-authoring.json +36 -0
- package/ai/catalog-authoring.schema.json +109 -0
- package/ai/compile-time-contracts-v1.json +149 -0
- package/ai/compile-time-contracts-v1.schema.json +52 -0
- package/ai/component-catalog-extension.schema.json +104 -0
- package/ai/component-catalog.json +4280 -457
- package/ai/component-catalog.schema.json +94 -1
- package/ai/component-class-owners.cjs +83 -0
- package/ai/component-composition-extension.d.ts +7 -0
- package/ai/component-composition-extension.schema.json +7 -0
- package/ai/component-composition-rules.json +520 -0
- package/ai/component-composition.d.ts +129 -0
- package/ai/component-composition.json +7401 -0
- package/ai/component-composition.schema.json +408 -0
- package/ai/components/README.md +171 -0
- package/ai/components/application-tabs.md +65 -0
- package/ai/components/badge.md +72 -0
- package/ai/components/chip.md +72 -0
- package/ai/components/collapsible-panel.md +102 -0
- package/ai/components/content-item.md +96 -0
- package/ai/components/disclosure-arrow.md +77 -0
- package/ai/components/document-baseline.md +75 -0
- package/ai/components/empty-state.md +80 -0
- package/ai/components/feedback.md +71 -0
- package/ai/components/floating-toolbar.md +82 -0
- package/ai/components/foundation.md +65 -0
- package/ai/components/grid.md +100 -0
- package/ai/components/headers.md +63 -0
- package/ai/components/layout.md +75 -0
- package/ai/components/list-action-row.md +91 -0
- package/ai/components/list-header.md +91 -0
- package/ai/components/list-inset-control.md +74 -0
- package/ai/components/list-inset-text.md +72 -0
- package/ai/components/list-item.md +94 -0
- package/ai/components/list.md +106 -0
- package/ai/components/loading-spinner.md +73 -0
- package/ai/components/lucide-icon.md +97 -0
- package/ai/components/nav-stack.md +105 -0
- package/ai/components/pane.md +104 -0
- package/ai/components/popup-menu.md +171 -0
- package/ai/components/recipe-app-shell.md +57 -0
- package/ai/components/recipe-collapsible-sidebar.md +57 -0
- package/ai/components/recipe-compact-toolbar.md +57 -0
- package/ai/components/recipe-composer-form.md +57 -0
- package/ai/components/recipe-list-detail-dialog.md +57 -0
- package/ai/components/recipe-list-workspace-states.md +57 -0
- package/ai/components/recipe-loading-inspector.md +57 -0
- package/ai/components/recipe-navigation-sidebar.md +57 -0
- package/ai/components/recipe-navigation-stack.md +57 -0
- package/ai/components/recipe-workspace-header.md +57 -0
- package/ai/components/resize.md +106 -0
- package/ai/components/row.md +96 -0
- package/ai/components/segmented-control.md +82 -0
- package/ai/components/select.md +115 -0
- package/ai/components/skeleton.md +84 -0
- package/ai/components/spacer.md +86 -0
- package/ai/components/split-view.md +103 -0
- package/ai/components/state-banner.md +94 -0
- package/ai/components/sunken-panel.md +79 -0
- package/ai/components/surface-scaffold.md +87 -0
- package/ai/components/tab-bar.md +113 -0
- package/ai/components/tab-navigator.md +95 -0
- package/ai/components/tabs.md +95 -0
- package/ai/components/text.md +87 -0
- package/ai/components/token-search-field.md +107 -0
- package/ai/components/toolbar-control-group.md +121 -0
- package/ai/components/toolbar-text.md +98 -0
- package/ai/components/toolbar.md +101 -0
- package/ai/components/value-table.md +73 -0
- package/ai/components/wa-accordion-item.md +55 -0
- package/ai/components/wa-accordion.md +65 -0
- package/ai/components/wa-animated-image.md +55 -0
- package/ai/components/wa-animation.md +55 -0
- package/ai/components/wa-avatar.md +55 -0
- package/ai/components/wa-badge.md +55 -0
- package/ai/components/wa-breadcrumb-item.md +53 -0
- package/ai/components/wa-breadcrumb.md +55 -0
- package/ai/components/wa-button-group.md +59 -0
- package/ai/components/wa-button.md +55 -0
- package/ai/components/wa-callout.md +58 -0
- package/ai/components/wa-card.md +59 -0
- package/ai/components/wa-carousel-item.md +53 -0
- package/ai/components/wa-carousel.md +55 -0
- package/ai/components/wa-checkbox-group.md +55 -0
- package/ai/components/wa-checkbox.md +55 -0
- package/ai/components/wa-color-picker.md +55 -0
- package/ai/components/wa-comparison.md +55 -0
- package/ai/components/wa-copy-button.md +55 -0
- package/ai/components/wa-details.md +61 -0
- package/ai/components/wa-dialog.md +59 -0
- package/ai/components/wa-divider.md +53 -0
- package/ai/components/wa-drawer.md +55 -0
- package/ai/components/wa-dropdown-item.md +60 -0
- package/ai/components/wa-dropdown.md +60 -0
- package/ai/components/wa-format-bytes.md +53 -0
- package/ai/components/wa-format-date.md +53 -0
- package/ai/components/wa-format-number.md +53 -0
- package/ai/components/wa-icon.md +58 -0
- package/ai/components/wa-include.md +53 -0
- package/ai/components/wa-input.md +59 -0
- package/ai/components/wa-intersection-observer.md +53 -0
- package/ai/components/wa-known-date.md +53 -0
- package/ai/components/wa-markdown.md +53 -0
- package/ai/components/wa-mutation-observer.md +53 -0
- package/ai/components/wa-number-input.md +55 -0
- package/ai/components/wa-option.md +59 -0
- package/ai/components/wa-otp-input.md +53 -0
- package/ai/components/wa-page.md +53 -0
- package/ai/components/wa-pagination.md +55 -0
- package/ai/components/wa-popover.md +55 -0
- package/ai/components/wa-popup.md +53 -0
- package/ai/components/wa-progress-bar.md +53 -0
- package/ai/components/wa-progress-ring.md +53 -0
- package/ai/components/wa-qr-code.md +53 -0
- package/ai/components/wa-radio-group.md +59 -0
- package/ai/components/wa-radio.md +55 -0
- package/ai/components/wa-random-content.md +53 -0
- package/ai/components/wa-rating.md +55 -0
- package/ai/components/wa-relative-time.md +53 -0
- package/ai/components/wa-resize-observer.md +53 -0
- package/ai/components/wa-scroller.md +53 -0
- package/ai/components/wa-select.md +63 -0
- package/ai/components/wa-skeleton.md +53 -0
- package/ai/components/wa-slider.md +55 -0
- package/ai/components/wa-spinner.md +58 -0
- package/ai/components/wa-split-panel.md +58 -0
- package/ai/components/wa-switch.md +53 -0
- package/ai/components/wa-tab-group.md +69 -0
- package/ai/components/wa-tab-panel.md +60 -0
- package/ai/components/wa-tab.md +59 -0
- package/ai/components/wa-tag.md +59 -0
- package/ai/components/wa-textarea.md +53 -0
- package/ai/components/wa-time-input.md +55 -0
- package/ai/components/wa-toast-item.md +60 -0
- package/ai/components/wa-toast.md +60 -0
- package/ai/components/wa-tooltip.md +55 -0
- package/ai/components/wa-tree-item.md +55 -0
- package/ai/components/wa-tree.md +55 -0
- package/ai/components/wa-zoomable-frame.md +55 -0
- package/ai/components/workbench.md +119 -0
- package/ai/public-api-signatures-v1.md +2821 -250
- package/ai/skill.md +354 -66
- package/ai/webawesome-jsx-signatures-v1.md +9 -2
- package/analyzer/cli.mjs +49 -0
- package/analyzer/component-ownership.d.mts +72 -0
- package/analyzer/component-ownership.mjs +429 -0
- package/analyzer/index.d.mts +53 -0
- package/analyzer/index.mjs +2346 -0
- package/analyzer/loud-pairs.d.mts +49 -0
- package/analyzer/loud-pairs.mjs +357 -0
- package/analyzer/report.schema.json +66 -0
- package/analyzer/selectors.d.mts +21 -0
- package/analyzer/selectors.mjs +212 -0
- package/catalog-projection-cli.mjs +96 -0
- package/catalog-projection.d.mts +55 -0
- package/catalog-projection.mjs +62 -0
- package/dist/app-tab.d.ts +39 -4
- package/dist/app-tab.js +2 -1
- package/dist/badge.d.ts +54 -0
- package/dist/badge.js +3 -0
- package/dist/badge.js.map +1 -0
- package/dist/browser/badge.js +3 -0
- package/dist/browser/catalog.js +26 -0
- package/dist/browser/chip.js +3 -0
- package/dist/browser/collapsible-panel.js +9 -0
- package/dist/browser/content-item.js +3 -0
- package/dist/browser/floating-toolbar.js +3 -0
- package/dist/browser/grid.js +3 -0
- package/dist/browser/list-action-row.js +5 -0
- package/dist/browser/{menu-header.js → list-header.js} +5 -3
- package/dist/browser/list-inset-control.js +3 -0
- package/dist/browser/list-inset-text.js +3 -0
- package/dist/browser/list-item.js +5 -0
- package/dist/browser/list.js +3 -0
- package/dist/browser/nav-stack.js +11 -0
- package/dist/browser/pane.js +3 -0
- package/dist/browser/popup-menu.js +3 -0
- package/dist/browser/row.js +3 -0
- package/dist/browser/segmented-control.js +0 -1
- package/dist/browser/select.js +2 -1
- package/dist/browser/spacer.js +3 -0
- package/dist/browser/split-view.js +13 -0
- package/dist/browser/state-banner.js +1 -0
- package/dist/browser/sunken-panel.js +3 -0
- package/dist/browser/surface-scaffold.js +3 -0
- package/dist/browser/tab-navigator.js +4 -0
- package/dist/browser/text.js +3 -0
- package/dist/browser/toolbar-control-group.js +1 -0
- package/dist/browser/workbench.js +14 -0
- package/dist/catalog-resources.d.ts +48 -0
- package/dist/catalog-resources.js +22 -0
- package/dist/catalog-resources.js.map +1 -0
- package/dist/catalog.d.ts +92 -0
- package/dist/catalog.js +541 -0
- package/dist/catalog.js.map +1 -0
- package/dist/chip.d.ts +36 -0
- package/dist/chip.js +3 -0
- package/dist/chip.js.map +1 -0
- package/dist/chunk-2GOCOLQL.js +270 -0
- package/dist/chunk-2GOCOLQL.js.map +1 -0
- package/dist/chunk-3CXRQAYT.js +288 -0
- package/dist/chunk-3CXRQAYT.js.map +1 -0
- package/dist/chunk-3RE2JMZU.js +48 -0
- package/dist/chunk-3RE2JMZU.js.map +1 -0
- package/dist/chunk-3SXWV2IR.js +295 -0
- package/dist/chunk-3SXWV2IR.js.map +1 -0
- package/dist/chunk-3XPGJUUQ.js +37 -0
- package/dist/chunk-3XPGJUUQ.js.map +1 -0
- package/dist/chunk-4Y4L5YEI.js +66 -0
- package/dist/chunk-4Y4L5YEI.js.map +1 -0
- package/dist/chunk-5BZBIRQG.js +452 -0
- package/dist/chunk-5BZBIRQG.js.map +1 -0
- package/dist/chunk-5D3WDMIK.js +71 -0
- package/dist/chunk-5D3WDMIK.js.map +1 -0
- package/dist/chunk-62VMNBV2.js +779 -0
- package/dist/chunk-62VMNBV2.js.map +1 -0
- package/dist/chunk-75I3SNUJ.js +44 -0
- package/dist/chunk-75I3SNUJ.js.map +1 -0
- package/dist/chunk-7QQ3HE47.js +17 -0
- package/dist/chunk-7QQ3HE47.js.map +1 -0
- package/dist/chunk-7TE6XDFI.js +91 -0
- package/dist/chunk-7TE6XDFI.js.map +1 -0
- package/dist/chunk-A7DYEERU.js +59 -0
- package/dist/chunk-A7DYEERU.js.map +1 -0
- package/dist/chunk-AN5IWMTM.js +24 -0
- package/dist/chunk-AN5IWMTM.js.map +1 -0
- package/dist/chunk-ARZ4RSQO.js +48 -0
- package/dist/chunk-ARZ4RSQO.js.map +1 -0
- package/dist/chunk-BJLXE56E.js +135 -0
- package/dist/chunk-BJLXE56E.js.map +1 -0
- package/dist/chunk-BYHGRKC3.js +44 -0
- package/dist/chunk-BYHGRKC3.js.map +1 -0
- package/dist/chunk-CEJ5FK6G.js +288 -0
- package/dist/chunk-CEJ5FK6G.js.map +1 -0
- package/dist/chunk-CVKIADIS.js +172 -0
- package/dist/chunk-CVKIADIS.js.map +1 -0
- package/dist/chunk-DQDTZE4W.js +70 -0
- package/dist/chunk-DQDTZE4W.js.map +1 -0
- package/dist/chunk-EFDCALR3.js +66 -0
- package/dist/chunk-EFDCALR3.js.map +1 -0
- package/dist/chunk-FL6J644M.js +116 -0
- package/dist/chunk-FL6J644M.js.map +1 -0
- package/dist/chunk-GS2QD3N7.js +14 -0
- package/dist/chunk-GS2QD3N7.js.map +1 -0
- package/dist/chunk-H45DAZBL.js +491 -0
- package/dist/chunk-H45DAZBL.js.map +1 -0
- package/dist/chunk-H7ZJEI3H.js +52 -0
- package/dist/chunk-H7ZJEI3H.js.map +1 -0
- package/dist/chunk-HFLGWMG3.js +138 -0
- package/dist/chunk-HFLGWMG3.js.map +1 -0
- package/dist/chunk-HFQDSSED.js +188 -0
- package/dist/chunk-HFQDSSED.js.map +1 -0
- package/dist/{chunk-56RJXPHG.js → chunk-I4SDIMFA.js} +7 -4
- package/dist/chunk-I4SDIMFA.js.map +1 -0
- package/dist/chunk-IM3GKYOG.js +202 -0
- package/dist/chunk-IM3GKYOG.js.map +1 -0
- package/dist/chunk-J3AWE5I4.js +50 -0
- package/dist/chunk-J3AWE5I4.js.map +1 -0
- package/dist/chunk-JOR5LGYE.js +55 -0
- package/dist/chunk-JOR5LGYE.js.map +1 -0
- package/dist/chunk-JZM3G6RT.js +149 -0
- package/dist/chunk-JZM3G6RT.js.map +1 -0
- package/dist/{chunk-7BR3DO2A.js → chunk-LAZLBC2Q.js} +14 -5
- package/dist/chunk-LAZLBC2Q.js.map +1 -0
- package/dist/chunk-LQKY5S4F.js +506 -0
- package/dist/chunk-LQKY5S4F.js.map +1 -0
- package/dist/chunk-LRAIS3YB.js +158 -0
- package/dist/chunk-LRAIS3YB.js.map +1 -0
- package/dist/chunk-MXNIVEVL.js +48 -0
- package/dist/chunk-MXNIVEVL.js.map +1 -0
- package/dist/chunk-NJZMR7HM.js +135 -0
- package/dist/chunk-NJZMR7HM.js.map +1 -0
- package/dist/chunk-NMWDHZVM.js +35 -0
- package/dist/chunk-NMWDHZVM.js.map +1 -0
- package/dist/{chunk-YGN7OMLT.js → chunk-NS2TBYM4.js} +8 -5
- package/dist/chunk-NS2TBYM4.js.map +1 -0
- package/dist/chunk-NVKRZ5DI.js +222 -0
- package/dist/chunk-NVKRZ5DI.js.map +1 -0
- package/dist/chunk-NVRJ7C3W.js +83 -0
- package/dist/chunk-NVRJ7C3W.js.map +1 -0
- package/dist/chunk-O27D24CA.js +250 -0
- package/dist/chunk-O27D24CA.js.map +1 -0
- package/dist/chunk-PQQQXJGV.js +58 -0
- package/dist/chunk-PQQQXJGV.js.map +1 -0
- package/dist/chunk-RRCD3A6G.js +139 -0
- package/dist/chunk-RRCD3A6G.js.map +1 -0
- package/dist/chunk-S3ECMF23.js +33 -0
- package/dist/chunk-S3ECMF23.js.map +1 -0
- package/dist/chunk-S4ZGTDSG.js +18 -0
- package/dist/chunk-S4ZGTDSG.js.map +1 -0
- package/dist/chunk-VHXHLZ6R.js +69 -0
- package/dist/chunk-VHXHLZ6R.js.map +1 -0
- package/dist/chunk-VIGVNDXZ.js +165 -0
- package/dist/chunk-VIGVNDXZ.js.map +1 -0
- package/dist/chunk-VR7MWD2X.js +91 -0
- package/dist/chunk-VR7MWD2X.js.map +1 -0
- package/dist/chunk-Y6KT7ZTR.js +109 -0
- package/dist/chunk-Y6KT7ZTR.js.map +1 -0
- package/dist/chunk-YLJ6X3AC.js +34 -0
- package/dist/chunk-YLJ6X3AC.js.map +1 -0
- package/dist/collapsible-panel.d.ts +137 -0
- package/dist/collapsible-panel.js +135 -0
- package/dist/collapsible-panel.js.map +1 -0
- package/dist/content-item.d.ts +99 -0
- package/dist/content-item.js +4 -0
- package/dist/content-item.js.map +1 -0
- package/dist/css-values.d.ts +112 -0
- package/dist/css-values.js +3 -0
- package/dist/css-values.js.map +1 -0
- package/dist/device-class.js +34 -6
- package/dist/device-class.js.map +1 -1
- package/dist/disclosure-arrow.d.ts +6 -1
- package/dist/disclosure-arrow.js +2 -1
- package/dist/empty-state.d.ts +5 -2
- package/dist/empty-state.js +2 -1
- package/dist/flex-alignment-4ms8ZbV8.d.ts +5 -0
- package/dist/floating-toolbar.d.ts +51 -0
- package/dist/floating-toolbar.js +3 -0
- package/dist/floating-toolbar.js.map +1 -0
- package/dist/grid.d.ts +57 -0
- package/dist/grid.js +5 -0
- package/dist/grid.js.map +1 -0
- package/dist/help-tags-register.d.ts +13 -0
- package/dist/help-tags-register.js +9 -0
- package/dist/help-tags-register.js.map +1 -0
- package/dist/index.d.ts +40 -18
- package/dist/index.js +44 -23
- package/dist/{menu-action-row.d.ts → list-action-row.d.ts} +21 -9
- package/dist/list-action-row.js +8 -0
- package/dist/list-action-row.js.map +1 -0
- package/dist/list-header.d.ts +98 -0
- package/dist/list-header.js +10 -0
- package/dist/list-header.js.map +1 -0
- package/dist/list-inset-control.d.ts +22 -0
- package/dist/list-inset-control.js +3 -0
- package/dist/list-inset-control.js.map +1 -0
- package/dist/list-inset-text.d.ts +30 -0
- package/dist/list-inset-text.js +4 -0
- package/dist/list-inset-text.js.map +1 -0
- package/dist/list-item.d.ts +62 -0
- package/dist/list-item.js +8 -0
- package/dist/list-item.js.map +1 -0
- package/dist/list.d.ts +63 -0
- package/dist/list.js +6 -0
- package/dist/list.js.map +1 -0
- package/dist/loading-spinner.d.ts +12 -2
- package/dist/loading-spinner.js +2 -1
- package/dist/lucide-icon.d.ts +14 -2
- package/dist/lucide-icon.js +2 -1
- package/dist/nav-stack-B1Qc2e5q.d.ts +101 -0
- package/dist/nav-stack.d.ts +13 -38
- package/dist/nav-stack.js +10 -1
- package/dist/pane.d.ts +116 -0
- package/dist/pane.js +4 -0
- package/dist/pane.js.map +1 -0
- package/dist/panel-toolbar-CL9tYOkh.d.ts +72 -0
- package/dist/popup-menu-register.d.ts +9 -0
- package/dist/popup-menu-register.js +244 -0
- package/dist/popup-menu-register.js.map +1 -0
- package/dist/popup-menu.d.ts +100 -0
- package/dist/popup-menu.js +3 -0
- package/dist/popup-menu.js.map +1 -0
- package/dist/resizable-region.d.ts +32 -3
- package/dist/resizable-region.js +1 -1
- package/dist/row.d.ts +48 -0
- package/dist/row.js +6 -0
- package/dist/row.js.map +1 -0
- package/dist/segmented-control.d.ts +12 -9
- package/dist/segmented-control.js +1 -2
- package/dist/select-register.d.ts +5 -1
- package/dist/select-register.js +247 -3
- package/dist/select-register.js.map +1 -1
- package/dist/select.d.ts +103 -8
- package/dist/select.js +3 -1
- package/dist/semantic-content-BbzjvSu9.d.ts +14 -0
- package/dist/semantic-tone-CdW013KF.d.ts +4 -0
- package/dist/sides-BPSWde0A.d.ts +4 -0
- package/dist/skeleton.d.ts +14 -7
- package/dist/skeleton.js +2 -1
- package/dist/spacer.d.ts +18 -0
- package/dist/spacer.js +4 -0
- package/dist/spacer.js.map +1 -0
- package/dist/split-view.d.ts +44 -7
- package/dist/split-view.js +124 -10
- package/dist/split-view.js.map +1 -1
- package/dist/state-banner.d.ts +21 -7
- package/dist/state-banner.js +3 -1
- package/dist/styles/app-tab.css +224 -0
- package/dist/styles/badge.css +118 -0
- package/dist/styles/catalog/components/catalog-example-stack.css +9 -0
- package/dist/styles/catalog/components/catalog-example.css +168 -0
- package/dist/styles/catalog/components/catalog-stage.css +55 -0
- package/dist/styles/catalog/components/catalog.css +50 -0
- package/dist/styles/catalog.css +5 -0
- package/dist/styles/chip.css +138 -0
- package/dist/styles/collapsible-panel.css +580 -0
- package/dist/styles/components/actions/floating-toolbar/floating-toolbar.css +119 -0
- package/dist/styles/components/actions/popup-menu/popup-menu.css +285 -0
- package/dist/styles/components/actions/toolbar/toolbar.css +417 -0
- package/dist/styles/components/actions/toolbar-control-group/toolbar-control-group.css +891 -0
- package/dist/styles/components/actions/toolbar-text/toolbar-text.css +171 -0
- package/dist/styles/components/collections/list/list.css +133 -0
- package/dist/styles/components/collections/list-action-row/list-action-row.css +258 -0
- package/dist/styles/components/collections/list-header/list-header.css +229 -0
- package/dist/styles/components/collections/list-inset-control/list-inset-control.css +30 -0
- package/dist/styles/components/collections/list-inset-text/list-inset-text.css +29 -0
- package/dist/styles/components/collections/list-item/list-item.css +255 -0
- package/dist/styles/components/data-display/value-table/value-table.css +105 -0
- package/dist/styles/components/feedback/badge/badge.css +118 -0
- package/dist/styles/components/feedback/chip/chip.css +138 -0
- package/dist/styles/components/feedback/empty-state/empty-state.css +47 -0
- package/dist/styles/components/feedback/loading-spinner/loading-spinner.css +25 -0
- package/dist/styles/components/feedback/skeleton/skeleton.css +92 -0
- package/dist/styles/components/feedback/state-banner/state-banner.css +248 -0
- package/dist/styles/components/forms/segmented-control/segmented-control.css +196 -0
- package/dist/styles/components/forms/select/select.css +454 -0
- package/dist/styles/components/forms/token-search-field/token-search-field.css +392 -0
- package/dist/styles/components/layout/collapsible-panel/collapsible-panel.css +580 -0
- package/dist/styles/components/layout/grid/grid.css +85 -0
- package/dist/styles/components/layout/pane/pane.css +294 -0
- package/dist/styles/components/layout/resizable-region/resizable-region.css +545 -0
- package/dist/styles/components/layout/row/row.css +111 -0
- package/dist/styles/components/layout/spacer/spacer.css +11 -0
- package/dist/styles/components/layout/split-view/split-view.css +146 -0
- package/dist/styles/components/layout/workbench/workbench.css +1075 -0
- package/dist/styles/components/media/lucide-icon/lucide-icon.css +15 -0
- package/dist/styles/components/navigation/app-tab/app-tab.css +376 -0
- package/dist/styles/components/navigation/disclosure-arrow/disclosure-arrow.css +23 -0
- package/dist/styles/components/navigation/nav-stack/nav-stack.css +242 -0
- package/dist/styles/components/navigation/tab-bar/tab-bar.css +183 -0
- package/dist/styles/components/navigation/tab-navigator/tab-navigator.css +237 -0
- package/dist/styles/components/surfaces/content-item/content-item.css +120 -0
- package/dist/styles/components/surfaces/sunken-panel/sunken-panel.css +34 -0
- package/dist/styles/components/surfaces/surface-scaffold/surface-scaffold.css +111 -0
- package/dist/styles/components/typography/text/text.css +158 -0
- package/dist/styles/content-item.css +120 -0
- package/dist/styles/document.css +33 -0
- package/dist/styles/floating-toolbar.css +119 -0
- package/dist/styles/foundation.css +187 -45
- package/dist/styles/grid.css +85 -0
- package/dist/styles/layout.css +3 -41
- package/dist/styles/list-action-row.css +258 -0
- package/dist/styles/list-header.css +229 -0
- package/dist/styles/list-inset-control.css +30 -0
- package/dist/styles/list-inset-text.css +29 -0
- package/dist/styles/list-item.css +255 -0
- package/dist/styles/list.css +133 -0
- package/dist/styles/loading-spinner.css +4 -0
- package/dist/styles/lucide-icon.css +9 -0
- package/dist/styles/nav-stack.css +180 -50
- package/dist/styles/pane.css +294 -0
- package/dist/styles/popup-menu.css +285 -0
- package/dist/styles/resizable-region.css +438 -4
- package/dist/styles/row.css +111 -0
- package/dist/styles/segmented-control.css +36 -9
- package/dist/styles/select.css +337 -21
- package/dist/styles/skeleton.css +64 -3
- package/dist/styles/spacer.css +11 -0
- package/dist/styles/split-view.css +114 -3
- package/dist/styles/state-banner.css +94 -19
- package/dist/styles/styles.css +13 -4
- package/dist/styles/sunken-panel.css +34 -0
- package/dist/styles/surface-scaffold.css +111 -0
- package/dist/styles/tab-bar.css +147 -9
- package/dist/styles/tab-navigator.css +237 -0
- package/dist/styles/text.css +158 -0
- package/dist/styles/token-search-field.css +167 -56
- package/dist/styles/toolbar-control-group.css +710 -30
- package/dist/styles/toolbar-text.css +139 -8
- package/dist/styles/toolbar.css +367 -11
- package/dist/styles/value-table.css +34 -4
- package/dist/styles/webawesome.css +388 -16
- package/dist/styles/workbench.css +988 -7
- package/dist/sunken-panel.d.ts +31 -0
- package/dist/sunken-panel.js +3 -0
- package/dist/sunken-panel.js.map +1 -0
- package/dist/surface-scaffold-register.d.ts +4 -0
- package/dist/surface-scaffold-register.js +59 -0
- package/dist/surface-scaffold-register.js.map +1 -0
- package/dist/surface-scaffold.d.ts +38 -0
- package/dist/surface-scaffold.js +3 -0
- package/dist/surface-scaffold.js.map +1 -0
- package/dist/tab-bar.d.ts +39 -6
- package/dist/tab-bar.js +1 -1
- package/dist/tab-navigator.d.ts +86 -0
- package/dist/tab-navigator.js +95 -0
- package/dist/tab-navigator.js.map +1 -0
- package/dist/text.d.ts +63 -0
- package/dist/text.js +3 -0
- package/dist/text.js.map +1 -0
- package/dist/token-search-field.d.ts +3 -43
- package/dist/token-search-field.js +2 -1
- package/dist/token-search-model-DTcTXWMS.d.ts +154 -0
- package/dist/token-search-model.d.ts +3 -0
- package/dist/token-search-model.js +3 -0
- package/dist/token-search-model.js.map +1 -0
- package/dist/toolbar-control-group.d.ts +89 -7
- package/dist/toolbar-control-group.js +3 -1
- package/dist/toolbar-text.d.ts +45 -9
- package/dist/toolbar-text.js +2 -1
- package/dist/toolbar.d.ts +59 -7
- package/dist/toolbar.js +1 -1
- package/dist/types-C9BubXfz.d.ts +117 -0
- package/dist/value-table.d.ts +11 -3
- package/dist/value-table.js +2 -1
- package/dist/webawesome.d.ts +8 -1
- package/dist/wire-catalog.d.ts +82 -0
- package/dist/wire-catalog.js +407 -0
- package/dist/wire-catalog.js.map +1 -0
- package/dist/wire-content-items.d.ts +11 -0
- package/dist/wire-content-items.js +114 -0
- package/dist/wire-content-items.js.map +1 -0
- package/dist/wire-nav-stack.d.ts +4 -1
- package/dist/wire-nav-stack.js +191 -15
- package/dist/wire-nav-stack.js.map +1 -1
- package/dist/wire-resizable-regions.d.ts +2 -1
- package/dist/wire-resizable-regions.js +2 -1
- package/dist/wire-scroll-dividers.d.ts +72 -0
- package/dist/wire-scroll-dividers.js +3 -0
- package/dist/wire-scroll-dividers.js.map +1 -0
- package/dist/wire-sidebar.d.ts +63 -0
- package/dist/wire-sidebar.js +231 -0
- package/dist/wire-sidebar.js.map +1 -0
- package/dist/wire-tab-bars.d.ts +19 -2
- package/dist/wire-tab-bars.js +1 -1
- package/dist/wire-tab-navigator.d.ts +11 -0
- package/dist/wire-tab-navigator.js +21 -0
- package/dist/wire-tab-navigator.js.map +1 -0
- package/dist/wire-token-search-fields.d.ts +65 -3
- package/dist/wire-token-search-fields.js +2 -1
- package/dist/wire-toolbar-visibility.d.ts +13 -0
- package/dist/wire-toolbar-visibility.js +3 -0
- package/dist/wire-toolbar-visibility.js.map +1 -0
- package/dist/wire-workbench.d.ts +116 -0
- package/dist/wire-workbench.js +6 -0
- package/dist/wire-workbench.js.map +1 -0
- package/dist/workbench.d.ts +246 -9
- package/dist/workbench.js +17 -15
- package/dist/workbench.js.map +1 -1
- package/docs/accessibility.md +497 -26
- package/docs/app-layouts.md +141 -10
- package/docs/apple-hig.md +1 -0
- package/docs/catalog.md +493 -0
- package/docs/collapsible-panel.md +382 -0
- package/docs/component-contract.md +736 -61
- package/docs/component-integration.md +75 -0
- package/docs/component-selection.md +619 -97
- package/docs/design/templates/empty-state/filtered-dark.svg +1 -0
- package/docs/design/templates/empty-state/filtered.svg +1 -0
- package/docs/design/templates/empty-state/with-action-dark.svg +1 -0
- package/docs/design/templates/empty-state/with-action.svg +1 -0
- package/docs/design/templates/empty-state-dark.svg +1 -0
- package/docs/design/templates/empty-state.svg +1 -0
- package/docs/design/templates/list/compact-dark.svg +1 -0
- package/docs/design/templates/list/compact.svg +1 -0
- package/docs/design/templates/list/stack-dark.svg +1 -0
- package/docs/design/templates/list/stack.svg +1 -0
- package/docs/design/templates/list-action-row/default-dark.svg +1 -0
- package/docs/design/templates/list-action-row/default.svg +1 -0
- package/docs/design/templates/list-action-row/selected-dark.svg +1 -0
- package/docs/design/templates/list-action-row/selected.svg +1 -0
- package/docs/design/templates/list-action-row-dark.svg +1 -0
- package/docs/design/templates/list-action-row.svg +1 -0
- package/docs/design/templates/list-dark.svg +1 -0
- package/docs/design/templates/list-header/action-dark.svg +1 -0
- package/docs/design/templates/list-header/action.svg +1 -0
- package/docs/design/templates/list-header/count-dark.svg +1 -0
- package/docs/design/templates/list-header/count.svg +1 -0
- package/docs/design/templates/list-header/inline-action-dark.svg +1 -0
- package/docs/design/templates/list-header/inline-action.svg +1 -0
- package/docs/design/templates/list-header/size-l-dark.svg +1 -0
- package/docs/design/templates/list-header/size-l.svg +1 -0
- package/docs/design/templates/list-header/size-m-dark.svg +1 -0
- package/docs/design/templates/list-header/size-m.svg +1 -0
- package/docs/design/templates/list-header/size-xl-dark.svg +1 -0
- package/docs/design/templates/list-header/size-xl.svg +1 -0
- package/docs/design/templates/list-header/size-xs-dark.svg +1 -0
- package/docs/design/templates/list-header/size-xs.svg +1 -0
- package/docs/design/templates/list-header/toggle-collapsed-dark.svg +1 -0
- package/docs/design/templates/list-header/toggle-collapsed.svg +1 -0
- package/docs/design/templates/list-header/toggle-expanded-dark.svg +1 -0
- package/docs/design/templates/list-header/toggle-expanded.svg +1 -0
- package/docs/design/templates/list-header-dark.svg +1 -0
- package/docs/design/templates/list-header.svg +1 -0
- package/docs/design/templates/list-item/default-dark.svg +1 -0
- package/docs/design/templates/list-item/default.svg +1 -0
- package/docs/design/templates/list-item/multiline-dark.svg +1 -0
- package/docs/design/templates/list-item/multiline.svg +1 -0
- package/docs/design/templates/list-item/selected-dark.svg +1 -0
- package/docs/design/templates/list-item/selected.svg +1 -0
- package/docs/design/templates/list-item/trailing-dark.svg +1 -0
- package/docs/design/templates/list-item/trailing.svg +1 -0
- package/docs/design/templates/list-item-dark.svg +1 -0
- package/docs/design/templates/list-item.svg +1 -0
- package/docs/design/templates/list.svg +1 -0
- package/docs/design/templates/segmented-control/equal-dark.svg +1 -0
- package/docs/design/templates/segmented-control/equal.svg +1 -0
- package/docs/design/templates/segmented-control/pill-small-dark.svg +1 -0
- package/docs/design/templates/segmented-control/pill-small.svg +1 -0
- package/docs/design/templates/segmented-control-dark.svg +1 -0
- package/docs/design/templates/segmented-control.svg +1 -0
- package/docs/design/templates/skeleton/avatar-dark.svg +1 -0
- package/docs/design/templates/skeleton/avatar.svg +1 -0
- package/docs/design/templates/skeleton/block-dark.svg +1 -0
- package/docs/design/templates/skeleton/block.svg +1 -0
- package/docs/design/templates/skeleton/lines-dark.svg +1 -0
- package/docs/design/templates/skeleton/lines.svg +1 -0
- package/docs/design/templates/skeleton-dark.svg +1 -0
- package/docs/design/templates/skeleton.svg +1 -0
- package/docs/design/templates/state-banner/danger-dark.svg +1 -0
- package/docs/design/templates/state-banner/danger.svg +1 -0
- package/docs/design/templates/state-banner/info-badge-dark.svg +1 -0
- package/docs/design/templates/state-banner/info-badge.svg +1 -0
- package/docs/design/templates/state-banner/info-dark.svg +1 -0
- package/docs/design/templates/state-banner/info.svg +1 -0
- package/docs/design/templates/state-banner/success-dark.svg +1 -0
- package/docs/design/templates/state-banner/success.svg +1 -0
- package/docs/design/templates/state-banner/warning-dark.svg +1 -0
- package/docs/design/templates/state-banner/warning.svg +1 -0
- package/docs/design/templates/state-banner-dark.svg +1 -0
- package/docs/design/templates/state-banner.svg +1 -0
- package/docs/design/templates/tab-bar/workspace-tabs-dark.svg +1 -0
- package/docs/design/templates/tab-bar/workspace-tabs.svg +1 -0
- package/docs/design/templates/tab-bar-dark.svg +1 -0
- package/docs/design/templates/tab-bar.svg +1 -0
- package/docs/design/templates/token-search-field/empty-dark.svg +1 -0
- package/docs/design/templates/token-search-field/empty.svg +1 -0
- package/docs/design/templates/token-search-field/tokens-dark.svg +1 -0
- package/docs/design/templates/token-search-field/tokens.svg +1 -0
- package/docs/design/templates/token-search-field-dark.svg +1 -0
- package/docs/design/templates/token-search-field.svg +1 -0
- package/docs/design/templates/toolbar/title-and-actions-dark.svg +1 -0
- package/docs/design/templates/toolbar/title-and-actions.svg +1 -0
- package/docs/design/templates/toolbar/width-visibility-320-dark.svg +1 -0
- package/docs/design/templates/toolbar/width-visibility-320.svg +1 -0
- package/docs/design/templates/toolbar/width-visibility-600-dark.svg +1 -0
- package/docs/design/templates/toolbar/width-visibility-600.svg +1 -0
- package/docs/design/templates/toolbar-control-group/borderless-single-dark.svg +1 -0
- package/docs/design/templates/toolbar-control-group/borderless-single.svg +1 -0
- package/docs/design/templates/toolbar-control-group/icon-buttons-dark.svg +1 -0
- package/docs/design/templates/toolbar-control-group/icon-buttons.svg +1 -0
- package/docs/design/templates/toolbar-control-group/icon-tile-brand-dark.svg +1 -0
- package/docs/design/templates/toolbar-control-group/icon-tile-brand.svg +1 -0
- package/docs/design/templates/toolbar-control-group/icon-tile-danger-dark.svg +1 -0
- package/docs/design/templates/toolbar-control-group/icon-tile-danger.svg +1 -0
- package/docs/design/templates/toolbar-control-group/icon-tile-neutral-dark.svg +1 -0
- package/docs/design/templates/toolbar-control-group/icon-tile-neutral.svg +1 -0
- package/docs/design/templates/toolbar-control-group/icon-tile-success-dark.svg +1 -0
- package/docs/design/templates/toolbar-control-group/icon-tile-success.svg +1 -0
- package/docs/design/templates/toolbar-control-group/icon-tile-warning-dark.svg +1 -0
- package/docs/design/templates/toolbar-control-group/icon-tile-warning.svg +1 -0
- package/docs/design/templates/toolbar-control-group/push-buttons-dark.svg +1 -0
- package/docs/design/templates/toolbar-control-group/push-buttons.svg +1 -0
- package/docs/design/templates/toolbar-control-group/with-text-dark.svg +1 -0
- package/docs/design/templates/toolbar-control-group/with-text.svg +1 -0
- package/docs/design/templates/toolbar-control-group-dark.svg +1 -0
- package/docs/design/templates/toolbar-control-group.svg +1 -0
- package/docs/design/templates/toolbar-dark.svg +1 -0
- package/docs/design/templates/toolbar-text/dark-tone-dark.svg +1 -0
- package/docs/design/templates/toolbar-text/dark-tone.svg +1 -0
- package/docs/design/templates/toolbar-text/default-dark.svg +1 -0
- package/docs/design/templates/toolbar-text/default.svg +1 -0
- package/docs/design/templates/toolbar-text/large-dark.svg +1 -0
- package/docs/design/templates/toolbar-text/large.svg +1 -0
- package/docs/design/templates/toolbar-text/small-dark.svg +1 -0
- package/docs/design/templates/toolbar-text/small.svg +1 -0
- package/docs/design/templates/toolbar-text-dark.svg +1 -0
- package/docs/design/templates/toolbar-text.svg +1 -0
- package/docs/design/templates/toolbar.svg +1 -0
- package/docs/design/templates/value-table/details-dark.svg +1 -0
- package/docs/design/templates/value-table/details.svg +1 -0
- package/docs/design/templates/value-table-dark.svg +1 -0
- package/docs/design/templates/value-table.svg +1 -0
- package/docs/design/templates.md +140 -0
- package/docs/design-philosophy.md +48 -20
- package/docs/device-class.md +10 -9
- package/docs/document-baseline.md +42 -0
- package/docs/examples/application-ui-profile.json +60 -0
- package/docs/examples/command-palette-adapter.tsx +69 -17
- package/docs/examples/component-catalog-extension.json +52 -0
- package/docs/examples/component-composition-extension.json +80 -0
- package/docs/layout.md +601 -59
- package/docs/nav-stack.md +154 -14
- package/docs/recipes.md +142 -55
- package/docs/split-view.md +77 -6
- package/docs/sunken-panel.md +93 -0
- package/docs/surface-scaffold.md +74 -0
- package/docs/tab-navigator.md +210 -0
- package/docs/type-contracts.md +135 -0
- package/docs/ui-analyzer.md +404 -0
- package/docs/ui-doctor.md +202 -0
- package/docs/ui-evaluator.md +139 -0
- package/docs/ux-demo.md +46 -16
- package/docs/webawesome-theme.md +188 -16
- package/docs/workbench.md +621 -12
- package/doctor/cli.mjs +120 -0
- package/doctor/component-style-checks.mjs +457 -0
- package/doctor/config.schema.json +94 -0
- package/doctor/eslint-diagnostics.d.mts +24 -0
- package/doctor/eslint-diagnostics.mjs +24 -0
- package/doctor/index.d.mts +122 -0
- package/doctor/index.mjs +1403 -0
- package/doctor/report.schema.json +118 -0
- package/evaluator/cli.mjs +89 -0
- package/evaluator/index.d.mts +90 -0
- package/evaluator/index.mjs +1203 -0
- package/evaluator/report.schema.json +152 -0
- package/llms.txt +510 -49
- package/package.json +266 -44
- package/scripts/component-catalog-extension-validation.mjs +28 -0
- package/traversal-exclusions.mjs +27 -0
- package/ux-demo/recipes/app-shell.tsx +205 -17
- package/ux-demo/recipes/collapsible-sidebar.tsx +260 -0
- package/ux-demo/recipes/compact-toolbar.tsx +135 -14
- package/ux-demo/recipes/composer-form.tsx +133 -21
- package/ux-demo/recipes/list-detail-dialog.tsx +286 -0
- package/ux-demo/recipes/list-workspace-states.tsx +183 -11
- package/ux-demo/recipes/loaders.ts +15 -5
- package/ux-demo/recipes/loading-inspector.tsx +204 -0
- package/ux-demo/recipes/mount-recipe.ts +28 -10
- package/ux-demo/recipes/navigation-sidebar.tsx +139 -13
- package/ux-demo/recipes/navigation-stack.tsx +81 -26
- package/ux-demo/recipes/types.ts +23 -2
- package/ux-demo/recipes/workspace-header.tsx +86 -5
- package/dist/browser/menu-action-row.js +0 -4
- package/dist/browser/menu-item.js +0 -4
- package/dist/browser/panel-header.js +0 -7
- package/dist/chunk-2RJBFNB6.js +0 -172
- package/dist/chunk-2RJBFNB6.js.map +0 -1
- package/dist/chunk-2Z5TWHKQ.js +0 -34
- package/dist/chunk-2Z5TWHKQ.js.map +0 -1
- package/dist/chunk-3YD6ZNRA.js +0 -34
- package/dist/chunk-3YD6ZNRA.js.map +0 -1
- package/dist/chunk-55DATV3A.js +0 -10
- package/dist/chunk-55DATV3A.js.map +0 -1
- package/dist/chunk-56RJXPHG.js.map +0 -1
- package/dist/chunk-7BR3DO2A.js.map +0 -1
- package/dist/chunk-7LDCTU7D.js +0 -134
- package/dist/chunk-7LDCTU7D.js.map +0 -1
- package/dist/chunk-AQNKJRFH.js +0 -79
- package/dist/chunk-AQNKJRFH.js.map +0 -1
- package/dist/chunk-B24C4A6T.js +0 -22
- package/dist/chunk-B24C4A6T.js.map +0 -1
- package/dist/chunk-BLK3UEEI.js +0 -23
- package/dist/chunk-BLK3UEEI.js.map +0 -1
- package/dist/chunk-BNQ2YDV4.js +0 -20
- package/dist/chunk-BNQ2YDV4.js.map +0 -1
- package/dist/chunk-DAFFDO33.js +0 -14
- package/dist/chunk-DAFFDO33.js.map +0 -1
- package/dist/chunk-H6URQGJI.js +0 -42
- package/dist/chunk-H6URQGJI.js.map +0 -1
- package/dist/chunk-I7INRJO4.js +0 -17
- package/dist/chunk-I7INRJO4.js.map +0 -1
- package/dist/chunk-LC3YSAZC.js +0 -39
- package/dist/chunk-LC3YSAZC.js.map +0 -1
- package/dist/chunk-M5JRI6MN.js +0 -27
- package/dist/chunk-M5JRI6MN.js.map +0 -1
- package/dist/chunk-MBR3TYNL.js +0 -14
- package/dist/chunk-MBR3TYNL.js.map +0 -1
- package/dist/chunk-MFKMHK5W.js +0 -10
- package/dist/chunk-MFKMHK5W.js.map +0 -1
- package/dist/chunk-MQIZAD4A.js +0 -227
- package/dist/chunk-MQIZAD4A.js.map +0 -1
- package/dist/chunk-PONXLV5U.js +0 -19
- package/dist/chunk-PONXLV5U.js.map +0 -1
- package/dist/chunk-RUNWEPR4.js +0 -10
- package/dist/chunk-RUNWEPR4.js.map +0 -1
- package/dist/chunk-W2FK7ZNY.js +0 -26
- package/dist/chunk-W2FK7ZNY.js.map +0 -1
- package/dist/chunk-WVPYVDXY.js +0 -15
- package/dist/chunk-WVPYVDXY.js.map +0 -1
- package/dist/chunk-YGN7OMLT.js.map +0 -1
- package/dist/chunk-YKUUZPED.js +0 -24
- package/dist/chunk-YKUUZPED.js.map +0 -1
- package/dist/menu-action-row.js +0 -5
- package/dist/menu-action-row.js.map +0 -1
- package/dist/menu-header.d.ts +0 -43
- package/dist/menu-header.js +0 -7
- package/dist/menu-header.js.map +0 -1
- package/dist/menu-item.d.ts +0 -33
- package/dist/menu-item.js +0 -5
- package/dist/menu-item.js.map +0 -1
- package/dist/panel-header.d.ts +0 -36
- package/dist/panel-header.js +0 -7
- package/dist/panel-header.js.map +0 -1
- package/dist/styles/menu-action-row.css +0 -160
- package/dist/styles/menu-header.css +0 -160
- package/dist/styles/menu-item.css +0 -123
- package/dist/styles/panel-header.css +0 -64
- package/dist/styles/tab-scaffold.css +0 -84
- package/dist/tab-scaffold.d.ts +0 -30
- package/dist/tab-scaffold.js +0 -16
- package/dist/tab-scaffold.js.map +0 -1
- package/dist/wire-tab-scaffold.d.ts +0 -11
- package/dist/wire-tab-scaffold.js +0 -16
- package/dist/wire-tab-scaffold.js.map +0 -1
- package/docs/tab-scaffold.md +0 -41
- package/ux-demo/recipes/master-detail-dialog.tsx +0 -45
- package/ux-demo/recipes/recipes.css +0 -355
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
`@kerfjs/ui` components are plain functions that return Kerf `SafeHtml`. They have no component instance or lifecycle.
|
|
4
4
|
|
|
5
|
+
### Shared semantic tones
|
|
6
|
+
|
|
7
|
+
`SemanticTone` is the shared color-role type for `Badge`, `Chip`, `StateBanner`,
|
|
8
|
+
and semantic `ContentItem` appearances: `neutral`, `info`, `pop`, `success`,
|
|
9
|
+
`warning`, and `danger`. Import it as a type from `@kerfjs/ui`,
|
|
10
|
+
`@kerfjs/ui/badge`, `@kerfjs/ui/state-banner`, or `@kerfjs/ui/content-item`.
|
|
11
|
+
Use `info` for the role backed by the existing `--kui-color-brand-*` tokens.
|
|
12
|
+
Migrate Badge/Chip `tone="brand"` to `tone="info"`; `BadgeTone` and
|
|
13
|
+
`StateBannerTone` remain deprecated aliases of `SemanticTone`.
|
|
14
|
+
|
|
5
15
|
## Selection boundary
|
|
6
16
|
|
|
7
17
|
Begin with the [need-first component matrix](./component-selection.md). Reuse a
|
|
@@ -18,25 +28,277 @@ package delivery paths, Web Awesome's installed manifest, AI guidance, and
|
|
|
18
28
|
documentation links. Nuanced prose in this contract and the selection guide
|
|
19
29
|
remains authored rather than generated.
|
|
20
30
|
|
|
31
|
+
### Markdown component reference (AI entry point)
|
|
32
|
+
|
|
33
|
+
[`ai/components/README.md`](../ai/components/README.md) and one
|
|
34
|
+
`ai/components/<id>.md` page per catalog entry are the assistant-facing view of
|
|
35
|
+
both catalogs. An assistant reads the index, then only the pages it uses,
|
|
36
|
+
instead of loading the full JSON. Each page merges the entry's selection facts
|
|
37
|
+
(purpose, use/avoid, alternatives), delivery (JavaScript subpath, CSS,
|
|
38
|
+
registration, wiring helpers), a link into `public-api-signatures-v1.md` for
|
|
39
|
+
exact props, composition (parents, contexts, zones with their JSX prop and
|
|
40
|
+
cardinality, children), state and wiring ownership including wiring-owned
|
|
41
|
+
state attributes, geometry, accessibility obligations, public class and token
|
|
42
|
+
hooks framed as a styling boundary (components own their styles; configure
|
|
43
|
+
through props rather than overriding internals), and `KUI-C###` diagnostics
|
|
44
|
+
with their conditions. `scripts/sync-component-docs.mjs` renders them only from
|
|
45
|
+
`component-catalog.json` and `component-composition.json` (plus the signature
|
|
46
|
+
file's module headings for anchors), sorted and Prettier-formatted;
|
|
47
|
+
`check:catalog` rejects a stale, missing, or orphaned page. The JSON files stay
|
|
48
|
+
the canonical tool-facing sources.
|
|
49
|
+
|
|
50
|
+
### Composition catalog
|
|
51
|
+
|
|
52
|
+
[`component-composition.json`](../ai/component-composition.json) adds a formal,
|
|
53
|
+
machine-evaluable composition layer beside `component-catalog.json` without
|
|
54
|
+
changing its selection and delivery contract; it is a generated companion, not
|
|
55
|
+
a newer version of that catalog. Every component-catalog entry projects once,
|
|
56
|
+
in order, under the stable qualified key `package:id`. Each composition entry
|
|
57
|
+
explicitly covers parents/contexts,
|
|
58
|
+
named zones and cardinality, optional explicit JSX prop bindings, child concepts, state ownership, required wiring,
|
|
59
|
+
responsive ownership, layout and geometry, accessibility obligations, public
|
|
60
|
+
CSS boundaries, diagnostics, and provenance. A wrapper entry may add
|
|
61
|
+
`rendersAs`: the cataloged roots it renders (any one of them, or nothing), so
|
|
62
|
+
composition checks treat its elements as each root rather than as an unknown
|
|
63
|
+
child. A placement with listed parent constraints produces one `KUI-L201`
|
|
64
|
+
diagnostic even when both the wrapper and a rendered root reject that parent.
|
|
65
|
+
When one catalog entry exports another JSX component with different placement,
|
|
66
|
+
`jsxExports` gives that export its own parent contract. The extra export does
|
|
67
|
+
not stand for the entry's root when a parent zone is checked.
|
|
68
|
+
Generated `boundaries.rootClass` prefers the public `kui-<entry-id>` class when
|
|
69
|
+
present, so a sibling export's class cannot become the entry's root class.
|
|
70
|
+
|
|
71
|
+
`boundaries.placeableClasses` names the subset of `publicClasses` an
|
|
72
|
+
application may write onto its own elements (layout utilities, the document
|
|
73
|
+
root, item geometry on another carrier); absent means none, and every other
|
|
74
|
+
public class is the component's rendered anatomy. `boundaries.rootElement`
|
|
75
|
+
names the element a component renders around its own placeable classes
|
|
76
|
+
(`content-item`: `div`), so a plain element of that tag carrying them is still
|
|
77
|
+
the component recreated. `eslint-plugin-kerfjs`'s `ui-public-boundaries`
|
|
78
|
+
reports both as `KUI-L103` with the export to render — for `@kerfjs/ui` and for
|
|
79
|
+
every consumer catalog a `.kerf-ui-profile.json` declares, whatever the class
|
|
80
|
+
prefix. `create-kerf-component` packages declare the same fields in
|
|
81
|
+
`kerf.components.json`.
|
|
82
|
+
|
|
83
|
+
`descendantRootAttribute` optionally names a `data-*` attribute on a
|
|
84
|
+
cataloged `rootElement`. It anchors ownership of arbitrary unclassed child
|
|
85
|
+
element selectors below that exact root, as `LucideIcon` does with
|
|
86
|
+
`svg[data-lucide]`. Without the attribute in a selector, the analyzer uses
|
|
87
|
+
only cataloged `descendantElements` and composed JSX evidence.
|
|
88
|
+
|
|
89
|
+
An entry's optional `cssValueProps` makes CSS-adjacent prop grammar equally
|
|
90
|
+
machine-evaluable. Each path records the property grammar, finite shorthands,
|
|
91
|
+
canonical versus exceptional spacing choices, standalone and expression-only
|
|
92
|
+
helpers, raw/unsafe policy, and serialization examples. Nested paths use the
|
|
93
|
+
bounded `items[].property` form. Consumer catalogs can publish the same facts;
|
|
94
|
+
ESLint, `kerf-ui-analyze`, and `kerf-ui-doctor` then issue the same stable
|
|
95
|
+
`KUI-L013`–`KUI-L017` feedback for application and third-party components.
|
|
96
|
+
|
|
97
|
+
`wiring.stateAttributes` lists the **wiring-owned state attributes**: the
|
|
98
|
+
`data-*` attributes a wiring helper writes at runtime, such as
|
|
99
|
+
`data-handle-inset` and `data-resizing`, which `wireResizableRegions` puts on a
|
|
100
|
+
`ResizableRegion`. Each entry names the attribute, the element that carries it
|
|
101
|
+
(`on`), the `helper` that writes it, and what it means. An application must not
|
|
102
|
+
render, remove, or treat these attributes as its own state; tools use the list
|
|
103
|
+
to tell them apart from app-authored attributes. They are declared once, on the
|
|
104
|
+
helper's wiring item in the component catalog, and the composition catalog
|
|
105
|
+
flattens them. `check:catalog`
|
|
106
|
+
reads each `wire*` helper's source and fails when its declarations differ from
|
|
107
|
+
the `data-*` attributes it actually writes. First-party entries always carry
|
|
108
|
+
the list, empty when their helpers write none; it is optional in extension
|
|
109
|
+
catalogs.
|
|
110
|
+
|
|
111
|
+
An extension catalog may add `wiring.sources` entries with `export` and
|
|
112
|
+
`source` for each application-owned helper. The source path is relative to its
|
|
113
|
+
package root; `ui-wiring` resolves helper imports through this file, including
|
|
114
|
+
relative re-export barrels. Every named export must also appear in
|
|
115
|
+
`wiring.helpers`.
|
|
116
|
+
|
|
117
|
+
The selection catalog's `wiringProviders` lists public helpers that install
|
|
118
|
+
other wiring helpers. The `ui-wiring` rule accepts a provider call for each
|
|
119
|
+
helper it declares; `wireCatalog` provides `wireScrollDividers`.
|
|
120
|
+
|
|
121
|
+
The generator starts with permissive defaults. An `any` mode records that the
|
|
122
|
+
catalog has no defensible prohibition; it does not claim every composition is
|
|
123
|
+
recommended. Objective rules live in
|
|
124
|
+
`component-composition-rules.json` and may carry stable `KUI-C###`
|
|
125
|
+
diagnostics. A tool reports a diagnostic only after proving its exact `when`
|
|
126
|
+
condition. Subjective choice, product policy, and visual taste remain prose.
|
|
127
|
+
|
|
128
|
+
Kerf UI calls component content positions **named `SafeHtml` prop slots**.
|
|
129
|
+
Use `children` for one homogeneous primary region; use explicit named
|
|
130
|
+
`SafeHtml` props for semantic positions or replacement content such as
|
|
131
|
+
`header`, `footer`, `leading`, `trailing`, `icon`, and `action`. These are typed
|
|
132
|
+
function-component props, not native web-component `<slot>` elements and not a
|
|
133
|
+
generic `slots={{...}}` object. A composition zone declares `jsx.prop` only when tooling
|
|
134
|
+
can soundly bind that zone to one public JSX prop; `children` is spelled
|
|
135
|
+
explicitly. Zones without that binding remain guidance and are never guessed
|
|
136
|
+
from their ids. Static tools inspect only visible JSX structure and leave
|
|
137
|
+
dynamic `SafeHtml` expressions to runtime and accessibility evaluation.
|
|
138
|
+
|
|
139
|
+
### Native named-slot assignment
|
|
140
|
+
|
|
141
|
+
Every public visual component with one stable conceptual root accepts an
|
|
142
|
+
explicit `slot?: string` prop and forwards it to that root on every render
|
|
143
|
+
branch. Use it when a Kerf component is a light-DOM child of a custom element,
|
|
144
|
+
for example `StateBanner({ title: 'Ready', slot: 'status' })`. Omitting the prop
|
|
145
|
+
omits the attribute.
|
|
146
|
+
|
|
147
|
+
This contract does not open a generic native-attribute bag: components still
|
|
148
|
+
accept only their documented props and narrow extension-attribute objects.
|
|
149
|
+
`ResizableRegion` and `CollapsiblePanel` are deliberately excluded because each
|
|
150
|
+
can return a region plus a sibling restore control, leaving no single root that
|
|
151
|
+
can truthfully own native slot assignment. Their single-root controls and all
|
|
152
|
+
alternate-root branches of supported components retain the contract.
|
|
153
|
+
|
|
154
|
+
Component-catalog consumers continue unchanged. Composition-aware consumers
|
|
155
|
+
read `component-catalog.json` for selection/delivery and
|
|
156
|
+
`component-composition.json` for composition. `npm run catalog:sync` projects every new component,
|
|
157
|
+
recipe, and supported Web Awesome entry, and the completeness gate prevents
|
|
158
|
+
silent omissions. Downstream catalogs use the composition extension schema and types,
|
|
159
|
+
retain their own package identity, and qualify cross-catalog references. See
|
|
160
|
+
the checked
|
|
161
|
+
[`component-composition-extension.json`](./examples/component-composition-extension.json)
|
|
162
|
+
application-owned example.
|
|
163
|
+
|
|
164
|
+
### Compile-time contract boundary
|
|
165
|
+
|
|
166
|
+
The versioned
|
|
167
|
+
[`compile-time-contracts-v1.json`](../ai/compile-time-contracts-v1.json)
|
|
168
|
+
artifact maps stable `KUI-T###` ids to public imports, emitted symbols, and
|
|
169
|
+
catalog identities. Its positive/negative fixture compiles against both source
|
|
170
|
+
and a freshly packed package, so source declarations and shipped declarations
|
|
171
|
+
cannot silently diverge. See [Compile-time contracts](./type-contracts.md) for
|
|
172
|
+
the full audit, migration guidance, and the relationships deliberately left to
|
|
173
|
+
runtime/catalog checks because TypeScript cannot prove them.
|
|
174
|
+
|
|
175
|
+
### Application UI profile
|
|
176
|
+
|
|
177
|
+
The component catalogs describe what packages provide; an application profile
|
|
178
|
+
describes which supported choices a project has approved. A workspace may
|
|
179
|
+
check in `.kerf-ui-profile.json` conforming to
|
|
180
|
+
[`application-ui-profile.schema.json`](../ai/application-ui-profile.schema.json).
|
|
181
|
+
Keep package-qualified catalog locations and recurring-concept preferences,
|
|
182
|
+
allowed color schemes and density, public semantic-token overrides,
|
|
183
|
+
layout/responsive conventions, application wiring entry paths, and narrow rule exceptions there. Product
|
|
184
|
+
records, copy, permissions, user preferences, and transport state do not belong
|
|
185
|
+
in this policy file.
|
|
186
|
+
|
|
187
|
+
Every catalog location names a composition artifact. `selection` is optional
|
|
188
|
+
for consumer packages whose generated metadata declares component-catalog
|
|
189
|
+
selection guidance not applicable; `@kerfjs/ui` retains its required
|
|
190
|
+
`component-catalog.json` selection artifact. This
|
|
191
|
+
lets a generated `component-composition.json` participate directly without a
|
|
192
|
+
fabricated compatibility file.
|
|
193
|
+
|
|
194
|
+
Discovery and precedence are deterministic:
|
|
195
|
+
|
|
196
|
+
1. Load `application-ui-profile.defaults.json` from `@kerfjs/ui`.
|
|
197
|
+
2. Load `.kerf-ui-profile.json` at the workspace root when present.
|
|
198
|
+
3. Walk from the workspace root toward the target directory and load each
|
|
199
|
+
directory-local profile in parent-to-child order.
|
|
200
|
+
|
|
201
|
+
Later scalar and object-map values win. Catalogs merge by package; preferences
|
|
202
|
+
and token overrides merge by key; exceptions merge by stable id. Lists such as
|
|
203
|
+
allowed themes/densities replace the earlier list rather than accumulating.
|
|
204
|
+
`wiring.entries` similarly names workspace-relative application entry modules;
|
|
205
|
+
later profile layers replace the entry list. The `ui-wiring` ESLint rule checks
|
|
206
|
+
application-scoped helper calls and registration imports once at each entry
|
|
207
|
+
that reaches a rendering module, while a composition entry with
|
|
208
|
+
`wiring.scope: "module"` keeps a local obligation. See the
|
|
209
|
+
[`ui-wiring` rule](../../eslint-plugin/docs/rules/ui-wiring.md).
|
|
210
|
+
Every resolved field retains its source file. The shipped
|
|
211
|
+
`application-ui-profile.mjs` API implements discovery, merge, loading, and
|
|
212
|
+
validation and reports actionable originating file + JSON-path diagnostics for stale
|
|
213
|
+
catalogs, unknown component/rule/token references, preference conflicts, and
|
|
214
|
+
broad exceptions. Each raw layer is validated against the catalogs effective at
|
|
215
|
+
that exact precedence point before merge, so a broken parent catalog, stale
|
|
216
|
+
parent reference, invalid value, or unknown field cannot disappear merely
|
|
217
|
+
because a child profile replaces it. The shipped
|
|
218
|
+
`application-ui-profile-sync.cjs` projects the same merge and validation contract
|
|
219
|
+
for synchronous hosts such as ESLint rules; it deliberately performs no async
|
|
220
|
+
I/O.
|
|
221
|
+
See the
|
|
222
|
+
[`application-ui-profile.json`](./examples/application-ui-profile.json) example.
|
|
223
|
+
|
|
224
|
+
The package defaults avoid every `Discouraged` Web Awesome entry — each
|
|
225
|
+
`webawesome` catalog entry whose `recommendation` is not `supported`, except the
|
|
226
|
+
encouraged `wa-popup` primitive — under a concept whose `preferred` value is the
|
|
227
|
+
Kerf component that wraps or replaces it (`command-menu` → `PopupMenu`,
|
|
228
|
+
`value-selection` → `Select`, `application-tabs` → `TabBar`, `icon` →
|
|
229
|
+
`LucideIcon`, `resizable-pane` → `ResizableRegion`, `exclusive-choice` →
|
|
230
|
+
`SegmentedControl`, `hierarchy-navigation` → `List`, `embedded-media` →
|
|
231
|
+
`ContentItem`). `eslint-plugin-kerfjs` `ui-preferences` (`KUI-L301`, also run by
|
|
232
|
+
`kerf-ui-doctor`) therefore reports a Discouraged element written directly as a
|
|
233
|
+
JSX tag (`<wa-dropdown>`) as well as through an imported component. A declared
|
|
234
|
+
component's own source file is exempt, because that wrapper is the sanctioned
|
|
235
|
+
owner of the element it renders. A unit test holds the avoid set and the
|
|
236
|
+
catalog's Discouraged set equal in both directions, so neither can drift. A
|
|
237
|
+
product that genuinely needs one of these elements records a narrow `KUI-L301`
|
|
238
|
+
profile exception for the file that renders it.
|
|
239
|
+
|
|
240
|
+
Catalog detail footers use one standard resource vocabulary and order. Build
|
|
241
|
+
them with `catalogResources()` from `@kerfjs/ui/catalog-resources`: `Demo source`
|
|
242
|
+
first, optional `Component source` and `Design template`, then `Guidance`.
|
|
243
|
+
Third-party entries use the typed `integrationGuidance` kind, which renders
|
|
244
|
+
`Integration guidance`, and omit `Component source` when the implementation is
|
|
245
|
+
not owned by the catalog's project. Prefer these semantic kinds over local labels
|
|
246
|
+
such as “View source” or “Read UI guidance”; the helper makes that convention a
|
|
247
|
+
compile-time choice while still returning ordinary `CatalogResource[]` values.
|
|
248
|
+
|
|
21
249
|
## Ownership boundaries
|
|
22
250
|
|
|
23
|
-
|
|
251
|
+
### Geometry ownership metadata
|
|
252
|
+
|
|
253
|
+
The canonical [`component-catalog.json`](../ai/component-catalog.json) records
|
|
254
|
+
the margin, border, and padding owner for every component and composition under
|
|
255
|
+
`geometry`. Read it before adding a wrapper or local spacing rule:
|
|
256
|
+
|
|
257
|
+
- `self` means the entry's public visual contract supplies that geometry.
|
|
258
|
+
- `parent` means the embedding layout must supply it.
|
|
259
|
+
- `child` means composed descendants supply it; the entry's outer shell does not.
|
|
260
|
+
- `none` means that dimension is intentionally absent from the standard contract.
|
|
261
|
+
- `conditional` means a variant, part, or configuration changes ownership; the
|
|
262
|
+
accompanying `notes` explain the boundary.
|
|
263
|
+
|
|
264
|
+
The values describe public ownership, including themed shadow parts, rather
|
|
265
|
+
than merely asking whether a CSS declaration appears on the host element.
|
|
266
|
+
Recipes are exempt because they arrange entries whose individual ownership is
|
|
267
|
+
already cataloged.
|
|
268
|
+
|
|
269
|
+
Downstream packages and applications should publish the same contract for their
|
|
270
|
+
reusable visual components. Use
|
|
271
|
+
[`component-catalog-extension.schema.json`](../ai/component-catalog-extension.schema.json)
|
|
272
|
+
and copy the structure of the checked
|
|
273
|
+
[`component-catalog-extension.json`](./examples/component-catalog-extension.json)
|
|
274
|
+
example. Keep app and Kerf entries as package-qualified inputs, then let people
|
|
275
|
+
or AI tools search their combined entries and compare `geometry` before adding
|
|
276
|
+
wrappers or insets. Do not add app-owned entries to Kerf's canonical catalog or
|
|
277
|
+
claim Kerf delivery paths for them.
|
|
278
|
+
Extension entries may add `uses` for direct composition dependencies and
|
|
279
|
+
repository-relative `source` and `demoSource` files. Resolve each dependency
|
|
280
|
+
against the combined Kerf and consumer catalogs; do not duplicate a Kerf id.
|
|
281
|
+
For Doctor's opt-in component ownership mode, add `styleSources` with the CSS
|
|
282
|
+
paths each entry owns, relative to the consumer package root.
|
|
283
|
+
|
|
284
|
+
- Components own semantic markup, stable anatomy, documented variants, ARIA projection, and package CSS hooks. They may render and style raw HTML or Web Awesome implementation elements they create and control. A nested Kerf or application component remains its own owner even when the parent renders it.
|
|
24
285
|
- Applications own signals/stores, product copy, domain-state mapping, persistence, routing, permissions, and transport.
|
|
25
286
|
- Actions are `data-action` strings. Wire them at a stable root with `delegate()` or `delegateActions()` and retain the disposer.
|
|
26
287
|
- A reusable component never owns per-instance mutable module state.
|
|
27
|
-
- Consumers
|
|
288
|
+
- Consumers configure presentation through component props and documented `--kui-*` semantic tokens. Foundation tokens provide opinionated neutral, brand/info, non-status pop, success, warning, and danger fill/border/foreground roles. Application stylesheets must not select package component classes or descendants. If genuinely new structure needs CSS, encapsulate that structure and its stylesheet in an application-owned component; configure any nested Kerf components through their public APIs. A thin composition that only connects other components should normally have no stylesheet. It may style only raw elements or layout it owns, never its component children.
|
|
28
289
|
|
|
29
|
-
`
|
|
30
|
-
`
|
|
290
|
+
`ListItem.rootAttributes`, `ListActionRow.rootAttributes`,
|
|
291
|
+
`ListHeader.rootAttributes`, `AppTab.rootAttributes`,
|
|
292
|
+
`CatalogExample.rootAttributes`, and `CatalogExampleStack.rootAttributes` accept
|
|
31
293
|
application-owned `data-*` metadata without
|
|
32
|
-
adding product fields to the shared API. A `
|
|
33
|
-
`trailingActionAttributes`, and a `
|
|
294
|
+
adding product fields to the shared API. A `ListActionRow` trailing action uses
|
|
295
|
+
`trailingActionAttributes`, and a `ListHeader` action/disclosure uses
|
|
34
296
|
`triggerAttributes`, for `data-*`, native popover target/action attributes, and
|
|
35
297
|
the corresponding `aria-controls`/`aria-haspopup` relationship. These slots do
|
|
36
298
|
not accept roles or component-owned action, selection, disclosure, accessible
|
|
37
299
|
name, disabled, or icon fields. Extension objects are filtered at runtime,
|
|
38
300
|
including case-insensitive rejection of protected `data-*` names, and the
|
|
39
|
-
component writes its protected attributes after the accepted metadata. Typed,
|
|
301
|
+
component or helper writes its protected attributes after the accepted metadata. Typed,
|
|
40
302
|
structurally widened, and JavaScript callers therefore cannot replace its
|
|
41
303
|
contract.
|
|
42
304
|
|
|
@@ -46,89 +308,347 @@ component continues to own the named close button or focusable separator, and
|
|
|
46
308
|
`wireTabBars()` / `wireResizableRegions()` continue to own transient behavior
|
|
47
309
|
and disposal.
|
|
48
310
|
|
|
49
|
-
`
|
|
50
|
-
`
|
|
311
|
+
`ListItem.trailing`, `ListActionRow.label`, `ListActionRow.icon`, and
|
|
312
|
+
`ListActionRow.trailingActionIcon` are dormant SafeHtml slots. They must not
|
|
51
313
|
contain controls. When a row needs an independently interactive trailing
|
|
52
|
-
region, `
|
|
314
|
+
region, `ListActionRow` owns the noninteractive root and the two sibling native
|
|
53
315
|
buttons; the application owns their delegated behavior and controlled state.
|
|
54
316
|
Both row components align a leading icon with the first label line when
|
|
55
317
|
`multiline` allows the label to wrap; additional lines extend below that fixed
|
|
56
318
|
visual anchor.
|
|
57
319
|
|
|
320
|
+
`ToolbarControlGroup.tileTone` selects `neutral`, `brand`, `success`, `warning`, or `danger` quiet fill, matching quiet border, and on-quiet foreground for a non-interactive icon tile. Compose a contained `single` group whose only child is a direct decorative LucideIcon (`aria-hidden="true"`). Omission preserves the normal group palette. The prop does not recolor interactive, mixed, multi-control, or borderless groups; keep real actions in controls with their existing focus/hover/pressed treatments.
|
|
321
|
+
|
|
58
322
|
### Public CSS anatomy
|
|
59
323
|
|
|
60
324
|
The `publicClasses` array on each entry in
|
|
61
|
-
[`component-catalog.json`](../ai/component-catalog.json)
|
|
62
|
-
anatomy
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
`
|
|
75
|
-
|
|
76
|
-
|
|
325
|
+
[`component-catalog.json`](../ai/component-catalog.json) identifies stable
|
|
326
|
+
anatomy for diagnostics, tooling, browser assertions, and package-owned
|
|
327
|
+
composition. It is not an application customization API. Applications choose
|
|
328
|
+
documented props and tokens; package components may compose other components
|
|
329
|
+
only through those public contracts, never by styling a child's classes from a
|
|
330
|
+
parent stylesheet.
|
|
331
|
+
|
|
332
|
+
Inside the package, a component never styles another component or writes
|
|
333
|
+
another component's variables. When a child must adapt to a composing parent,
|
|
334
|
+
the child styles itself in that context from its own stylesheet: the parent's
|
|
335
|
+
class and state appear only in an ancestor compound, the styled compound is
|
|
336
|
+
the child's own class (or one of the child's own unclassed internals below
|
|
337
|
+
it), and the child reads context values the parent provides under the
|
|
338
|
+
parent's name. `ResizableRegion` widens its edge extent by the unsafe inset a
|
|
339
|
+
split `SplitView` provides, and a `Skeleton` derives its fill from a solid
|
|
340
|
+
`Badge`'s on-solid color, both in their own stylesheets; an `AppTab` rounds its
|
|
341
|
+
outer corners in a segmented `TabBar` and shares a fill-allocated strip from
|
|
342
|
+
`app-tab.css`. A `PopupMenu` sizes
|
|
343
|
+
its trigger and applies a group's `menuInset` in its own stylesheet, and an
|
|
344
|
+
icon-only `Select` reads the control slot a `ToolbarControlGroup` provides
|
|
345
|
+
(`--_kui-toolbar-control-group-slot-*`). A parent may still style its own
|
|
346
|
+
elements keyed on a child's state, naming the child by class inside `:has()`
|
|
347
|
+
(`:has(> .kui-select[open])`, or `TabBar` insetting a segmented strip that
|
|
348
|
+
holds compact tabs), and it keeps styling raw native and raw Web
|
|
349
|
+
Awesome children no kerf component owns, excluding kerf children by class
|
|
350
|
+
(`wa-dropdown:not(.kui-popup-menu)`). `npm run check:css-ownership` enforces
|
|
351
|
+
this in every component stylesheet (a same-basename `.css` and `.tsx` pair
|
|
352
|
+
under `src/components/<family>/<component>/`), deriving the component names,
|
|
353
|
+
the Web Awesome tags each component renders, and its composed children from the
|
|
354
|
+
colocated component source:
|
|
355
|
+
|
|
356
|
+
- **Foreign classes.** Another component's class or `[data-component]` may
|
|
357
|
+
appear only in an ancestor compound or inside `:has()` / `:not()`; the
|
|
358
|
+
styled compound is the stylesheet's own class.
|
|
359
|
+
- **Owned Web Awesome tags.** Kerf components are named by class, never by a
|
|
360
|
+
`wa-*` tag they render. A tag another component renders (`wa-dropdown`,
|
|
361
|
+
`wa-select`, `wa-option`, a `PopupMenu`'s trigger `wa-button`) — as the
|
|
362
|
+
subject, or as an ancestor whose internals the rule reaches — must be scoped
|
|
363
|
+
to that component by its class or excluded with `:not()`. A direct child
|
|
364
|
+
that cannot be the owner's internal
|
|
365
|
+
(`.kui-toolbar-control-group > wa-button`) needs no exclusion.
|
|
366
|
+
- **Variables.** A stylesheet writes only its own `--_kui-<self>-*` private
|
|
367
|
+
variables, and never overrides a public `--kui-<other>-*` token that another
|
|
368
|
+
component reads. Shared foundation tokens (`--kui-layout-*`,
|
|
369
|
+
`--kui-color-*`, …) are not any one component's. Context a parent provides
|
|
370
|
+
is named after the parent.
|
|
371
|
+
- **Context on any child.** Custom properties set on a subject that can be any
|
|
372
|
+
element (`.kui-x > *`, `> :not(…)`) also land on composed components' roots.
|
|
373
|
+
- **Hook classes.** A class the component places on a composed kerf child's
|
|
374
|
+
root (`<ToolbarText className="kui-nav-stack__title">`, a class NavStack once styled) may not be styled;
|
|
375
|
+
the child styles itself in that context instead.
|
|
376
|
+
|
|
377
|
+
The documented exceptions live with their reasons in
|
|
378
|
+
`scripts/lib/css-ownership.mjs`, and an exception that stops matching fails the
|
|
379
|
+
check, so the list only shrinks. The layout regions' inherited edge-inset
|
|
380
|
+
context (`--kui-edge-inset-*` handed to a sole Pane or layout child and cleared
|
|
381
|
+
for any other content, and a Toolbar clearing it for its zones) is the one
|
|
382
|
+
design exception; the others name the open fix ticket.
|
|
383
|
+
|
|
384
|
+
Applications and component packages built on the package follow the same
|
|
385
|
+
rules, and the downstream tools enforce them against the composition catalog
|
|
386
|
+
instead of package source: `kerf-ui-analyze` / `kerf-ui-doctor` report a rule
|
|
387
|
+
whose subject is another package's component (`KUI-L019`), another
|
|
388
|
+
component's private `--_*` variable (`KUI-L020`), an override of a token a
|
|
389
|
+
typed prop sets (`KUI-L021`), and a hook class on a component's root
|
|
390
|
+
(`KUI-L022`), plus borrowed public classes in source markup (`KUI-L023`);
|
|
391
|
+
`eslint-plugin-kerfjs`'s `ui-component-ownership` reports
|
|
392
|
+
`KUI-L020` / `KUI-L021` in script. Both share the selector parsing in
|
|
393
|
+
`analyzer/selectors.mjs` with `check:css-ownership`, and
|
|
394
|
+
`check:css-ownership` fails when a component renders a Web Awesome tag the
|
|
395
|
+
catalog does not list, so `KUI-L019` keeps covering every tag a kerf component
|
|
396
|
+
renders. Each finding names the configuration to use and routes a missing
|
|
397
|
+
prop to a component-gap report (see [the analyzer guide](./ui-analyzer.md#component-ownership-kui-l019kui-l023)).
|
|
398
|
+
|
|
399
|
+
The composition catalog additionally requires `boundaries.rootClass` to be
|
|
400
|
+
either one exact member of `publicClasses` or `null` when the entry has no
|
|
401
|
+
rendered class root. Runtime geometry tooling uses this explicit field; array
|
|
402
|
+
order never implies root ownership.
|
|
403
|
+
|
|
404
|
+
Do not select a component root or descendant by class, element name, id, or
|
|
405
|
+
attribute. Selectors such as `.workspace .kui-toolbar`,
|
|
406
|
+
`.kui-state-banner span`, and `.kui-list-item [data-state]` cross the ownership
|
|
407
|
+
boundary. If no prop or token expresses a recurring need, add the configuration
|
|
408
|
+
to the owning component instead of inferring it from rendered markup.
|
|
409
|
+
|
|
410
|
+
`Badge` owns the complete visual treatment for compact status, count, category,
|
|
411
|
+
and metadata labels. Configure its semantic `tone`, `appearance`, `shape`, and
|
|
412
|
+
`size`; do not recreate or override badge anatomy in an application or consuming
|
|
413
|
+
component. Use `label` when visible content is abbreviated and `ariaHidden` only
|
|
414
|
+
when a surrounding component already includes the same value in its accessible name.
|
|
415
|
+
Every tone's text and solid fill use that tone's `--kui-color-{tone}-on-fill`
|
|
416
|
+
token (`neutral` uses the text colors), the foreground tuned to clear WCAG AA
|
|
417
|
+
(4.5:1) on the tone's fills in light and dark mode.
|
|
418
|
+
|
|
419
|
+
`ListItem` renders its leading icon and nested SVG at a root-scaled 18px by
|
|
420
|
+
default while retaining the row's 44px minimum interactive target. Multiline
|
|
421
|
+
rows align that 18px visual with the first inherited text line. The row clips
|
|
422
|
+
descendant painting to its rounded root so labels, status, and dormant trailing
|
|
423
|
+
content cannot escape its visible boundary. Rows with descriptions grow enough
|
|
424
|
+
to keep their owned two-line label stack readable; use `multiline` when the
|
|
425
|
+
primary label should wrap rather than truncate. A single-line row ends its
|
|
426
|
+
primary label and description with an ellipsis before the trailing status
|
|
427
|
+
slot, even when the label is one long word; a `multiline` row wraps instead,
|
|
428
|
+
breaking a word wider than the label column (a long component or file name)
|
|
429
|
+
rather than letting it run under the trailing slot. A string label in a
|
|
430
|
+
`multiline` row gets line-break opportunities at its camelCase and acronym
|
|
431
|
+
boundaries, so `QuickTicketComposer` wraps as `QuickTicket` / `Composer`
|
|
432
|
+
rather than mid-word; breaking anywhere is only the last resort for a single
|
|
433
|
+
word that is still too wide. The text and accessible name are unchanged. `ListActionRow` labels
|
|
434
|
+
follow the same single-line and `multiline` rules before the trailing action.
|
|
435
|
+
|
|
436
|
+
`DisclosureArrow` uses an 18px root-scaled visual by default. Pass its typed
|
|
437
|
+
`size` prop when a consumer needs another size. Kerf `Select` uses a separate Web Awesome expand
|
|
77
438
|
glyph contract, `--kui-disclosure-icon-scale: .5`; changing one contract does
|
|
78
439
|
not implicitly change the other. Direction changes take the shortest rotation
|
|
79
440
|
path; a 180-degree closed-to-open tie uses counterclockwise rotation.
|
|
80
441
|
|
|
81
|
-
In `
|
|
442
|
+
In `ListHeader` toggle mode, omitting `actionIcon` composes the production
|
|
82
443
|
`DisclosureArrow` and derives its visual direction from `expanded`. The app
|
|
83
444
|
must update that controlled state and reveal or hide real content. Passing a
|
|
84
445
|
custom `actionIcon` replaces the default rather than layering or rotating both.
|
|
85
|
-
The root fills the available inline width after its standard margins
|
|
86
|
-
|
|
87
|
-
|
|
446
|
+
The root fills the available inline width after its standard margins by
|
|
447
|
+
default. Set `inline` when it must shrink-wrap beside surrounding content; that
|
|
448
|
+
presentation removes the root margin, border, and padding while retaining the
|
|
449
|
+
title and optional action's own control geometry. A separate action stays at
|
|
450
|
+
the logical end while the visible glyph defaults to 18px through
|
|
451
|
+
`--kui-list-header-action-icon-size`.
|
|
88
452
|
|
|
89
453
|
`StateBanner` exposes instance-level `--kui-state-banner-background`,
|
|
90
454
|
`--kui-state-banner-border`, `--kui-state-banner-foreground`,
|
|
91
|
-
`--kui-state-banner-detail
|
|
455
|
+
`--kui-state-banner-detail` and action background variables. Its optional
|
|
456
|
+
badge composes `Badge` beside the title and follows the banner tone by default. The
|
|
457
|
+
title, badge, and detail flow as inline text: a wrapping title keeps the badge one item
|
|
458
|
+
gap after its last word, and a detail that does not fit whole beside them moves to its
|
|
459
|
+
own line and truncates at the full copy width (below 576px it always takes its own
|
|
460
|
+
line). The title and detail both use the tone's `--kui-color-{tone}-on-fill`
|
|
461
|
+
foreground (`info` uses `brand`) at full strength, clearing WCAG AA over the tone's fill in light and dark
|
|
462
|
+
mode; the detail reads as secondary through its smaller, regular-weight type, and
|
|
463
|
+
only the neutral tone quiets it, to `--kui-color-neutral-on-quiet`. Its five built-in
|
|
92
464
|
tones can be rethemed globally with
|
|
93
465
|
`--kui-state-banner-{tone}-{background|border|foreground}`. Toolbar control,
|
|
94
466
|
segmented-control, app-tab, and tab-bar colors likewise use their public
|
|
95
467
|
`--kui-*-*` variables. `SegmentedControl` exposes surface, border, foreground,
|
|
96
468
|
hover, and selected-state variables, so rounded, pill, and toolbar presentations
|
|
97
|
-
remain opinionated but locally overridable.
|
|
469
|
+
remain opinionated but locally overridable. Its label color switches with the
|
|
470
|
+
theme without Web Awesome's native button color transition, so a dark filled
|
|
471
|
+
track never briefly pairs with an interpolated low-contrast label.
|
|
472
|
+
|
|
473
|
+
Inset hover and selection surfaces follow the outer control shape instead of
|
|
474
|
+
choosing an independent radius. `--kui-layout-highlight-inset` is the full
|
|
475
|
+
distance between those edges; the inner radius is the outer radius minus that
|
|
476
|
+
inset. `ToolbarControlGroup` publishes its derived radius to nested toolbar
|
|
477
|
+
`SegmentedControl` choices, keeping both direct buttons and exclusive-choice
|
|
478
|
+
highlights concentric when the group switches between pill and rounded shapes.
|
|
98
479
|
|
|
99
480
|
`ResizableRegion` owns the Hot Sheet 2 split treatment: a persistent 1px
|
|
100
|
-
separator with a compact grip that appears on hover or keyboard focus.
|
|
481
|
+
separator with a compact grip that appears on hover or keyboard focus. The grip
|
|
482
|
+
is drawn centered on the separator line even though the pointer target is wider
|
|
483
|
+
than the line, so the handle never reads as offset into a pane. Override
|
|
101
484
|
`--kui-resizable-region-separator-color`,
|
|
102
485
|
`--kui-resizable-region-handle-color`, or
|
|
103
486
|
`--kui-resizable-region-handle-active-color` on a region when its containing
|
|
104
487
|
surface needs a different contrast level.
|
|
105
488
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
489
|
+
`Pane` defines one structural model for sidebars, main areas, inspectors, and
|
|
490
|
+
dialogs. Its `.kui-pane` root is unpadded and contains an optional vertical
|
|
491
|
+
header, one scrolling vertical `.kui-pane__content`, and an optional footer.
|
|
492
|
+
Logical-edge separator lines are independently opt-in and default off.
|
|
493
|
+
`@kerfjs/ui/layout.css` retains the pane roles and supplies the related content
|
|
494
|
+
geometry classes.
|
|
495
|
+
`List` is the corresponding layout-only vertical stack: its children stretch by
|
|
496
|
+
default, while `gap`, `flex`, and `scrollable` opt into typed spacing,
|
|
497
|
+
flex growth, and vertical scroll ownership. `Row.flex` uses the same typed flex
|
|
498
|
+
participation contract on the horizontal counterpart. `dividerSides` accepts canonical
|
|
499
|
+
physical top/right/bottom/left combinations such as `tr` and `trbl`; the stack
|
|
500
|
+
adds no list semantics, margin, or padding of its own. Use a direct finite
|
|
501
|
+
spacing shorthand such as `gap="2xs"`, or pass a `CssLength` created by the
|
|
502
|
+
CSS-free `@kerfjs/ui/css-values` helpers: `space('m')`, `rem(0.25)`,
|
|
503
|
+
`lengthVar('--app-gap')`, or `calc(plus(rem(0.25), pct(10)))`. `plus` returns a
|
|
504
|
+
non-standalone `CssLengthExpression`; only `calc` turns it into a complete
|
|
505
|
+
length. `remify(18)` is the runtime twin of source CSS's `remify(18px)`: it
|
|
506
|
+
takes a pixel count and returns a `CssLength` in rem (`1.125rem`) against the
|
|
507
|
+
same fixed 16px baseline. Raw CSS strings, and the source-only `remify(4px)`
|
|
508
|
+
string form, are not valid runtime props. The `CssLength` name intentionally includes percentages for UI dimension
|
|
509
|
+
props. Its opaque string brand improves authoring correctness; it is not a CSS
|
|
510
|
+
sanitizer or security boundary.
|
|
511
|
+
`Row.flex` and `List.flex` likewise accept their boolean default, finite keywords, or `CssFlex`
|
|
512
|
+
from `flex(grow, shrink, basis)`. `Skeleton` width/height use `CssSize`, radius
|
|
513
|
+
uses `CssLength`, and `SelectChoice.color` uses `CssForegroundColor` from
|
|
514
|
+
`uiColor()` with a foreground token such as `success-on-quiet`, or from
|
|
515
|
+
`foregroundColorVar()`. Fill tokens such as `success` are pale background tints
|
|
516
|
+
and do not type-check there. Never exchange these property grammars. List rows expose
|
|
517
|
+
`className`, public tokens, and semantic props instead of unrestricted `style`
|
|
518
|
+
declarations.
|
|
109
519
|
`.kui-content` gives major children 24px vertical separation.
|
|
110
|
-
`.kui-content-item` gives
|
|
111
|
-
8px
|
|
112
|
-
|
|
520
|
+
`ContentItem` (`@kerfjs/ui/content-item`, rendering `.kui-content-item`) gives
|
|
521
|
+
one child 8px inline margin, a real 1px border, 8px padding, and 12px corners;
|
|
522
|
+
the border stays transparent unless `frame="framed"`, so framing never changes
|
|
523
|
+
geometry. `shape="pill"` selects the 22px radius. `appearance="surface"`
|
|
524
|
+
paints the base surface, while `neutral`, `info`, `pop`, `success`, `warning`,
|
|
525
|
+
and `danger` coordinate the same quiet background, border, and readable
|
|
526
|
+
foreground tokens as `StateBanner`. The default `transparent` appearance
|
|
527
|
+
preserves the surrounding surface.
|
|
528
|
+
`flush` removes block padding and borders while preserving inline geometry;
|
|
529
|
+
`title` passes through as the native tooltip. Interactive hover uses the normal
|
|
530
|
+
neutral fill so it remains visible on a lowered surface. For a card with
|
|
531
|
+
multiple actions, put sibling buttons in a static ContentItem (or use
|
|
532
|
+
`ListActionRow` for a simple two-action row).
|
|
533
|
+
For an interactive ContentItem, `wireContentItems` activates the card on Enter
|
|
534
|
+
or Space only when the key event originated from the card itself. A nested
|
|
535
|
+
native control, including one inside a custom element's shadow root, keeps its
|
|
536
|
+
own keyboard activation.
|
|
113
537
|
|
|
114
538
|
`ToolbarControlGroup` is the unit of toolbar organization, even for dormant
|
|
115
539
|
text. Each group reserves `calc(2px + remify(42px))`, or 44px, with 8px between
|
|
116
|
-
groups and inside items.
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
540
|
+
groups and inside items. For an ordinary icon/action control inside a group, use
|
|
541
|
+
a plain `<button>` — the group styles `> button` fully, and it keeps the group
|
|
542
|
+
free of a Web Awesome dependency and shadow DOM. Use `ToolbarActionLink` when
|
|
543
|
+
the action must retain native anchor navigation; the group owns its geometry,
|
|
544
|
+
hover, and focus treatment. Set `overflow="scroll"` when a row of controls must
|
|
545
|
+
stay inside the available toolbar width. A disabled native button keeps the
|
|
546
|
+
group's geometry, dims to half opacity, uses the `not-allowed` cursor, and
|
|
547
|
+
paints neither its own nor a lone group's hover surface.
|
|
548
|
+
Set `visibility="compact-only"` for a
|
|
549
|
+
group that replaces wider toolbar controls below the Toolbar's compact container
|
|
550
|
+
breakpoint; do not hide the group with an application class.
|
|
551
|
+
Use `sizing="grow"` on an expanded search group in a wrapping zone: it grows from
|
|
552
|
+
`growBasis` (19rem by default) into available row space, then takes a whole
|
|
553
|
+
row at 480px container width or less. The basis remains its intrinsic minimum
|
|
554
|
+
in a wider, non-stacked Toolbar, so sibling trailing groups can share the
|
|
555
|
+
row. The collapsed search stays icon-sized.
|
|
556
|
+
Use `sizing="fill"` for a group, including a non-search segmented control,
|
|
557
|
+
that spans its wrapping row. Set `visibility="hide-collapsed-tiny"` on a
|
|
558
|
+
collapsible group to omit its closed icon at 224px or less; expanded content
|
|
559
|
+
remains visible. These sizes use the enclosing Toolbar's container width.
|
|
560
|
+
In a stacked Toolbar, set `placement="end"` on a collapsed group that should
|
|
561
|
+
sit at the trailing edge of its flex row. An expanded search with
|
|
562
|
+
`sizing="fill"` takes a whole row and enters from the row above; reduced-motion
|
|
563
|
+
preferences remove that entrance animation.
|
|
564
|
+
Use `visibility="yield-to-expanded-sibling"` on trailing groups that should
|
|
565
|
+
leave a 480px-or-narrower toolbar while a sibling trailing group is expanded.
|
|
566
|
+
They return when it collapses or the toolbar widens; leading and center zones
|
|
567
|
+
remain visible.
|
|
568
|
+
Reach for `wa-button` only when you need a Web Awesome feature; a popup menu is a `PopupMenu`, which renders its own
|
|
569
|
+
trigger. By default a group stays on one row: each icon sits beside its label,
|
|
570
|
+
and the enclosing `Toolbar`'s responsive policy relocates whole groups. Set
|
|
571
|
+
`overflow="wrap"` only for independent links that should move as whole actions
|
|
572
|
+
to another row within the group; use `overflow="scroll"` for a bounded one-row
|
|
573
|
+
action strip. A wrapping group centers in the toolbar band on one row and
|
|
574
|
+
starts at its top when it grows to multiple rows. For a compact mixed-content
|
|
575
|
+
group, set `nestedDropdown`; a
|
|
576
|
+
text-and-caret trigger grows to its intrinsic width while an icon-only trigger
|
|
577
|
+
can remain square. A compact icon `<button>` is a 32px circle, so a selected
|
|
578
|
+
compact segment never becomes an oval. An icon-only `Select` joins a group as
|
|
579
|
+
one more segment with its siblings' inset, radius, hover, and focus ring; only a
|
|
580
|
+
lone Select grows the group to its icon-and-caret pill.
|
|
581
|
+
|
|
582
|
+
Select menus use native viewport shifting with 10px gutters: default menus grow to content (up to 20rem), while `fitMenu` matches trigger width and long labels wrap. Keep popup sizing and position repairs out of consumer CSS.
|
|
583
|
+
|
|
584
|
+
For a rail view heading, use `Select presentation="title"`: its intrinsic
|
|
585
|
+
36px borderless trigger has a bold large label flush with its leading edge and
|
|
586
|
+
a caret beside that label. Set `focusRingInset` when a NavStack or panel clips
|
|
587
|
+
outside painting; the Select keeps its focus outline 3px inside the trigger
|
|
588
|
+
and drops it while the listbox is open. Both settings belong to Select, not an
|
|
589
|
+
application `::part()` override.
|
|
590
|
+
|
|
591
|
+
Set `menuInset` to configure the dropdown menu surface
|
|
592
|
+
without application `::part(menu)` CSS; the default `standard` keeps each menu's
|
|
593
|
+
own inset (8px for a raw `wa-dropdown`, the Select listbox's 4px for a
|
|
594
|
+
`PopupMenu`), while `compact` and `list-zero` apply to every nested menu. A
|
|
595
|
+
`PopupMenu` and a `Select` draw one popup: the same caret that turns to face the
|
|
596
|
+
open popup, fade-in surface, surface inset, row height and padding, current-row
|
|
597
|
+
fill, and group titles, all read from one private popup-choice contract in
|
|
598
|
+
`foundation.css`. Checkbox items reserve a check column; plain commands start
|
|
599
|
+
at the checkmark's leading edge, beside the group title rather than the
|
|
600
|
+
farther-in Select option label. Checked submenu items keep their checkmark and
|
|
601
|
+
label inside the submenu surface. Compact mixed controls retain the standard
|
|
602
|
+
item padding, omit an internal separator, and let the raised selected item paint
|
|
603
|
+
over the outer border instead of shrinking to an inset highlight. The Web
|
|
604
|
+
Awesome trigger's shadow base owns max-content sizing, so icons, localized text,
|
|
605
|
+
and the shadow caret determine the width without a fixed host measurement.
|
|
606
|
+
With `popup-menu/register` loaded, PopupMenu and a raw dropdown inside
|
|
607
|
+
`PopupSurface` preserve item navigation made during the Web Awesome show
|
|
608
|
+
animation across its final initial-focus handoff.
|
|
609
|
+
At viewport widths of 480px or less, `PopupMenu` places an open submenu above
|
|
610
|
+
or below its parent menu, choosing the side with room and constraining the
|
|
611
|
+
submenu to the viewport. It never paints over the parent list. The submenu
|
|
612
|
+
remains a native Web Awesome `menu`: the reverse horizontal arrow (ArrowLeft in
|
|
613
|
+
LTR, ArrowRight in RTL) returns focus to its parent item, Escape dismisses the
|
|
614
|
+
menu, and choosing a child dispatches the normal
|
|
615
|
+
`data-action` and `wa-select` events. Wider viewports retain the side cascade.
|
|
616
|
+
The enclosing `Toolbar` owns zone alignment and responsive topology: use
|
|
617
|
+
`centerAlign="stretch"` when the center group should consume its track, and
|
|
618
|
+
choose `responsive="stack"` with `responsiveAt="compact" | "narrow"`,
|
|
619
|
+
`responsive="wrap"` for a heading whose title must stay whole, or
|
|
620
|
+
`responsive="center-priority"` instead of selecting its zone classes from a
|
|
621
|
+
parent stylesheet. No policy clips an action: the trailing zone wraps whole
|
|
622
|
+
groups and its standalone primary `wa-button` onto another row; a stacked
|
|
623
|
+
center zone wraps its groups. The center zone never
|
|
624
|
+
compresses below its content width, so when the leading identity, center, and
|
|
625
|
+
trailing zones share a row that is too narrow, the leading title is what gives
|
|
626
|
+
way: it truncates with an ellipsis (as a platform toolbar's title does) instead
|
|
627
|
+
of the center group painting over it. When everything fits, the center group
|
|
628
|
+
keeps its place, centered in the track between the leading and trailing zones.
|
|
629
|
+
`ListHeader` similarly separates its dormant title and optional indicators
|
|
630
|
+
from its optional 44px action. Use the `count`/`countLabel` pair for a sole
|
|
631
|
+
non-negative safe-integer section quantity; it excludes `badge` and `status`.
|
|
632
|
+
`badge` and `status` may appear together, and either may be explicitly
|
|
633
|
+
`undefined` as app state changes. Give a contextual quantity in a badge a full
|
|
634
|
+
spoken phrase, such as "3 lines unpriced". Do not concatenate counts into the
|
|
635
|
+
section label. Set `width="content"` to shrink-wrap while retaining
|
|
636
|
+
normal header geometry; `inline` is the separate zero-outer-geometry mode. Do
|
|
637
|
+
not add padding to pane shells,
|
|
121
638
|
double child-owned geometry with wrapper insets, or create competing scroll
|
|
122
639
|
owners. The [layout contract](./layout.md) lists the public roles and tokens.
|
|
123
640
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
641
|
+
Panel, dialog, and page headings are direct `Toolbar` compositions. The leading
|
|
642
|
+
zone holds an optional icon `ToolbarControlGroup` and a direct extra-large
|
|
643
|
+
`ToolbarText`; app actions belong in a trailing `ToolbarControlGroup`. Omit the
|
|
644
|
+
icon group when it has no content. Supporting copy is app-owned content below
|
|
645
|
+
the toolbar so it cannot pull the icon or actions out of alignment.
|
|
646
|
+
For an editable title, `ToolbarText action="edit-title"` renders a native button
|
|
647
|
+
directly in the leading zone. It keeps content width when there is room, shrinks
|
|
648
|
+
and ellipsizes beside a status chip when space is tight, and emits the delegated
|
|
649
|
+
action on click or keyboard activation. The application owns the editing control
|
|
650
|
+
and the swap between display and edit states. An actionable title is a button,
|
|
651
|
+
so place any required heading landmark on another element in the view.
|
|
132
652
|
|
|
133
653
|
`ValueTable` composes typed `ValueTableRow` entries. A row owns its `dt`/`dd`
|
|
134
654
|
semantics and may receive a leading `SafeHtml` icon. Every row keeps 8px of
|
|
@@ -139,6 +659,16 @@ padding + 24px icon + 8px gap) and 8px from the right edge for an icon-bearing
|
|
|
139
659
|
row. Applications own the values, formatting, and whether an icon is decorative
|
|
140
660
|
or meaningfully labeled.
|
|
141
661
|
|
|
662
|
+
A row follows the settings-style key/value priority: the value keeps its
|
|
663
|
+
content and the label gives way. The label and value are two content-sized
|
|
664
|
+
columns that share the row's free space equally, each stopping once its content
|
|
665
|
+
fits. A short value therefore stays whole on one line beside any label, and a
|
|
666
|
+
long label takes the remaining width, wrapping at its spaces and ending a word
|
|
667
|
+
wider than its column (a long component or file name) in an ellipsis before the
|
|
668
|
+
value rather than running under it. A short label keeps its width beside a
|
|
669
|
+
long value, which wraps; when both are long they split the row, so neither is
|
|
670
|
+
starved.
|
|
671
|
+
|
|
142
672
|
## Imports and side effects
|
|
143
673
|
|
|
144
674
|
Every component has an explicit JS and CSS subpath. In CSS-aware browser builds,
|
|
@@ -159,25 +689,58 @@ by default it also owns the collapsible field's transient expand/collapse/focus
|
|
|
159
689
|
state in a signal it exposes on the returned handle. An app reads that signal in
|
|
160
690
|
render, hands in its own via `collapsible.signals`, drives it through
|
|
161
691
|
`handle.open`/`handle.close`, or disables any individual behavior — so transient
|
|
162
|
-
UI is consistent by default without every app reinventing it.
|
|
692
|
+
UI is consistent by default without every app reinventing it. A collapsed
|
|
693
|
+
field may reveal its editor after the current microtask; the helper keeps a
|
|
694
|
+
bounded render-frame focus handoff for that reveal and cancels it on disposal.
|
|
695
|
+
`TokenSearchField.trailingAction` supplies an icon, accessible `label`, delegated
|
|
696
|
+
`action`, and optional `id`; the field renders a 24px wide button that fills its
|
|
697
|
+
34px line slot, including the hit target, disabled state, hover, and focus ring.
|
|
698
|
+
Use `trailing` for passive content. The two props are mutually exclusive.
|
|
699
|
+
For a collapsible search in a stretched Toolbar center, `fill` lets the expanded
|
|
700
|
+
field and its enclosing search `ToolbarControlGroup` consume the available width;
|
|
701
|
+
the collapsed action retains its fixed icon width.
|
|
702
|
+
Grammar suggestion rows align their labels to one leading edge inside the
|
|
703
|
+
anchored popover, including when the labels have different lengths.
|
|
704
|
+
|
|
705
|
+
A public subpath that exposes several visual components is a folder-backed
|
|
706
|
+
surface. Put each component in its own source file and give each visual
|
|
707
|
+
component exactly one owned stylesheet alongside it. Keep the public
|
|
708
|
+
compatibility entrypoints implementation-free: the JavaScript/TypeScript
|
|
709
|
+
entrypoint only re-exports the folder modules, and the CSS entrypoint only
|
|
710
|
+
imports their owner stylesheets. A shared public name is not permission to put
|
|
711
|
+
several component implementations or visual contracts back into one file.
|
|
163
712
|
|
|
164
713
|
`wireTokenSearchFields` is a deliberate exception, not the rule for `wire…`
|
|
165
|
-
helpers. Its collapse behavior was
|
|
714
|
+
helpers. Its collapse behavior was _rich and error-prone_ — reveal, focus
|
|
166
715
|
transfer, Escape, empty-blur collapse, focus return — the kind of transient chrome
|
|
167
716
|
apps kept reimplementing inconsistently, so the helper owns it. Everywhere else the
|
|
168
717
|
app's state is **domain or persisted, not transient chrome, and stays app-owned**: a
|
|
169
|
-
`NavStack`'s view stack is navigation history, a `TabBar`/`
|
|
718
|
+
`NavStack`'s view stack is navigation history, a `TabBar`/`TabNavigator`'s selection
|
|
170
719
|
and tab order are data, a `ResizableRegion`'s committed size and a
|
|
171
720
|
`Workbench`/`SplitView` rail's `collapsed` flag are persisted layout preferences.
|
|
172
|
-
Each helper already owns only the
|
|
721
|
+
Each helper already owns only the _ephemeral mechanics_ around that state —
|
|
173
722
|
`wireNavStack` the push/pop animation, `wireTabBars` the overflow autoscroll and
|
|
174
723
|
drag preview, `wireResizableRegions` the live drag preview — and reports committed
|
|
175
|
-
changes through callbacks. A `
|
|
724
|
+
changes through callbacks. A `ListHeader` `toggle` disclosure's `expanded` is
|
|
176
725
|
likewise app-owned: it is a one-line boolean the app already tracks and must read to
|
|
177
726
|
render the section body, so a managed helper would remove no real complexity. Reach
|
|
178
727
|
for a managed default only when the transient behavior is substantial enough that
|
|
179
728
|
hand-rolling it produces genuine, inconsistent variation.
|
|
180
729
|
|
|
730
|
+
TabBar itself owns the inline geometry around those mechanics. Its tab list is
|
|
731
|
+
the only shrinking, horizontally scrolling region; `leading`, `trailing`, and
|
|
732
|
+
`end` action regions remain fixed. Set `trailingPlacement="adjacent"` when the
|
|
733
|
+
trailing action belongs immediately after the final tab and use `end` for a
|
|
734
|
+
separate action pinned to the far edge. Applications own the action content,
|
|
735
|
+
but must not restyle TabBar descendants to recreate that allocation.
|
|
736
|
+
When a leading AppTab is pinned, the leading scroll divider appears at that
|
|
737
|
+
tab's trailing edge while peer tabs scroll beneath it, including in RTL.
|
|
738
|
+
With `snapTabs`, `wireTabBars` measures the pinned tab and settles peers at
|
|
739
|
+
whole-tab starts after scroll and selection changes, reserving end room so the
|
|
740
|
+
last peer can align there. The application still owns selection and tab order.
|
|
741
|
+
ResizeObserver notifications coalesce snap measurements into the next animation
|
|
742
|
+
frame, so inset writes cannot resize the observed strip during observer delivery.
|
|
743
|
+
|
|
181
744
|
CSS, the generated wrappers that make it
|
|
182
745
|
reachable, and the registration module are the package's only declared side
|
|
183
746
|
effects.
|
|
@@ -186,14 +749,74 @@ A value-bearing component's `placeholder` prop is a first-class loading mode: th
|
|
|
186
749
|
component renders its own real chrome (labels, icon and action affordances,
|
|
187
750
|
container geometry) while replacing each **value** slot with a subtle, deliberately
|
|
188
751
|
unanimated `Skeleton` block and disabling its own interactive controls
|
|
189
|
-
(`aria-busy`, dropped `data-action`, disabled buttons).
|
|
752
|
+
(`aria-busy`, dropped `data-action`, disabled buttons). Only unknown values become
|
|
753
|
+
skeletons; nothing else may change. Sizes, shapes, typography, color, and opacity stay
|
|
190
754
|
identical to the populated component, so a parent composes a faithful loading view —
|
|
191
755
|
an inspector, a detail pane — from placeholder children without hand-rebuilding
|
|
192
756
|
markup. The application still owns the loading lifecycle (when to pass `placeholder`)
|
|
193
|
-
and which slots are unknown; the standalone `Skeleton` covers custom slots.
|
|
757
|
+
and which slots are unknown; the standalone `Skeleton` covers custom slots. A
|
|
758
|
+
`Skeleton` is `inline-block` so it sits in a text line; pass `block` to lay it out
|
|
759
|
+
as `display: block` where it stands in for a box, such as an icon, so it takes no
|
|
760
|
+
line of its own and centers in its slot. It is a
|
|
194
761
|
placeholder, not progress: use `LoadingSpinner` for known busy activity, and never
|
|
195
762
|
animate the skeleton.
|
|
196
763
|
|
|
764
|
+
`LucideIcon` defaults to `appearance="outline"`. Pass
|
|
765
|
+
`appearance="solid"` for a filled state glyph such as a selected star or
|
|
766
|
+
triangle. The SVG uses `fill="currentColor"`, so fill follows the icon's text
|
|
767
|
+
color without styling its internal SVG from the application. Choose a Lucide
|
|
768
|
+
node whose geometry supports a solid fill; the prop does not replace an icon
|
|
769
|
+
node's own fill attributes.
|
|
770
|
+
The SVG is block-level by default. Pass `inline` when it belongs inside a
|
|
771
|
+
sentence or `Text`: the SVG becomes `inline-block`, keeps its inherited 1em
|
|
772
|
+
size unless `size` is supplied, and stays decorative unless `label` is set.
|
|
773
|
+
|
|
774
|
+
`LoadingSpinner` accepts the same `size` steps as `LucideIcon`: `xs`, `s`, `m`,
|
|
775
|
+
`l`, `xl` (12/16/20/24/32px at a 16px root) or a positive finite pixel
|
|
776
|
+
number converted to rem. Omit `size` to keep its inherited 1em box. A supplied
|
|
777
|
+
size is exposed as `data-size`; callers configure the spinner through this prop
|
|
778
|
+
instead of sizing its SVG from outside.
|
|
779
|
+
|
|
780
|
+
A placeholder is loading, not unavailable, so it keeps the `disabled` attribute (its
|
|
781
|
+
controls stay inert and out of the keyboard order) but never shows disabled chrome.
|
|
782
|
+
`skeleton.css`, which every component that renders a skeleton loads, neutralizes generic
|
|
783
|
+
disabled styling under `[data-placeholder="true"]` — including Web Awesome's native
|
|
784
|
+
`button:disabled { opacity: 0.5; cursor: not-allowed }` when `webawesome.css` is
|
|
785
|
+
loaded — to full opacity and the non-interactive `default` cursor. That opacity reset
|
|
786
|
+
carries zero specificity, so a component's own opacity (a control hidden until
|
|
787
|
+
interaction) still wins, and each component excludes placeholders from its own
|
|
788
|
+
disabled tone and hover feedback — including hover reveals: a `ListActionRow` with
|
|
789
|
+
`trailingActionVisibility="interaction"` keeps its trailing action hidden when its
|
|
790
|
+
placeholder is hovered, as the resting live row does. The cursor is the one intentional difference from the
|
|
791
|
+
live state: a placeholder is not clickable, so it never advertises a pointer.
|
|
792
|
+
|
|
793
|
+
A control the author disabled is different: it will be unavailable once loaded, so its
|
|
794
|
+
placeholder keeps the live disabled tone. Each such control carries the component-owned
|
|
795
|
+
`data-kui-disabled="true"` marker whenever its own disabled prop is set, independent of
|
|
796
|
+
`placeholder` — `ListItem` and `ListActionRow` `disabled`, `trailingActionDisabled`,
|
|
797
|
+
a `SegmentedControl` choice's `disabled`, and `ListHeader` `actionDisabled` (on the
|
|
798
|
+
action or disclosure toggle). The placeholder reset skips the marker and components key
|
|
799
|
+
their disabled tone on it, so only the `placeholder`-only `disabled` attribute is
|
|
800
|
+
neutralized. That tone is each component's own, never Web Awesome's native
|
|
801
|
+
`button:disabled`, so an author-disabled control is dimmed with or without
|
|
802
|
+
`webawesome.css`. The marker is reserved: the extension-attribute channels
|
|
803
|
+
(`rootAttributes`, `trailingActionAttributes`, `triggerAttributes`) cannot set it. A
|
|
804
|
+
disabled placeholder still shows the `default` cursor, never `not-allowed`.
|
|
805
|
+
Chrome a component draws itself from a known prop stays live, even inside a slot that
|
|
806
|
+
also holds values. `ListItem`'s trailing slot has three inputs: the `busy` spinner is
|
|
807
|
+
component-owned chrome and stays live, while `status` text and author-supplied
|
|
808
|
+
`trailing` content are values and each become a skeleton (the component cannot tell an
|
|
809
|
+
author's chevron from a count, so all `trailing` content is treated as a value).
|
|
810
|
+
`ListActionRow`'s status line follows the same split: its `busy` spinner stays live and
|
|
811
|
+
only the `status` text becomes a skeleton.
|
|
812
|
+
`SegmentedControl` is the one placeholder without a skeleton: its choices are known
|
|
813
|
+
chrome and only the selection is unknown, so it renders every choice's live label or
|
|
814
|
+
icon at its live geometry, selects none, and neutralizes its own disabled chrome.
|
|
815
|
+
`tests/browser/placeholder-fixture.spec.ts` enforces the rule: it renders every
|
|
816
|
+
placeholder component live and as a placeholder from identical props and diffs each
|
|
817
|
+
element's geometry and computed chrome, excluding only the value slots, and checks that
|
|
818
|
+
every author-disabled control is dimmed in both renders.
|
|
819
|
+
|
|
197
820
|
Package source styles express root-scaled geometry with `remify(<px>)`; the
|
|
198
821
|
build converts it against the 16px authoring baseline and exposes only ordinary
|
|
199
822
|
`rem` CSS. Literal pixels remain for intentional hairlines, and `em` remains
|
|
@@ -209,7 +832,25 @@ Kerf JSX declaration boundary for every catalog-supported `wa-*` tag.
|
|
|
209
832
|
Consumers register only the individual Web Awesome modules they render and can
|
|
210
833
|
override `--wa-*` values after the theme import. The shared `--wa-*` values feed
|
|
211
834
|
both Web Awesome controls and Kerf's `--kui-*` foundation aliases, preventing a
|
|
212
|
-
second application palette.
|
|
835
|
+
second application palette. Without the theme, every foundation color token,
|
|
836
|
+
every elevation token (`--kui-shadow-*`), and the focus-ring color fall back to
|
|
837
|
+
the same value the theme assigns, including its `light-dark()` pair, so
|
|
838
|
+
surfaces (including the dark `surface-raised`), links (`text-link` is the brand
|
|
839
|
+
on-quiet text color, not the brand fill), tone text, fills, and raised-surface
|
|
840
|
+
shadows keep their light and dark appearance and contrast either way. The
|
|
841
|
+
theme's elevation shadows are scheme-aware: light keeps the soft Hot Sheet 2
|
|
842
|
+
alphas, and dark raises them (`--wa-shadow-s` 14% to 50% black, `-m` 11% to
|
|
843
|
+
40%, `-l` 9% to 32%) so a raised surface still separates from a near-black
|
|
844
|
+
page.
|
|
845
|
+
Kerf owns the light `brand`, `success`, and `warning` `on-quiet` values in that
|
|
846
|
+
theme layer: each keeps its hue but is dark enough to clear WCAG AA (4.5:1) on
|
|
847
|
+
the lowered page background (`--kui-color-surface-lowered`, approximately `#f2f2f7` over white), not
|
|
848
|
+
only on the white surface, so toned text reads on every background a page
|
|
849
|
+
paints. It likewise owns every tone's loud pair: each `on-loud` text color
|
|
850
|
+
clears AA on its `fill-loud` in both schemes. Light brand and danger keep white
|
|
851
|
+
text on a slightly deeper fill of the same hue (`#0075db`, `#eb0005`); success
|
|
852
|
+
keeps its bright green with dark text, as warning does; the dark-mode brand and
|
|
853
|
+
danger fills keep their color with dark text.
|
|
213
854
|
|
|
214
855
|
`Select` owns its custom-element reconciliation seam. It gives each slotted
|
|
215
856
|
option icon a stable key and leaves the upgraded Web Awesome-owned slot subtree
|
|
@@ -228,4 +869,38 @@ Keep product adapters outside the package: connection-state maps, ticket empty-s
|
|
|
228
869
|
|
|
229
870
|
## Testing contract
|
|
230
871
|
|
|
231
|
-
Each behavior has focused unit coverage and a real-browser flow through the production-backed catalog. Consumer bundle tests enforce subpath CSS reachability, transitive component styles, root/SSR isolation, optional registration boundaries, and the CSS-only Web Awesome theme boundary. Visual evidence supplements—never replaces—keyboard, focus, state, and event assertions.
|
|
872
|
+
Each behavior has focused unit coverage and a real-browser flow through the production-backed catalog. Consumer bundle tests enforce subpath CSS reachability, transitive component styles, root/SSR isolation, optional registration boundaries, and the CSS-only Web Awesome theme boundary. `npm run check:css-ownership` rejects application selectors into Kerf or Web Awesome components, a non-minimal catalog compatibility stylesheet, or a return of the shared recipe stylesheet. Visual evidence supplements—never replaces—keyboard, focus, state, and event assertions.
|
|
873
|
+
|
|
874
|
+
### Toolbar width visibility
|
|
875
|
+
|
|
876
|
+
`ToolbarText` and `ToolbarControlGroup` accept typed `hideBelow` and
|
|
877
|
+
`showBelow` CSS lengths. Call `wireToolbarVisibility(root)` from
|
|
878
|
+
`@kerfjs/ui/wire-toolbar-visibility` after mounting, and call its disposer when
|
|
879
|
+
the application unmounts. The nearest Toolbar's **content-box width**, excluding
|
|
880
|
+
padding, borders, and safe-area insets, determines visibility. `hideBelow={px(416)}`
|
|
881
|
+
hides strictly below 416px; `showBelow={px(416)}` shows strictly below 416px. At
|
|
882
|
+
416px the first is visible and the second hidden. Together they define the visible
|
|
883
|
+
interval `[hideBelow, showBelow)`. Width rules intersect existing visibility and
|
|
884
|
+
expanded-state rules; they never force a CSS-hidden group visible.
|
|
885
|
+
|
|
886
|
+
Use `px`, `rem`, `em`, `pct`, `space`, `lengthVar`, or `calc`/`plus` to construct
|
|
887
|
+
lengths. Percentages resolve against that content box, `em` uses the child item's
|
|
888
|
+
font size, and custom properties use its inherited and own token context. The
|
|
889
|
+
helper follows resizes, theme/token/font changes, inserted items, nested toolbars,
|
|
890
|
+
and relocated groups. Invalid, unresolved, negative, or contradictory thresholds
|
|
891
|
+
leave the item visible under this width policy. Server-rendered content is visible
|
|
892
|
+
until wiring runs; without browser observers, initial wiring and window resize
|
|
893
|
+
still update it. Probe context and lengths are reconciled only when their CSSOM
|
|
894
|
+
values change, so unrelated DOM observers can redraw without feeding an ongoing
|
|
895
|
+
mutation loop. Probes are helper-owned imperative nodes preserved across Kerf
|
|
896
|
+
rerenders, preventing repeated probe creation and resize/DOM observer churn.
|
|
897
|
+
Invisible preserved state children keep actual CSS visibility stable while a render
|
|
898
|
+
removes transient parent markers, so post-render geometry measurements cannot
|
|
899
|
+
feed a show/hide render loop. These children never enter layout, focus or the
|
|
900
|
+
accessible tree. Toolbar replacement or deliberate internal-node removal is
|
|
901
|
+
still repaired. Dispose to
|
|
902
|
+
remove measurement probes and restore prior markers.
|
|
903
|
+
|
|
904
|
+
Hidden controls leave layout and keyboard navigation. A hidden busy group also
|
|
905
|
+
hides only its own adjacent busy status. Keep primary actions always available;
|
|
906
|
+
show a complementary overflow group for secondary actions at narrow widths.
|