@kerfjs/ui 5.0.0-beta.55 → 5.0.0-beta.57
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 +74 -41
- package/ai/application-ui-diagnostic-ids-v1.json +9 -1
- package/ai/application-ui-profile-sync.cjs +1 -1
- package/ai/application-ui-profile.defaults.json +63 -8
- package/ai/application-ui-profile.mjs +1 -1
- package/ai/compile-time-contracts-v1.json +2 -2
- package/ai/component-catalog.json +407 -80
- package/ai/component-catalog.schema.json +2 -0
- 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-catalog-v2-overrides.json → component-composition-rules.json} +2 -1
- package/ai/{component-catalog-v2.d.ts → component-composition.d.ts} +9 -5
- package/ai/{component-catalog-v2.json → component-composition.json} +302 -61
- package/ai/{component-catalog-v2.schema.json → component-composition.schema.json} +21 -5
- package/ai/components/README.md +170 -0
- package/ai/components/application-tabs.md +65 -0
- package/ai/components/badge.md +72 -0
- package/ai/components/collapsible-panel.md +102 -0
- package/ai/components/content-item.md +90 -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 +80 -0
- package/ai/components/foundation.md +65 -0
- package/ai/components/grid.md +93 -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 +89 -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 +88 -0
- package/ai/components/list.md +103 -0
- package/ai/components/loading-spinner.md +72 -0
- package/ai/components/lucide-icon.md +66 -0
- package/ai/components/nav-stack.md +103 -0
- package/ai/components/pane.md +100 -0
- package/ai/components/popup-menu.md +82 -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 +101 -0
- package/ai/components/row.md +96 -0
- package/ai/components/segmented-control.md +82 -0
- package/ai/components/select.md +107 -0
- package/ai/components/skeleton.md +84 -0
- package/ai/components/spacer.md +86 -0
- package/ai/components/split-view.md +102 -0
- package/ai/components/state-banner.md +92 -0
- package/ai/components/sunken-panel.md +79 -0
- package/ai/components/surface-scaffold.md +78 -0
- package/ai/components/tab-bar.md +112 -0
- package/ai/components/tab-scaffold.md +94 -0
- package/ai/components/tabs.md +90 -0
- package/ai/components/text.md +82 -0
- package/ai/components/token-search-field.md +101 -0
- package/ai/components/toolbar-control-group.md +100 -0
- package/ai/components/toolbar-text.md +76 -0
- package/ai/components/toolbar.md +95 -0
- package/ai/components/value-table.md +72 -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 +114 -0
- package/ai/public-api-signatures-v1.md +572 -101
- package/ai/skill.md +107 -52
- package/ai/webawesome-jsx-signatures-v1.md +8 -2
- package/analyzer/component-ownership.d.mts +56 -0
- package/analyzer/component-ownership.mjs +184 -0
- package/analyzer/index.d.mts +3 -0
- package/analyzer/index.mjs +274 -20
- package/analyzer/selectors.d.mts +21 -0
- package/analyzer/selectors.mjs +212 -0
- package/dist/app-tab.js +1 -1
- package/dist/badge.d.ts +35 -7
- package/dist/badge.js +1 -1
- package/dist/browser/catalog.js +25 -0
- package/dist/browser/collapsible-panel.js +7 -0
- package/dist/browser/content-item.js +3 -0
- package/dist/browser/nav-stack.js +8 -0
- package/dist/browser/select.js +1 -0
- package/dist/browser/split-view.js +10 -0
- package/dist/browser/tab-scaffold.js +4 -0
- package/dist/browser/workbench.js +10 -0
- package/dist/catalog-resources.d.ts +12 -1
- package/dist/catalog.d.ts +14 -3
- package/dist/catalog.js +53 -43
- package/dist/catalog.js.map +1 -1
- package/dist/{chunk-WZ2GLEY4.js → chunk-2G2ZJQYK.js} +2 -14
- package/dist/chunk-2G2ZJQYK.js.map +1 -0
- package/dist/{chunk-R754MHXX.js → chunk-553ASUK6.js} +8 -8
- package/dist/chunk-553ASUK6.js.map +1 -0
- package/dist/{chunk-D7GWXIAS.js → chunk-5I7QGQVT.js} +1 -1
- package/dist/chunk-5I7QGQVT.js.map +1 -0
- package/dist/{chunk-RNRUVPJ3.js → chunk-63ZWBGE3.js} +3 -2
- package/dist/chunk-63ZWBGE3.js.map +1 -0
- package/dist/{chunk-44IG7PFV.js → chunk-6CINWX2E.js} +3 -3
- package/dist/{chunk-44IG7PFV.js.map → chunk-6CINWX2E.js.map} +1 -1
- package/dist/{chunk-MTM43SJO.js → chunk-6YFHCLHG.js} +2 -2
- package/dist/chunk-6YFHCLHG.js.map +1 -0
- package/dist/{chunk-C2FAYFDE.js → chunk-AGXQQFKZ.js} +2 -2
- package/dist/{chunk-C2FAYFDE.js.map → chunk-AGXQQFKZ.js.map} +1 -1
- package/dist/{chunk-ATHXW6RP.js → chunk-AHEG27M7.js} +2 -2
- package/dist/{chunk-ATHXW6RP.js.map → chunk-AHEG27M7.js.map} +1 -1
- package/dist/chunk-BFPBS5Y4.js +250 -0
- package/dist/chunk-BFPBS5Y4.js.map +1 -0
- package/dist/{chunk-5OLVUEND.js → chunk-DG6G5EPF.js} +4 -6
- package/dist/chunk-DG6G5EPF.js.map +1 -0
- package/dist/{chunk-LZXQVUGN.js → chunk-EVYKTVBQ.js} +5 -14
- package/dist/chunk-EVYKTVBQ.js.map +1 -0
- package/dist/{chunk-7GUQYHKA.js → chunk-EZVNC4J6.js} +7 -1
- package/dist/chunk-EZVNC4J6.js.map +1 -0
- package/dist/{chunk-RNZAKSME.js → chunk-F4QMLOXJ.js} +5 -4
- package/dist/chunk-F4QMLOXJ.js.map +1 -0
- package/dist/{chunk-EAX2GSS4.js → chunk-G2RKFVRB.js} +54 -20
- package/dist/chunk-G2RKFVRB.js.map +1 -0
- package/dist/chunk-JCV4GXWB.js +249 -0
- package/dist/chunk-JCV4GXWB.js.map +1 -0
- package/dist/chunk-K47P7QZC.js +17 -0
- package/dist/chunk-K47P7QZC.js.map +1 -0
- package/dist/{chunk-HMQ2ZDGG.js → chunk-KROD7KZK.js} +3 -2
- package/dist/chunk-KROD7KZK.js.map +1 -0
- package/dist/{chunk-5NDQABWK.js → chunk-M7QV3IHH.js} +3 -1
- package/dist/chunk-M7QV3IHH.js.map +1 -0
- package/dist/chunk-MA73TA6D.js +42 -0
- package/dist/chunk-MA73TA6D.js.map +1 -0
- package/dist/{chunk-ZMBU522F.js → chunk-MEY33VWB.js} +2 -2
- package/dist/{chunk-ZMBU522F.js.map → chunk-MEY33VWB.js.map} +1 -1
- package/dist/chunk-MP2GDBQZ.js +50 -0
- package/dist/chunk-MP2GDBQZ.js.map +1 -0
- package/dist/{chunk-3NBL3OUQ.js → chunk-NAPE7WUS.js} +2 -2
- package/dist/chunk-NAPE7WUS.js.map +1 -0
- package/dist/{chunk-BSKEH3UC.js → chunk-NBYTIVHS.js} +2 -2
- package/dist/{chunk-BSKEH3UC.js.map → chunk-NBYTIVHS.js.map} +1 -1
- package/dist/{chunk-T22EM4ET.js → chunk-OUK6QRDR.js} +71 -31
- package/dist/chunk-OUK6QRDR.js.map +1 -0
- package/dist/chunk-PWXNJS2B.js +115 -0
- package/dist/chunk-PWXNJS2B.js.map +1 -0
- package/dist/{chunk-GUIHMIT2.js → chunk-QOWG4ZCL.js} +5 -4
- package/dist/chunk-QOWG4ZCL.js.map +1 -0
- package/dist/{chunk-5I22LMCV.js → chunk-VZOFZPSO.js} +2 -2
- package/dist/chunk-VZOFZPSO.js.map +1 -0
- package/dist/{chunk-4BIMLITI.js → chunk-WLG6SSNT.js} +5 -3
- package/dist/chunk-WLG6SSNT.js.map +1 -0
- package/dist/{chunk-NE5JAOQS.js → chunk-WOUF7YXM.js} +3 -3
- package/dist/{chunk-NE5JAOQS.js.map → chunk-WOUF7YXM.js.map} +1 -1
- package/dist/{chunk-N7FHFNT6.js → chunk-XCO6YCYM.js} +34 -5
- package/dist/chunk-XCO6YCYM.js.map +1 -0
- package/dist/{chunk-TZ5IHWB2.js → chunk-XDKAYSVD.js} +5 -3
- package/dist/chunk-XDKAYSVD.js.map +1 -0
- package/dist/collapsible-panel.d.ts +14 -3
- package/dist/collapsible-panel.js +13 -16
- package/dist/collapsible-panel.js.map +1 -1
- package/dist/content-item.d.ts +46 -0
- package/dist/content-item.js +4 -0
- package/dist/content-item.js.map +1 -0
- package/dist/css-values.d.ts +5 -11
- package/dist/css-values.js +1 -1
- package/dist/disclosure-arrow.d.ts +4 -1
- package/dist/disclosure-arrow.js +1 -1
- package/dist/floating-toolbar.d.ts +17 -6
- package/dist/floating-toolbar.js +1 -1
- package/dist/grid.js +1 -1
- 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 +7 -5
- package/dist/index.js +29 -26
- package/dist/list-action-row.js +2 -1
- package/dist/list-header.d.ts +14 -1
- package/dist/list-header.js +1 -1
- package/dist/list-inset-control.d.ts +1 -1
- package/dist/list-inset-control.js +1 -1
- package/dist/list-inset-text.d.ts +3 -10
- package/dist/list-inset-text.js +1 -1
- package/dist/list-item.js +2 -1
- package/dist/list.d.ts +10 -3
- package/dist/list.js +1 -1
- package/dist/nav-stack.d.ts +50 -5
- package/dist/nav-stack.js +4 -1
- package/dist/pane.d.ts +37 -2
- package/dist/pane.js +1 -1
- package/dist/{panel-toolbar-BFQxFITu.d.ts → panel-toolbar-BN4x0rth.d.ts} +13 -1
- package/dist/popup-menu-register.js +3 -2
- package/dist/popup-menu-register.js.map +1 -1
- package/dist/popup-menu.js +1 -1
- package/dist/row.d.ts +1 -1
- package/dist/row.js +1 -1
- package/dist/select-register.js +70 -3
- package/dist/select-register.js.map +1 -1
- package/dist/select.d.ts +46 -8
- package/dist/select.js +2 -1
- package/dist/{divider-sides-BzB6rphT.d.ts → sides-BPSWde0A.d.ts} +1 -3
- package/dist/skeleton.js +1 -1
- package/dist/spacer.js +1 -1
- package/dist/split-view.d.ts +31 -3
- package/dist/split-view.js +34 -5
- package/dist/split-view.js.map +1 -1
- package/dist/state-banner.js +1 -1
- package/dist/styles/app-tab.css +31 -0
- package/dist/styles/badge.css +32 -11
- package/dist/styles/catalog/components/catalog-example.css +1 -1
- package/dist/styles/catalog/components/catalog-stage.css +1 -1
- package/dist/styles/collapsible-panel.css +199 -42
- package/dist/styles/content-item.css +30 -0
- package/dist/styles/floating-toolbar.css +26 -2
- package/dist/styles/foundation.css +28 -19
- package/dist/styles/layout.css +1 -21
- package/dist/styles/list-action-row.css +13 -1
- package/dist/styles/list-header.css +0 -12
- package/dist/styles/list-inset-text.css +1 -2
- package/dist/styles/list-item.css +14 -1
- package/dist/styles/list.css +5 -5
- package/dist/styles/nav-stack.css +63 -71
- package/dist/styles/pane.css +83 -1
- package/dist/styles/popup-menu.css +229 -0
- package/dist/styles/resizable-region.css +70 -15
- package/dist/styles/select.css +60 -19
- package/dist/styles/skeleton.css +30 -3
- package/dist/styles/split-view.css +31 -32
- package/dist/styles/state-banner.css +0 -19
- package/dist/styles/surface-scaffold.css +8 -3
- package/dist/styles/tab-bar.css +79 -28
- package/dist/styles/tab-scaffold.css +60 -14
- package/dist/styles/text.css +17 -1
- package/dist/styles/token-search-field.css +4 -4
- package/dist/styles/toolbar-control-group.css +143 -69
- package/dist/styles/toolbar-text.css +21 -0
- package/dist/styles/toolbar.css +22 -37
- package/dist/styles/value-table.css +19 -2
- package/dist/styles/webawesome.css +3 -1
- package/dist/styles/workbench.css +145 -42
- package/dist/tab-scaffold.d.ts +46 -2
- package/dist/tab-scaffold.js +52 -16
- package/dist/tab-scaffold.js.map +1 -1
- package/dist/token-search-field.d.ts +4 -2
- package/dist/token-search-field.js +1 -1
- package/dist/toolbar-text.d.ts +7 -1
- package/dist/toolbar-text.js +1 -1
- package/dist/toolbar.d.ts +20 -5
- package/dist/toolbar.js +1 -1
- package/dist/{types-D6vzj-VT.d.ts → types-BuHELdXR.d.ts} +39 -6
- package/dist/value-table.js +1 -1
- package/dist/webawesome.d.ts +7 -1
- package/dist/wire-catalog.d.ts +15 -2
- package/dist/wire-catalog.js +12 -2
- package/dist/wire-catalog.js.map +1 -1
- package/dist/wire-scroll-dividers.d.ts +69 -0
- package/dist/wire-scroll-dividers.js +3 -0
- package/dist/wire-scroll-dividers.js.map +1 -0
- package/dist/wire-token-search-fields.js +1 -1
- package/dist/workbench.d.ts +60 -22
- package/dist/workbench.js +1 -1
- package/docs/accessibility.md +116 -7
- package/docs/app-layouts.md +18 -8
- package/docs/catalog.md +26 -7
- package/docs/collapsible-panel.md +32 -9
- package/docs/component-contract.md +182 -30
- package/docs/component-selection.md +59 -46
- package/docs/design/templates/empty-state/with-action-dark.svg +1 -1
- package/docs/design/templates/empty-state/with-action.svg +1 -1
- package/docs/design/templates/empty-state-dark.svg +1 -1
- package/docs/design/templates/empty-state.svg +1 -1
- package/docs/design/templates/list/compact-dark.svg +1 -1
- package/docs/design/templates/list/compact.svg +1 -1
- package/docs/design/templates/list/stack-dark.svg +1 -1
- package/docs/design/templates/list/stack.svg +1 -1
- package/docs/design/templates/list-action-row/default-dark.svg +1 -1
- package/docs/design/templates/list-action-row/default.svg +1 -1
- package/docs/design/templates/list-action-row/selected-dark.svg +1 -1
- package/docs/design/templates/list-action-row/selected.svg +1 -1
- package/docs/design/templates/list-action-row-dark.svg +1 -1
- package/docs/design/templates/list-action-row.svg +1 -1
- package/docs/design/templates/list-dark.svg +1 -1
- package/docs/design/templates/list-item/default-dark.svg +1 -1
- package/docs/design/templates/list-item/default.svg +1 -1
- package/docs/design/templates/list-item/selected-dark.svg +1 -1
- package/docs/design/templates/list-item/selected.svg +1 -1
- package/docs/design/templates/list-item/trailing-dark.svg +1 -1
- package/docs/design/templates/list-item/trailing.svg +1 -1
- package/docs/design/templates/list-item-dark.svg +1 -1
- package/docs/design/templates/list-item.svg +1 -1
- package/docs/design/templates/list.svg +1 -1
- package/docs/design/templates/tab-bar/workspace-tabs-dark.svg +1 -1
- package/docs/design/templates/tab-bar/workspace-tabs.svg +1 -1
- package/docs/design/templates/tab-bar-dark.svg +1 -1
- package/docs/design/templates/tab-bar.svg +1 -1
- package/docs/design/templates/value-table/details-dark.svg +1 -1
- package/docs/design/templates/value-table/details.svg +1 -1
- package/docs/design/templates/value-table-dark.svg +1 -1
- package/docs/design/templates/value-table.svg +1 -1
- package/docs/design-philosophy.md +31 -4
- package/docs/examples/application-ui-profile.json +4 -4
- package/docs/examples/command-palette-adapter.tsx +3 -2
- package/docs/examples/{component-catalog-extension-v2.json → component-composition-extension.json} +3 -3
- package/docs/layout.md +148 -29
- package/docs/nav-stack.md +77 -3
- package/docs/recipes.md +4 -3
- package/docs/split-view.md +54 -5
- package/docs/tab-scaffold.md +73 -2
- package/docs/type-contracts.md +21 -20
- package/docs/ui-analyzer.md +99 -5
- package/docs/ui-doctor.md +10 -0
- package/docs/ux-demo.md +2 -2
- package/docs/webawesome-theme.md +1 -2
- package/docs/workbench.md +57 -11
- package/doctor/index.mjs +6 -1
- package/llms.txt +117 -24
- package/package.json +29 -6
- package/ux-demo/recipes/collapsible-sidebar.tsx +3 -3
- package/ux-demo/recipes/composer-form.tsx +0 -1
- package/ux-demo/recipes/list-detail-dialog.tsx +0 -2
- package/ux-demo/recipes/list-workspace-states.tsx +0 -1
- package/ux-demo/recipes/loading-inspector.tsx +0 -1
- package/ux-demo/recipes/navigation-sidebar.tsx +3 -2
- package/ux-demo/recipes/navigation-stack.tsx +3 -2
- package/ux-demo/recipes/workspace-header.tsx +0 -1
- package/ai/component-catalog-extension-v2.d.ts +0 -7
- package/ai/component-catalog-extension-v2.schema.json +0 -7
- package/dist/chunk-3NBL3OUQ.js.map +0 -1
- package/dist/chunk-4BIMLITI.js.map +0 -1
- package/dist/chunk-5I22LMCV.js.map +0 -1
- package/dist/chunk-5NDQABWK.js.map +0 -1
- package/dist/chunk-5OLVUEND.js.map +0 -1
- package/dist/chunk-7GUQYHKA.js.map +0 -1
- package/dist/chunk-D7GWXIAS.js.map +0 -1
- package/dist/chunk-DQA5FMOX.js +0 -85
- package/dist/chunk-DQA5FMOX.js.map +0 -1
- package/dist/chunk-EAX2GSS4.js.map +0 -1
- package/dist/chunk-GUIHMIT2.js.map +0 -1
- package/dist/chunk-HMQ2ZDGG.js.map +0 -1
- package/dist/chunk-LZXQVUGN.js.map +0 -1
- package/dist/chunk-MTM43SJO.js.map +0 -1
- package/dist/chunk-N7FHFNT6.js.map +0 -1
- package/dist/chunk-R754MHXX.js.map +0 -1
- package/dist/chunk-RNRUVPJ3.js.map +0 -1
- package/dist/chunk-RNZAKSME.js.map +0 -1
- package/dist/chunk-T22EM4ET.js.map +0 -1
- package/dist/chunk-TZ5IHWB2.js.map +0 -1
- package/dist/chunk-WZ2GLEY4.js.map +0 -1
- package/dist/chunk-XD7DWYXG.js +0 -34
- package/dist/chunk-XD7DWYXG.js.map +0 -1
package/docs/nav-stack.md
CHANGED
|
@@ -5,14 +5,19 @@ and out over one another while the top chrome settles. A **single-pane layout is
|
|
|
5
5
|
a `NavStack` with one entry**. It is one of the opt-in app layouts (see
|
|
6
6
|
[`../../docs/23-app-layouts.md`](../../docs/23-app-layouts.md)).
|
|
7
7
|
|
|
8
|
-
Import the component and its
|
|
8
|
+
Import the component and its wiring helper:
|
|
9
9
|
|
|
10
10
|
```ts
|
|
11
11
|
import { NavStack, type NavStackView } from "@kerfjs/ui/nav-stack";
|
|
12
12
|
import { wireNavStack } from "@kerfjs/ui/wire-nav-stack";
|
|
13
|
-
import "@kerfjs/ui/nav-stack.css";
|
|
14
13
|
```
|
|
15
14
|
|
|
15
|
+
In a browser bundler that honors the `browser` export condition (Vite, esbuild, and
|
|
16
|
+
webpack do by default), the import above also
|
|
17
|
+
loads NavStack's stylesheet and those of the components it renders internally
|
|
18
|
+
(`Toolbar`, `ToolbarControlGroup`, `ToolbarText`, `LucideIcon`). Without that condition, import the manual stylesheets instead:
|
|
19
|
+
`@kerfjs/ui/nav-stack.css` plus those components' CSS, or `@kerfjs/ui/styles.css`.
|
|
20
|
+
|
|
16
21
|
## State lives in the app
|
|
17
22
|
|
|
18
23
|
Like every `@kerfjs/ui` component, `NavStack` is declarative: the app owns the
|
|
@@ -49,11 +54,55 @@ views.value = [
|
|
|
49
54
|
`NavStack` renders every entry stacked, the last one active and the rest kept
|
|
50
55
|
mounted (so their DOM state survives) but hidden. Each entry carries a
|
|
51
56
|
`key` (stable identity), `content`, an optional `title`, optional per-view
|
|
52
|
-
`toolbar`
|
|
57
|
+
`leading`, `center`, and trailing `toolbar` groups for the top toolbar, and an
|
|
58
|
+
optional per-view `bottomToolbar`. The component-level
|
|
53
59
|
`bottomToolbar` remains a persistent fallback for views that do not provide one.
|
|
54
60
|
The back control appears automatically once the stack has more than one entry;
|
|
55
61
|
`wireNavStack`'s `onBack` is where the app pops its own signal.
|
|
56
62
|
|
|
63
|
+
## The top toolbar
|
|
64
|
+
|
|
65
|
+
The top chrome is a real `Toolbar`, so it follows the same zone,
|
|
66
|
+
group, and responsive rules as every other toolbar. Its leading zone holds the
|
|
67
|
+
back control (a borderless `ToolbarControlGroup`, shown once the stack has
|
|
68
|
+
depth), then the active view's `leading` groups, then the view's `title` as a
|
|
69
|
+
`ToolbarText`. The view's `center` fills the center zone and its `toolbar`
|
|
70
|
+
fills the trailing zone. Give each zone `ToolbarControlGroup`s or `ToolbarText`,
|
|
71
|
+
as in any toolbar.
|
|
72
|
+
|
|
73
|
+
Configure the toolbar with `toolbarConfig` instead of styling it:
|
|
74
|
+
|
|
75
|
+
```tsx
|
|
76
|
+
<NavStack
|
|
77
|
+
id="mail"
|
|
78
|
+
label="Mail"
|
|
79
|
+
views={views.value}
|
|
80
|
+
backText={previousTitle}
|
|
81
|
+
toolbarConfig={{
|
|
82
|
+
headingLevel: 1,
|
|
83
|
+
titleSize: "xlarge",
|
|
84
|
+
dividerSides: "b",
|
|
85
|
+
responsive: "wrap",
|
|
86
|
+
}}
|
|
87
|
+
/>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
- `toolbarConfig` forwards the `Toolbar` configuration (`dividerSides`,
|
|
91
|
+
`centerAlign`, `responsive`, `responsiveAt`, `safeAreaEdges`) and adds
|
|
92
|
+
`label` (the toolbar's accessible name), `titleSize` (the title's
|
|
93
|
+
`ToolbarText` size, default `large`), and `headingLevel` (expose the title as
|
|
94
|
+
a heading; default a plain span). The defaults keep the stack's own chrome:
|
|
95
|
+
no divider, the standard Toolbar height (a 44px control band with 8px above and below), and the top and side safe-area edges
|
|
96
|
+
claimed.
|
|
97
|
+
- `backIcon` replaces the default chevron-left icon. `backText` adds visible
|
|
98
|
+
text beside it (for example, the previous view's title); visible text names
|
|
99
|
+
the control, so `backLabel` applies only to the icon-only control.
|
|
100
|
+
|
|
101
|
+
The catalog's **Configured toolbar** example shows these together: a level-2
|
|
102
|
+
heading title over a bottom divider, leading and center groups on the root
|
|
103
|
+
view, a trailing group on the pushed view, and `backText` set to the previous
|
|
104
|
+
view's title.
|
|
105
|
+
|
|
57
106
|
Focus follows the controlled stack automatically. On push, `wireNavStack`
|
|
58
107
|
remembers the focused descendant of the departing view and moves focus into the
|
|
59
108
|
new top view. On pop it restores that exact descendant when it still exists. A
|
|
@@ -65,6 +114,31 @@ When a remembered control was removed during the controlled rerender, the same
|
|
|
65
114
|
fallback order applies. Disposing the helper stops future transitions and
|
|
66
115
|
cleans up any temporary fallback `tabindex` it added.
|
|
67
116
|
|
|
117
|
+
## Scroll dividers
|
|
118
|
+
|
|
119
|
+
The stack draws no permanent line between its chrome and the view. With
|
|
120
|
+
`wireScrollDividers(appRoot)` installed (see
|
|
121
|
+
[Layout › Scroll dividers](layout.md#scroll-dividers)), the top chrome shows a
|
|
122
|
+
line along its bottom edge only while the active view's content is scrolled
|
|
123
|
+
beneath it, and the bottom toolbar a line along its top edge only while more
|
|
124
|
+
content lies below it — neither when the content fits. The line follows the
|
|
125
|
+
active view across a push or pop. The chrome's line is overlaid on its bottom
|
|
126
|
+
edge and the bottom toolbar's is its always-present 1px top border, colored
|
|
127
|
+
only while shown, so neither ever moves the chrome or the content. When the view's only child is a `Pane`,
|
|
128
|
+
the line keys on whichever actually scrolls — the view, or the Pane's content —
|
|
129
|
+
and a Pane header or footer draws its own boundary instead. An explicit
|
|
130
|
+
`toolbarConfig.dividerSides` still draws a permanent Toolbar edge.
|
|
131
|
+
|
|
132
|
+
`chromeDividers` configures both lines, with the same values as a `Pane`'s:
|
|
133
|
+
`scroll` (the default) follows the scroll state above and draws nothing until
|
|
134
|
+
the wiring runs; `always` keeps both lines, with or without the wiring; `none`
|
|
135
|
+
drops them even when the wiring reports scroll state. It does not change the
|
|
136
|
+
top Toolbar's own `dividerSides`.
|
|
137
|
+
|
|
138
|
+
```tsx
|
|
139
|
+
<NavStack id="settings" label="Settings" views={views.value} chromeDividers="always" />
|
|
140
|
+
```
|
|
141
|
+
|
|
68
142
|
## Safe areas
|
|
69
143
|
|
|
70
144
|
The stack paints through a device's unsafe areas. Its chrome pads for the top
|
package/docs/recipes.md
CHANGED
|
@@ -57,8 +57,8 @@ component variables.
|
|
|
57
57
|
[Open the recipe](../ux-demo/?component=recipe-navigation-sidebar) · [TSX source](../ux-demo/recipes/navigation-sidebar.tsx)
|
|
58
58
|
|
|
59
59
|
One unpadded `.kui-pane` owns toolbar/content/footer structure. Its
|
|
60
|
-
`.kui-content` uses 24px major gaps; `ListHeader`, `ListItem`, and
|
|
61
|
-
|
|
60
|
+
`.kui-content` uses 24px major gaps; `ListHeader`, `ListItem`, and
|
|
61
|
+
`ContentItem` children own their 8px margin, 1px border, and 8px padding.
|
|
62
62
|
Rows and footer toolbar groups remain 44px tall. The app owns routes,
|
|
63
63
|
permissions, labels, selection, valid section counts and their localized
|
|
64
64
|
`countLabel` phrases, non-count badge content, disclosure state, and revealed
|
|
@@ -205,7 +205,8 @@ Chromium, Firefox, and WebKit by `tests/browser/collapsible-sidebar-recipe.spec.
|
|
|
205
205
|
`@kerfjs/ui/webawesome.css`.
|
|
206
206
|
- Compose, don't style. A recipe ships no stylesheet, sets no inline style, and
|
|
207
207
|
names no class outside the published layout vocabulary (`.kui-content`,
|
|
208
|
-
`.kui-
|
|
208
|
+
`.kui-control-cluster`, …) and themed Web Awesome classes — a content item is
|
|
209
|
+
a `ContentItem`, not a hand-written `.kui-content-item`; it configures
|
|
209
210
|
components through props, `rootAttributes`, and tokens. When a recipe needs a
|
|
210
211
|
capability no component offers, record it as a component gap rather than
|
|
211
212
|
papering over it with CSS. `npm run check:recipes` enforces these rules on
|
package/docs/split-view.md
CHANGED
|
@@ -8,11 +8,16 @@ on compact ones. One of the opt-in app layouts (see
|
|
|
8
8
|
```ts
|
|
9
9
|
import { SplitView } from "@kerfjs/ui/split-view";
|
|
10
10
|
import { deviceClass } from "@kerfjs/ui/device-class";
|
|
11
|
-
|
|
12
|
-
// plus nav-stack.css when the compact path is reachable, and
|
|
13
|
-
// wireResizableRegions / wireNavStack for the interactive behavior.
|
|
11
|
+
// plus wireResizableRegions / wireNavStack for the interactive behavior.
|
|
14
12
|
```
|
|
15
13
|
|
|
14
|
+
In a browser bundler that honors the `browser` export condition (Vite, esbuild, and
|
|
15
|
+
webpack do by default), the import above also
|
|
16
|
+
loads SplitView's stylesheet and those of the components it renders internally
|
|
17
|
+
(its compact `NavStack`, `ResizableRegion`, and the toolbar
|
|
18
|
+
components). Without that condition, import the manual stylesheets instead:
|
|
19
|
+
`@kerfjs/ui/split-view.css` plus those components' CSS, or `@kerfjs/ui/styles.css`.
|
|
20
|
+
|
|
16
21
|
## Safe areas
|
|
17
22
|
|
|
18
23
|
The list pane grows by the inline-start unsafe inset and pads for the edges it
|
|
@@ -53,11 +58,55 @@ const selected = signal<string | null>(null);
|
|
|
53
58
|
app's selection). This is the portrait-tablet / handset presentation; as a
|
|
54
59
|
dialog the compact form is a full-screen or large partial-cover modal.
|
|
55
60
|
|
|
61
|
+
## Configuring the list region and the compact stack
|
|
62
|
+
|
|
63
|
+
`resizable` forwards the list's `ResizableRegion` configuration alongside
|
|
64
|
+
`size`, `min`, and `max`: `separator` (`"hidden"` keeps the resize hit target
|
|
65
|
+
but paints no line), `handleIcon`, `contentOverflow`, and collapse —
|
|
66
|
+
`collapsed`, `transitioning`, `collapseMotion`, `restoreControl`, and
|
|
67
|
+
`restorePosition`. A collapsed list snaps to zero width, renders `inert` and
|
|
68
|
+
`aria-hidden`, and the detail fills the split; the app owns the `collapsed`
|
|
69
|
+
flag and renders the restore control (usually a `FloatingToolbar`). Omitted
|
|
70
|
+
options keep the region's defaults.
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
resizable={{
|
|
74
|
+
size: listWidth.value,
|
|
75
|
+
min: 220,
|
|
76
|
+
max: 480,
|
|
77
|
+
collapsed: listCollapsed.value,
|
|
78
|
+
restoreControl: <ShowThreadsToolbar />,
|
|
79
|
+
}}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`compactStack` configures the compact `NavStack`: `toolbarConfig`, `backIcon`,
|
|
83
|
+
`backText`, `hideToolbar`, the persistent `bottomToolbar`, and `chromeDividers`
|
|
84
|
+
forward to the stack, and `list` / `detail` give each view its own top-toolbar groups
|
|
85
|
+
(`leading`, `center`, trailing `toolbar`) and `bottomToolbar`:
|
|
86
|
+
|
|
87
|
+
```tsx
|
|
88
|
+
compactStack={{
|
|
89
|
+
backText: "Threads",
|
|
90
|
+
toolbarConfig: { headingLevel: 1 },
|
|
91
|
+
list: { toolbar: <ComposeGroup /> },
|
|
92
|
+
detail: { toolbar: <ReplyGroup />, bottomToolbar: <MessageActions /> },
|
|
93
|
+
}}
|
|
94
|
+
```
|
|
95
|
+
|
|
56
96
|
The catalog's **Interactive compact drill-down** example exercises this exact
|
|
57
97
|
controlled flow: a list action sets the selected message, `detailActive` pushes
|
|
58
98
|
its detail, and the wired Back action clears the selection to reveal the
|
|
59
|
-
preserved list.
|
|
60
|
-
|
|
99
|
+
preserved list. It also forwards `compactStack`: a level-2 heading title over
|
|
100
|
+
a bottom divider, a Compose group on the list view, and a Reply group plus a
|
|
101
|
+
bottom toolbar on the detail. Use the same structure in application demos so
|
|
102
|
+
compact examples show the interaction rather than rendering a disconnected
|
|
103
|
+
detail state.
|
|
104
|
+
|
|
105
|
+
The catalog's **Resizable, collapsible list** example forwards `resizable`: a
|
|
106
|
+
hidden separator that still resizes the list (its committed width comes back
|
|
107
|
+
through `wireResizableRegions`' `onCommit` into the app's size signal), a Hide
|
|
108
|
+
control in the list's own toolbar, and a `FloatingToolbar` restore control in
|
|
109
|
+
the split's bottom-start corner.
|
|
61
110
|
|
|
62
111
|
Compose the interactive wiring from the existing helpers — `SplitView` adds no
|
|
63
112
|
wire of its own.
|
package/docs/tab-scaffold.md
CHANGED
|
@@ -9,9 +9,14 @@ It is distinct from `TabBar` (document-oriented, reorderable strips).
|
|
|
9
9
|
```ts
|
|
10
10
|
import { TabScaffold } from "@kerfjs/ui/tab-scaffold";
|
|
11
11
|
import { wireTabScaffold } from "@kerfjs/ui/wire-tab-scaffold";
|
|
12
|
-
import "@kerfjs/ui/tab-scaffold.css";
|
|
13
12
|
```
|
|
14
13
|
|
|
14
|
+
In a browser bundler that honors the `browser` export condition (Vite, esbuild, and
|
|
15
|
+
webpack do by default), the import above also
|
|
16
|
+
loads TabScaffold's stylesheet and those of the components it renders internally
|
|
17
|
+
(the tab `Badge`). Without that condition, import the manual stylesheets instead:
|
|
18
|
+
`@kerfjs/ui/tab-scaffold.css` plus those components' CSS, or `@kerfjs/ui/styles.css`.
|
|
19
|
+
|
|
15
20
|
## Controlled selection
|
|
16
21
|
|
|
17
22
|
The app owns the active tab (a signal); `TabScaffold` renders every tab's scene
|
|
@@ -44,7 +49,8 @@ const dispose = wireTabScaffold(root, {
|
|
|
44
49
|
});
|
|
45
50
|
```
|
|
46
51
|
|
|
47
|
-
Each `TabScaffoldTab` has an `id`, `label`, optional `icon`,
|
|
52
|
+
Each `TabScaffoldTab` has an `id`, `label`, optional `icon`, optional `badge`
|
|
53
|
+
and `badgeLabel` (see [Tab badges](#tab-badges)), and `content`. The
|
|
48
54
|
bottom bar paints through the home-indicator safe area and pads for it and for
|
|
49
55
|
the side insets, while each scene pads for the top and side insets (a scene
|
|
50
56
|
whose only child is a `NavStack` or `Pane` lets that child own them; see
|
|
@@ -52,3 +58,68 @@ whose only child is a `NavStack` or `Pane` lets that child own them; see
|
|
|
52
58
|
truncate horizontally with an ellipsis when a destination name exceeds its
|
|
53
59
|
share of the bar. On larger device classes, promote the tab set to a
|
|
54
60
|
`Workbench` rail or a persistent sidebar instead of a bottom bar.
|
|
61
|
+
|
|
62
|
+
## Scroll divider
|
|
63
|
+
|
|
64
|
+
The bar has no permanent top border. With `wireScrollDividers(appRoot)`
|
|
65
|
+
installed (see [Layout › Scroll dividers](layout.md#scroll-dividers)), it shows
|
|
66
|
+
a line along its top edge only while the active scene's content continues below
|
|
67
|
+
it — not at the scroll end and not when the content fits. The line keys on
|
|
68
|
+
whatever actually scrolls in the scene: the scene itself or, through a sole
|
|
69
|
+
child, a `NavStack`'s active view or a `Pane`'s content. A `NavStack` with its
|
|
70
|
+
own bottom toolbar sits between them, so that toolbar's line applies instead.
|
|
71
|
+
The line is the bar's always-present 1px top border, colored only while shown,
|
|
72
|
+
so it never moves the bar or a tab.
|
|
73
|
+
|
|
74
|
+
`chromeDividers` configures it, with the same values as a `Pane`'s: `scroll`
|
|
75
|
+
(the default) follows the scroll state and draws nothing until the wiring runs;
|
|
76
|
+
`always` keeps the line, with or without the wiring; `none` drops it even when
|
|
77
|
+
the wiring reports content below.
|
|
78
|
+
|
|
79
|
+
## Tab badges
|
|
80
|
+
|
|
81
|
+
Give a tab a `badge` (a count or short string such as `3`, `"99+"`, or
|
|
82
|
+
`"New"`) to show the iOS tab-bar badge: a compact, solid `danger` `Badge` at the
|
|
83
|
+
top-trailing corner of the tab's icon, growing outward as the text lengthens
|
|
84
|
+
(without an icon it sits above the label). The badge is decorative
|
|
85
|
+
(`aria-hidden`); its meaning reaches assistive technology through `badgeLabel`,
|
|
86
|
+
which the tab folds into its accessible name as `"<label>, <badgeLabel>"`:
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
{
|
|
90
|
+
id: "inbox",
|
|
91
|
+
label: "Inbox",
|
|
92
|
+
icon: <LucideIcon icon={Inbox} name="inbox" />,
|
|
93
|
+
badge: unread.value,
|
|
94
|
+
badgeLabel: `${unread.value} unread`,
|
|
95
|
+
content: <InboxStack />,
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
`badgeLabel` defaults to the badge text itself, so supply a localized phrase
|
|
100
|
+
whenever the bare text would be ambiguous. Omitting `badge` (or passing an
|
|
101
|
+
empty string or a non-finite number) renders no badge and leaves the tab's name
|
|
102
|
+
as its label; `0` renders, so pass `undefined` when a count should disappear.
|
|
103
|
+
Keep the text short — clamp large counts (`"99+"`) in the app. The tone follows
|
|
104
|
+
the platform convention and is fixed; do not restyle the badge.
|
|
105
|
+
|
|
106
|
+
### Dot badges
|
|
107
|
+
|
|
108
|
+
For new content without a count, pass `badge: true`. The tab shows the iOS
|
|
109
|
+
tab-bar dot — an 8px solid `danger` `Badge` (`size="dot"`) centered on the
|
|
110
|
+
icon's top-trailing corner (above the label without an icon). A dot has no
|
|
111
|
+
text to fall back on, so `badgeLabel` is required by the types:
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
{
|
|
115
|
+
id: "feed",
|
|
116
|
+
label: "Feed",
|
|
117
|
+
icon: <LucideIcon icon={Rss} name="rss" />,
|
|
118
|
+
badge: hasNewPosts.value ? true : undefined,
|
|
119
|
+
badgeLabel: "New activity",
|
|
120
|
+
content: <FeedStack />,
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The tab's accessible name becomes `"Feed, New activity"`. Pass `undefined` to
|
|
125
|
+
clear the dot; `false` is not a badge value.
|
package/docs/type-contracts.md
CHANGED
|
@@ -11,22 +11,22 @@ public-signature artifact.
|
|
|
11
11
|
|
|
12
12
|
## Strengthened contracts
|
|
13
13
|
|
|
14
|
-
| ID | Compile-time guarantee
|
|
15
|
-
| ---------- |
|
|
16
|
-
| `KUI-T001` | `ListHeader` is a passive heading, a fully named/icon-bearing trailing action, or a controlled disclosure with `action` + `expanded`. Props ignored by the selected mode are rejected.
|
|
17
|
-
| `KUI-T002` | `Select` has a visible `label` or an `ariaLabel`.
|
|
18
|
-
| `KUI-T003` | A literal `Select.value` belongs to its literal `choices`.
|
|
19
|
-
| `KUI-T004` | A literal `SegmentedControl.value` belongs to its literal `choices`.
|
|
20
|
-
| `KUI-T005` | `expanded`, `expandAction`, and `expandLabel` exist only on `TokenSearchField({ collapsible: true })`.
|
|
21
|
-
| `KUI-T006` | `TokenSearchEditorAttributes` accepts application `data-*` metadata but rejects component-owned identity, morph, count, and placeholder attributes.
|
|
22
|
-
| `KUI-T007` | `ToolbarText.maxLines` requires `wrap: true`; it is never silently ignored in typed code.
|
|
23
|
-
| `KUI-T008` | A literal `TabScaffold.active` id belongs to its literal `tabs`.
|
|
24
|
-
| `KUI-T009` | Adjacent-token keyboard removal requires `onRemoveToken`; disabling removal rejects the now-meaningless callback.
|
|
25
|
-
| `KUI-T010` | Finite public variants have named exported union types, including divider sides, tab activation, banner urgency, and all AppTab, TabBar, ToolbarControlGroup, and Select presentation axes; the convenience root barrel re-exports them.
|
|
26
|
-
| `KUI-T011` | Semantic component zones use the recursive `KerfUiContent` type: `SafeHtml`, runtime-empty booleans/nullish values, and readonly nested arrays are valid; arbitrary strings, numbers, and signals are rejected. Explicit text positions such as `ListInsetText` retain their text exception.
|
|
27
|
-
| `KUI-T012` | `List.gap` accepts finite `UiSpaceName` shorthands or a complete branded `CssLength`; raw strings and non-standalone `CssLengthExpression` arithmetic are rejected. `calc(plus(...))` promotes a typed expression to a complete value.
|
|
28
|
-
| `KUI-T013` | CSS-valued props preserve property grammar: `List.flex` uses `CssFlex`, `Skeleton` dimensions use `CssSize`/`CssLength`, and choice icons use `CssForegroundColor` (foreground tokens via `uiColor()` or `foregroundColorVar()`; fill
|
|
29
|
-
| `KUI-T014` | Stable single-root visual components accept the explicit native `slot` attribute. Multi-root `ResizableRegion` and `CollapsiblePanel` remain excluded because no single returned element can own the assignment, and other arbitrary native attributes remain rejected.
|
|
14
|
+
| ID | Compile-time guarantee |
|
|
15
|
+
| ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
16
|
+
| `KUI-T001` | `ListHeader` is a passive heading, a fully named/icon-bearing trailing action, or a controlled disclosure with `action` + `expanded`. Props ignored by the selected mode are rejected. |
|
|
17
|
+
| `KUI-T002` | `Select` has a visible `label` or an `ariaLabel`. |
|
|
18
|
+
| `KUI-T003` | A literal `Select.value` belongs to its literal `choices`. |
|
|
19
|
+
| `KUI-T004` | A literal `SegmentedControl.value` belongs to its literal `choices`. |
|
|
20
|
+
| `KUI-T005` | `expanded`, `expandAction`, and `expandLabel` exist only on `TokenSearchField({ collapsible: true })`. |
|
|
21
|
+
| `KUI-T006` | `TokenSearchEditorAttributes` accepts application `data-*` metadata but rejects component-owned identity, morph, count, and placeholder attributes. |
|
|
22
|
+
| `KUI-T007` | `ToolbarText.maxLines` requires `wrap: true`; it is never silently ignored in typed code. |
|
|
23
|
+
| `KUI-T008` | A literal `TabScaffold.active` id belongs to its literal `tabs`. |
|
|
24
|
+
| `KUI-T009` | Adjacent-token keyboard removal requires `onRemoveToken`; disabling removal rejects the now-meaningless callback. |
|
|
25
|
+
| `KUI-T010` | Finite public variants have named exported union types, including divider sides, tab activation, banner urgency, and all AppTab, TabBar, ToolbarControlGroup, and Select presentation axes; the convenience root barrel re-exports them. |
|
|
26
|
+
| `KUI-T011` | Semantic component zones use the recursive `KerfUiContent` type: `SafeHtml`, runtime-empty booleans/nullish values, and readonly nested arrays are valid; arbitrary strings, numbers, and signals are rejected. Explicit text positions such as `ListInsetText` retain their text exception. |
|
|
27
|
+
| `KUI-T012` | `List.gap` accepts finite `UiSpaceName` shorthands or a complete branded `CssLength`; raw strings and non-standalone `CssLengthExpression` arithmetic are rejected. `calc(plus(...))` promotes a typed expression to a complete value. |
|
|
28
|
+
| `KUI-T013` | CSS-valued props preserve property grammar: `List.flex` uses `CssFlex`, `Skeleton` dimensions use `CssSize`/`CssLength`, and choice icons use `CssForegroundColor` (foreground tokens via `uiColor()` or `foregroundColorVar()`; fill tokens such as `uiColor('success-fill-quiet')` are rejected); row declaration strings are absent. |
|
|
29
|
+
| `KUI-T014` | Stable single-root visual components accept the explicit native `slot` attribute. Multi-root `ResizableRegion` and `CollapsiblePanel` remain excluded because no single returned element can own the assignment, and other arbitrary native attributes remain rejected. |
|
|
30
30
|
|
|
31
31
|
`KerfUiContent` lets conditionals and mapped component collections be direct
|
|
32
32
|
siblings without an otherwise-unnecessary `Fragment`:
|
|
@@ -113,9 +113,10 @@ move errors into casts without making the integration safer.
|
|
|
113
113
|
`{ keyboard: { removeAdjacentToken: false } }` when only caret navigation is
|
|
114
114
|
wanted.
|
|
115
115
|
- Add `wrap: true` anywhere `ToolbarText.maxLines` is used.
|
|
116
|
-
- Replace `Toolbar({ divider: false })` with `dividerSides: ''
|
|
117
|
-
|
|
118
|
-
`
|
|
116
|
+
- Replace `Toolbar({ divider: false })` with `dividerSides: ''`, which is now
|
|
117
|
+
the default (a toolbar pinned over scrolling content gets its divider from
|
|
118
|
+
`wireScrollDividers` through its `Pane`); canonical combinations such as `b`,
|
|
119
|
+
`tr`, and `trbl` select permanent physical edges.
|
|
119
120
|
- Replace raw `List.gap` strings with a direct spacing shorthand (`"xs"`,
|
|
120
121
|
`"m"`) or a complete value from `@kerfjs/ui/css-values`. Replace
|
|
121
122
|
`gap="0.25rem"` with `gap={rem(0.25)}` and wrap sums with `calc(plus(...))`.
|
|
@@ -123,7 +124,7 @@ move errors into casts without making the integration safer.
|
|
|
123
124
|
keyword; replace raw Skeleton dimensions with `px`/`rem`/`em`/`pct` builders;
|
|
124
125
|
and replace raw choice colors with a foreground token such as
|
|
125
126
|
`uiColor('success-on-quiet')` or an app-owned `foregroundColorVar()`.
|
|
126
|
-
`SelectChoice.color` rejects fill
|
|
127
|
+
`SelectChoice.color` rejects fill tokens (`uiColor('success-fill-quiet')`) and
|
|
127
128
|
unqualified `colorVar()` values because a fill paints a nearly invisible
|
|
128
129
|
icon.
|
|
129
130
|
- Remove `style` from `ListItem` and `ListActionRow`; use `className`, public
|
package/docs/ui-analyzer.md
CHANGED
|
@@ -61,7 +61,7 @@ policy, or analysis inputs to the containing application.
|
|
|
61
61
|
| `KUI-L002` | error | A stylesheet references an unknown or private `--kui-*` token. |
|
|
62
62
|
| `KUI-L003` | error | One element combines public classes that claim the same geometry. |
|
|
63
63
|
| `KUI-L004` | review | Nested literal classes both add a content inset. |
|
|
64
|
-
| `KUI-L005` |
|
|
64
|
+
| `KUI-L005` | — | Retired; folded into `KUI-L019` (see below). |
|
|
65
65
|
| `KUI-L006` | review | Literal spacing falls outside Kerf's approved scale. |
|
|
66
66
|
| `KUI-L007` | error | A declared scroll owner is nested inside another scroll owner. |
|
|
67
67
|
| `KUI-L008` | review | A dynamic class expression cannot be classified soundly. |
|
|
@@ -75,6 +75,10 @@ policy, or analysis inputs to the containing application.
|
|
|
75
75
|
| `KUI-L016` | error | A removed declaration-list escape hatch is used. |
|
|
76
76
|
| `KUI-L017` | review | A valid but exceptional off-scale shorthand needs justification. |
|
|
77
77
|
| `KUI-L018` | review | A loud fill override lacks a governing `on-loud`, or the literal pair is below 4.5:1. |
|
|
78
|
+
| `KUI-L019` | error | A rule's subject is another package's component (class, `data-component`, or tag). |
|
|
79
|
+
| `KUI-L020` | error | CSS reads or writes another component's private `--_*` variable. |
|
|
80
|
+
| `KUI-L021` | error | CSS overrides a component token that a typed prop sets. |
|
|
81
|
+
| `KUI-L022` | error | A class placed on a component's root is styled by the application (a hook class). |
|
|
78
82
|
|
|
79
83
|
Errors are provable contract violations and make the command exit 1. Review
|
|
80
84
|
findings are deliberately heuristic and do not fail by default; pass
|
|
@@ -92,9 +96,10 @@ CSS extension points. A component catalog may additionally list shadow-part
|
|
|
92
96
|
names in `boundaries.publicParts`; all other `::part()` targets are private.
|
|
93
97
|
Part names are scoped to that entry's `boundaries.rootClass`, so an extension
|
|
94
98
|
point on one component does not authorize the same-named part on another.
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
99
|
+
Selectors for application-owned content remain allowed, including in a
|
|
100
|
+
component's context (`.kui-pane > .my-content`): a public class is an
|
|
101
|
+
extension point for naming a context, not for restyling the component itself,
|
|
102
|
+
which `KUI-L019` reports.
|
|
98
103
|
|
|
99
104
|
Catalog entries may also publish `cssValueProps`. Each path names its grammar,
|
|
100
105
|
finite shorthands, canonical and exceptional scale steps, accepted typed
|
|
@@ -103,6 +108,94 @@ uses that same metadata for direct component calls and JSX, including nested
|
|
|
103
108
|
paths such as `choices[].color`; consumer catalogs receive identical checks.
|
|
104
109
|
Dynamic values remain a type-system responsibility rather than being guessed.
|
|
105
110
|
|
|
111
|
+
## Component ownership (`KUI-L019`–`KUI-L022`)
|
|
112
|
+
|
|
113
|
+
Components own their styles and are configured, never overridden. These
|
|
114
|
+
diagnostics apply the package's own `check:css-ownership` rules to
|
|
115
|
+
applications and component packages; the selector parsing is the same module
|
|
116
|
+
(`analyzer/selectors.mjs`), so the package rule and the consumer rule agree on
|
|
117
|
+
which element a selector styles.
|
|
118
|
+
|
|
119
|
+
- **`KUI-L019` — a rule restyles a cataloged component.** The rule's subject
|
|
120
|
+
(the rightmost compound of each selector, ignoring `:has()` and `:not()`
|
|
121
|
+
arguments) names a public class of a cataloged component (`.kui-toolbar`,
|
|
122
|
+
`.kui-list-item__label`, `.acme-meter`), its `[data-component="…"]` root, or
|
|
123
|
+
a Web Awesome tag the package themes (`wa-button`, `wa-select`), and the rule
|
|
124
|
+
sets at least one ordinary property. A `::part()` subject is left to
|
|
125
|
+
`KUI-L011`; a rule that only sets custom properties is configuration, judged
|
|
126
|
+
by the token rules. Forcing a component's dimensions is one such restyle
|
|
127
|
+
and reports here once: `.kui-pane { width: 300px }`.
|
|
128
|
+
- **`KUI-L020` — another component's private variable.** CSS reads or writes a
|
|
129
|
+
`--_<root>-*` variable of a cataloged component (`--_kui-list-gap`), or any
|
|
130
|
+
`--_kui-*` variable.
|
|
131
|
+
- **`KUI-L021` — a token a typed prop sets.** CSS assigns `--<root>-<prop>`
|
|
132
|
+
where the component has that typed prop (`--kui-list-gap` is `List gap`,
|
|
133
|
+
`--kui-floating-toolbar-inset` is `FloatingToolbar inset`). The message
|
|
134
|
+
quotes the prop's cataloged example.
|
|
135
|
+
- **`KUI-L022` — a hook class on a component's root.** A literal class on an
|
|
136
|
+
imported component's JSX (`<Toolbar className="header" />`) is the subject
|
|
137
|
+
of a rule in a stylesheet that file imports, so the application restyles the
|
|
138
|
+
component through it. The evidence names the stylesheet, line, and selector.
|
|
139
|
+
|
|
140
|
+
Every message names the configuration to use (the component's typed props,
|
|
141
|
+
public tokens, and variants from its catalog entry) and ends with the same
|
|
142
|
+
route for a real need that has none: report the component gap to the owning
|
|
143
|
+
package (open a feature request) instead of overriding it.
|
|
144
|
+
|
|
145
|
+
What stays allowed mirrors the package rule, where a child styles itself in a
|
|
146
|
+
parent's context:
|
|
147
|
+
|
|
148
|
+
```css
|
|
149
|
+
/* Your own element in a component's context. */
|
|
150
|
+
.kui-toolbar > .my-widget {
|
|
151
|
+
margin-inline-start: auto;
|
|
152
|
+
}
|
|
153
|
+
/* Keying your own element on a component's state. */
|
|
154
|
+
.shell:has(.kui-select[open]) .my-status {
|
|
155
|
+
opacity: 0.5;
|
|
156
|
+
}
|
|
157
|
+
/* Configuring a component through a public token with no typed prop. */
|
|
158
|
+
.kui-list {
|
|
159
|
+
--kui-list-divider-color: var(--kui-color-neutral-border-quiet);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* KUI-L019, KUI-L020, KUI-L021. */
|
|
163
|
+
.kui-toolbar {
|
|
164
|
+
padding: 0;
|
|
165
|
+
}
|
|
166
|
+
.app {
|
|
167
|
+
--_kui-list-gap: 2px;
|
|
168
|
+
--kui-list-gap: 4px;
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Ownership is decided per package: a stylesheet belongs to the package whose
|
|
173
|
+
`package.json` is nearest it, and only other packages' catalog entries are
|
|
174
|
+
foreign to it. A component package built on Kerf UI therefore styles its own
|
|
175
|
+
cataloged components (including `.kui-toolbar > .acme-meter` from its own
|
|
176
|
+
stylesheet) without findings, while an application that restyles
|
|
177
|
+
`.acme-meter` is reported against `@acme/widgets`. All four ids are
|
|
178
|
+
ownership-boundary diagnostics, so `--adoption` reports them as review
|
|
179
|
+
findings. `eslint-plugin-kerfjs`'s `ui-component-ownership` rule reports
|
|
180
|
+
`KUI-L020` and `KUI-L021` in JavaScript and TypeScript (style strings, style
|
|
181
|
+
objects, and `style.setProperty()`), where this analyzer reads only CSS.
|
|
182
|
+
|
|
183
|
+
### Retired: `KUI-L005` (forced component dimension)
|
|
184
|
+
|
|
185
|
+
`KUI-L005` used to report, as a review finding, any `width`/`height`/`min-*`/
|
|
186
|
+
`max-*` declaration in a rule that mentioned a public component class
|
|
187
|
+
anywhere in its selector. `KUI-L019` now reports every restyle whose subject is
|
|
188
|
+
a cataloged component — dimensions included — so the subject case was
|
|
189
|
+
double-reported (an error and a review finding for one declaration). Its only
|
|
190
|
+
other shape, a public class as an ancestor
|
|
191
|
+
(`.kui-pane .app-sidebar { width: 240px }`), sizes the application's own
|
|
192
|
+
element in the component's context, which the ownership rules explicitly
|
|
193
|
+
allow. With no unique true positive left,
|
|
194
|
+
the rule was retired rather than narrowed. The analyzer no longer emits it;
|
|
195
|
+
the id stays in `ai/application-ui-diagnostic-ids-v1.json` (listed under
|
|
196
|
+
`retired`) so a profile exception that already names it still loads. Remove
|
|
197
|
+
such exceptions at your convenience.
|
|
198
|
+
|
|
106
199
|
## Loud fill / on-loud pairing (`KUI-L018`)
|
|
107
200
|
|
|
108
201
|
The shipped Web Awesome theme pairs every `--wa-color-{tone}-fill-loud` with a
|
|
@@ -207,6 +300,7 @@ validator.
|
|
|
207
300
|
|
|
208
301
|
Review findings remain visible until explicitly suppressed. Avoid suppressing
|
|
209
302
|
`KUI-L001`, `KUI-L002`, `KUI-L003`, `KUI-L007`, `KUI-L009`, `KUI-L010`,
|
|
210
|
-
`KUI-L011`, `KUI-L012`, `KUI-L013`, `KUI-L014`, `KUI-L015`,
|
|
303
|
+
`KUI-L011`, `KUI-L012`, `KUI-L013`, `KUI-L014`, `KUI-L015`, `KUI-L016`,
|
|
304
|
+
`KUI-L019`, `KUI-L020`, `KUI-L021`, or `KUI-L022`:
|
|
211
305
|
those indicate a
|
|
212
306
|
definite boundary or parsing failure rather than an aesthetic judgment.
|
package/docs/ui-doctor.md
CHANGED
|
@@ -30,6 +30,16 @@ that lacks a governing `--wa-color-{tone}-on-loud` (in the same or an ancestor
|
|
|
30
30
|
scope, in any stylesheet the same entry loads), or whose literal pair measures
|
|
31
31
|
below 4.5:1 (see [the analyzer rule](./ui-analyzer.md#loud-fill--on-loud-pairing-kui-l018)).
|
|
32
32
|
|
|
33
|
+
Component ownership is part of the same loop. The analyzer stage reports
|
|
34
|
+
application or third-party CSS that restyles another package's component
|
|
35
|
+
(`KUI-L019`), touches its private `--_*` variables (`KUI-L020`), overrides a
|
|
36
|
+
token a typed prop sets (`KUI-L021`), or styles it through a hook class on its
|
|
37
|
+
root (`KUI-L022`); the ESLint stage's `ui-component-ownership` rule reports
|
|
38
|
+
`KUI-L020` / `KUI-L021` in script. Each finding's `action` points at the
|
|
39
|
+
component's configuration, and its message routes a need with no prop to a
|
|
40
|
+
component-gap report instead of an override (see
|
|
41
|
+
[the analyzer rule](./ui-analyzer.md#component-ownership-kui-l019kui-l022)).
|
|
42
|
+
|
|
33
43
|
The browser evaluator is different: it runs the application and is disabled by default. It only runs when configuration supplies `browser.url` or the command receives `--browser-url`. Start and authorize the target application separately.
|
|
34
44
|
|
|
35
45
|
An unavailable or failed stage does not prevent independent stages from reporting. Its final exit is still a configuration failure, so a partial run cannot appear clean.
|
package/docs/ux-demo.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# UX catalog contract
|
|
2
2
|
|
|
3
|
-
Run `npm run dev` from `ui/`. The catalog is a development and review surface, not a second implementation. The development server allows repo-owned assets used by the catalog, and its production bundle uses relative asset URLs so the complete catalog remains intact below preview and proxy paths.
|
|
3
|
+
Run `npm run dev` from `ui/`. The catalog is a development and review surface, not a second implementation. The development server reloads component source edits without a restart: component entries still load through their `dist/browser` wrappers, so each component's reachable CSS is exercised as consumers receive it, but the JavaScript those wrappers re-export (and every other `@kerfjs/ui` subpath) resolves to `src/`, and CSS resolves to `src/` as well. A component that gains a new CSS dependency needs a restart, because the wrapper listing its stylesheets is regenerated only by the build. Production demo builds, previews, and the browser tests use `dist/`. The development server allows repo-owned assets used by the catalog, and its production bundle uses relative asset URLs so the complete catalog remains intact below preview and proxy paths.
|
|
4
4
|
|
|
5
5
|
Every Playwright entry point builds current source before the preview server
|
|
6
6
|
starts. `npm run test:e2e -- tests/browser/row.spec.ts` and a direct focused
|
|
@@ -51,6 +51,6 @@ deterministic state, and semantic layout owners from the [recipe guide](./recipe
|
|
|
51
51
|
- The footer action log is an `aria-live` region, making interactions visible to both people and browser tests.
|
|
52
52
|
- The focused Toast route calls Web Awesome's documented programmatic stack API and notes that Hot Sheet 2 still uses its own app-level toast implementation; the catalog demonstrates ecosystem support without implying current product adoption.
|
|
53
53
|
- Browser coverage walks every Kerf, composition, and Web Awesome route, checks every listed Web Awesome custom element is registered in its focused specimen, exercises the ecosystem disclosure and both relationship directions, validates offline source/guidance hrefs and accessible wide/narrow/200%-zoom wrapping, and covers tab selection/reordering/overflow, semantic palettes and scoped overrides, light/dark rendering, toolbar popup and responsive find behavior, single/multiline search alignment, menu alignment, banner urgency, keyboard resizing, live custom-element values, and representative wide/narrow captures.
|
|
54
|
-
- The production build keeps the catalog shell and Kerf routes in the entry chunk, then dynamically imports the complete Web Awesome specimen and registration surface when an ecosystem route or the ToolbarControlGroup popup specimen is selected. Directly addressed routes pass through the same loader.
|
|
54
|
+
- The production build keeps the catalog shell and Kerf routes in the entry chunk and moves the third-party code loaded at startup (the Web Awesome select and popup-menu registrations with their Lit and Floating UI runtime) into an eagerly preloaded `vendor` chunk, so neither nears the largest-chunk limit in `demo-bundle-budget.json`; only modules statically reachable from the entry qualify, so lazy-only dependencies stay in their lazy chunks. It then dynamically imports the complete Web Awesome specimen and registration surface when an ecosystem route or the ToolbarControlGroup popup specimen is selected. Directly addressed routes pass through the same loader.
|
|
55
55
|
|
|
56
56
|
Before handoff, inspect the actual captures for readability, context, alignment, clipping, spacing, responsiveness, focus, and obvious defects. Fix and recapture rather than treating the screenshot as proof by itself.
|
package/docs/webawesome-theme.md
CHANGED
|
@@ -176,8 +176,7 @@ their open state uses the independent `rotate` property.
|
|
|
176
176
|
|
|
177
177
|
That scale applies to each Web Awesome component's intrinsic glyph and is
|
|
178
178
|
independent of Kerf `DisclosureArrow`, whose default box is 18px relative to
|
|
179
|
-
the root font size and whose consumer override is
|
|
180
|
-
`--kui-disclosure-arrow-size`.
|
|
179
|
+
the root font size and whose consumer override is its typed `size` prop.
|
|
181
180
|
|
|
182
181
|
Tooltip and Popover use arrowless floating surfaces by default, matching Hot
|
|
183
182
|
Sheet 2. The theme sets Web Awesome's public `--wa-tooltip-arrow-size` token to
|