@kerfjs/ui 5.0.0-beta.7 → 5.0.0-beta.71
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 +501 -139
- package/ai/application-ui-diagnostic-ids-v1.json +109 -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 +3905 -446
- 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 +524 -0
- package/ai/component-composition.d.ts +129 -0
- package/ai/component-composition.json +7140 -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 +93 -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 +98 -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 +94 -0
- package/ai/components/list.md +105 -0
- package/ai/components/loading-spinner.md +73 -0
- package/ai/components/lucide-icon.md +78 -0
- package/ai/components/nav-stack.md +104 -0
- package/ai/components/pane.md +101 -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 +113 -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 +94 -0
- package/ai/components/sunken-panel.md +79 -0
- package/ai/components/surface-scaffold.md +78 -0
- package/ai/components/tab-bar.md +113 -0
- package/ai/components/tab-scaffold.md +94 -0
- package/ai/components/tabs.md +95 -0
- package/ai/components/text.md +85 -0
- package/ai/components/token-search-field.md +106 -0
- package/ai/components/toolbar-control-group.md +102 -0
- package/ai/components/toolbar-text.md +79 -0
- package/ai/components/toolbar.md +97 -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 +118 -0
- package/ai/public-api-signatures-v1.md +2748 -210
- package/ai/skill.md +286 -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 +401 -0
- package/analyzer/index.d.mts +53 -0
- package/analyzer/index.mjs +2307 -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 +52 -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} +4 -2
- 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/{panel-header.js → nav-stack.js} +5 -3
- 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 +1 -0
- package/dist/browser/spacer.js +3 -0
- package/dist/browser/split-view.js +11 -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-scaffold.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 +503 -0
- package/dist/catalog.js.map +1 -0
- package/dist/chip.d.ts +35 -0
- package/dist/chip.js +3 -0
- package/dist/chip.js.map +1 -0
- package/dist/chunk-2G2ZJQYK.js +152 -0
- package/dist/chunk-2G2ZJQYK.js.map +1 -0
- package/dist/chunk-3BYFWTP3.js +108 -0
- package/dist/chunk-3BYFWTP3.js.map +1 -0
- package/dist/chunk-47CKKLBE.js +34 -0
- package/dist/chunk-47CKKLBE.js.map +1 -0
- package/dist/chunk-4SQK27MR.js +202 -0
- package/dist/chunk-4SQK27MR.js.map +1 -0
- package/dist/chunk-5I7QGQVT.js +24 -0
- package/dist/chunk-5I7QGQVT.js.map +1 -0
- package/dist/chunk-6DFDTWGG.js +288 -0
- package/dist/chunk-6DFDTWGG.js.map +1 -0
- package/dist/chunk-7OKX3EF6.js +135 -0
- package/dist/chunk-7OKX3EF6.js.map +1 -0
- package/dist/chunk-AHEG27M7.js +66 -0
- package/dist/chunk-AHEG27M7.js.map +1 -0
- package/dist/chunk-AYUHMAI6.js +48 -0
- package/dist/chunk-AYUHMAI6.js.map +1 -0
- package/dist/chunk-B2ZMR7NY.js +85 -0
- package/dist/chunk-B2ZMR7NY.js.map +1 -0
- package/dist/chunk-BFPBS5Y4.js +250 -0
- package/dist/chunk-BFPBS5Y4.js.map +1 -0
- package/dist/chunk-DB5ADJKF.js +775 -0
- package/dist/chunk-DB5ADJKF.js.map +1 -0
- package/dist/chunk-DC6CN2DS.js +123 -0
- package/dist/chunk-DC6CN2DS.js.map +1 -0
- package/dist/chunk-DG6G5EPF.js +35 -0
- package/dist/chunk-DG6G5EPF.js.map +1 -0
- package/dist/{chunk-56RJXPHG.js → chunk-G4S2QU6V.js} +7 -4
- package/dist/chunk-G4S2QU6V.js.map +1 -0
- package/dist/chunk-GLDWRCAM.js +49 -0
- package/dist/chunk-GLDWRCAM.js.map +1 -0
- package/dist/chunk-I3Q7KKYM.js +33 -0
- package/dist/chunk-I3Q7KKYM.js.map +1 -0
- package/dist/chunk-IA7TMD4Y.js +288 -0
- package/dist/chunk-IA7TMD4Y.js.map +1 -0
- package/dist/chunk-J3KGJ6P6.js +135 -0
- package/dist/chunk-J3KGJ6P6.js.map +1 -0
- package/dist/chunk-K47P7QZC.js +17 -0
- package/dist/chunk-K47P7QZC.js.map +1 -0
- package/dist/chunk-K67Y2JNF.js +222 -0
- package/dist/chunk-K67Y2JNF.js.map +1 -0
- package/dist/chunk-KCCEH7RF.js +492 -0
- package/dist/chunk-KCCEH7RF.js.map +1 -0
- package/dist/chunk-KLJKU6ZL.js +109 -0
- package/dist/chunk-KLJKU6ZL.js.map +1 -0
- package/dist/chunk-KVBRMEPM.js +44 -0
- package/dist/chunk-KVBRMEPM.js.map +1 -0
- package/dist/chunk-M6DEEBEF.js +156 -0
- package/dist/chunk-M6DEEBEF.js.map +1 -0
- package/dist/chunk-MEY33VWB.js +44 -0
- package/dist/chunk-MEY33VWB.js.map +1 -0
- package/dist/chunk-MP2GDBQZ.js +50 -0
- package/dist/chunk-MP2GDBQZ.js.map +1 -0
- package/dist/chunk-NC4CFOID.js +188 -0
- package/dist/chunk-NC4CFOID.js.map +1 -0
- package/dist/chunk-NCSWXG7G.js +80 -0
- package/dist/chunk-NCSWXG7G.js.map +1 -0
- package/dist/chunk-NN6GYOA2.js +47 -0
- package/dist/chunk-NN6GYOA2.js.map +1 -0
- package/dist/chunk-OXO2QJWV.js +55 -0
- package/dist/chunk-OXO2QJWV.js.map +1 -0
- package/dist/chunk-P7D3EMXM.js +52 -0
- package/dist/chunk-P7D3EMXM.js.map +1 -0
- package/dist/chunk-PSHUSWQH.js +18 -0
- package/dist/chunk-PSHUSWQH.js.map +1 -0
- package/dist/chunk-Q6YU3BT7.js +138 -0
- package/dist/chunk-Q6YU3BT7.js.map +1 -0
- package/dist/chunk-QJ5VFCW3.js +131 -0
- package/dist/chunk-QJ5VFCW3.js.map +1 -0
- package/dist/chunk-RGS4WX2M.js +44 -0
- package/dist/chunk-RGS4WX2M.js.map +1 -0
- package/dist/chunk-RNQNEENY.js +146 -0
- package/dist/chunk-RNQNEENY.js.map +1 -0
- package/dist/chunk-RVERAFFY.js +291 -0
- package/dist/chunk-RVERAFFY.js.map +1 -0
- package/dist/chunk-SLWCCHNP.js +491 -0
- package/dist/chunk-SLWCCHNP.js.map +1 -0
- package/dist/chunk-SMZGAPCU.js +70 -0
- package/dist/chunk-SMZGAPCU.js.map +1 -0
- package/dist/{chunk-7BR3DO2A.js → chunk-SRSJO5QE.js} +13 -4
- package/dist/chunk-SRSJO5QE.js.map +1 -0
- package/dist/chunk-TJK44RQC.js +452 -0
- package/dist/chunk-TJK44RQC.js.map +1 -0
- package/dist/chunk-UIDKY4UB.js +14 -0
- package/dist/chunk-UIDKY4UB.js.map +1 -0
- package/dist/chunk-V3DX3K65.js +43 -0
- package/dist/chunk-V3DX3K65.js.map +1 -0
- package/dist/chunk-VZOFZPSO.js +71 -0
- package/dist/chunk-VZOFZPSO.js.map +1 -0
- package/dist/chunk-W2AC6Q2A.js +83 -0
- package/dist/chunk-W2AC6Q2A.js.map +1 -0
- package/dist/chunk-WF75U3V4.js +33 -0
- package/dist/chunk-WF75U3V4.js.map +1 -0
- package/dist/chunk-WTSNV5RG.js +52 -0
- package/dist/chunk-WTSNV5RG.js.map +1 -0
- package/dist/{chunk-YGN7OMLT.js → chunk-X5QSICJ3.js} +8 -5
- package/dist/chunk-X5QSICJ3.js.map +1 -0
- package/dist/chunk-YDGNU2OD.js +61 -0
- package/dist/chunk-YDGNU2OD.js.map +1 -0
- package/dist/collapsible-panel.d.ts +133 -0
- package/dist/collapsible-panel.js +131 -0
- package/dist/collapsible-panel.js.map +1 -0
- package/dist/content-item.d.ts +81 -0
- package/dist/content-item.js +4 -0
- package/dist/content-item.js.map +1 -0
- package/dist/css-values.d.ts +107 -0
- package/dist/css-values.js +3 -0
- package/dist/css-values.js.map +1 -0
- package/dist/device-class.js +33 -5
- 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 +50 -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 +34 -14
- package/dist/index.js +43 -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 +99 -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 +9 -2
- package/dist/loading-spinner.js +2 -1
- package/dist/lucide-icon.d.ts +9 -2
- package/dist/lucide-icon.js +2 -1
- package/dist/nav-stack.d.ts +66 -10
- package/dist/nav-stack.js +6 -1
- package/dist/pane.d.ts +108 -0
- package/dist/pane.js +4 -0
- package/dist/pane.js.map +1 -0
- package/dist/panel-toolbar-DDKh4uKd.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 +243 -2
- package/dist/select-register.js.map +1 -1
- package/dist/select.d.ts +102 -8
- package/dist/select.js +3 -1
- package/dist/semantic-content-BbzjvSu9.d.ts +14 -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 +39 -7
- package/dist/split-view.js +120 -10
- package/dist/split-view.js.map +1 -1
- package/dist/state-banner.d.ts +18 -6
- 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 +12 -0
- package/dist/styles/catalog.css +5 -0
- package/dist/styles/chip.css +132 -0
- package/dist/styles/collapsible-panel.css +575 -0
- package/dist/styles/content-item.css +75 -0
- package/dist/styles/document.css +23 -0
- package/dist/styles/floating-toolbar.css +119 -0
- package/dist/styles/foundation.css +178 -40
- package/dist/styles/grid.css +35 -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 +5 -0
- package/dist/styles/nav-stack.css +172 -47
- package/dist/styles/pane.css +263 -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 +29 -0
- package/dist/styles/surface-scaffold.css +56 -0
- package/dist/styles/tab-bar.css +147 -9
- package/dist/styles/tab-scaffold.css +126 -3
- package/dist/styles/text.css +112 -0
- package/dist/styles/token-search-field.css +155 -55
- package/dist/styles/toolbar-control-group.css +608 -29
- package/dist/styles/toolbar-text.css +101 -8
- package/dist/styles/toolbar.css +343 -12
- package/dist/styles/value-table.css +34 -4
- package/dist/styles/webawesome.css +365 -10
- package/dist/styles/workbench.css +980 -7
- package/dist/sunken-panel.d.ts +27 -0
- package/dist/sunken-panel.js +3 -0
- package/dist/sunken-panel.js.map +1 -0
- package/dist/surface-scaffold.d.ts +30 -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-scaffold.d.ts +57 -7
- package/dist/tab-scaffold.js +83 -9
- package/dist/tab-scaffold.js.map +1 -1
- package/dist/text.d.ts +56 -0
- package/dist/text.js +3 -0
- package/dist/text.js.map +1 -0
- package/dist/token-search-field-CVGwDn2y.d.ts +154 -0
- package/dist/token-search-field.d.ts +3 -43
- package/dist/token-search-field.js +2 -1
- 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 +77 -7
- package/dist/toolbar-control-group.js +3 -1
- package/dist/toolbar-text.d.ts +35 -4
- package/dist/toolbar-text.js +2 -1
- package/dist/toolbar.d.ts +59 -7
- package/dist/toolbar.js +1 -1
- package/dist/types-BuHELdXR.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 +327 -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 +147 -7
- 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-scaffold.js +9 -4
- package/dist/wire-tab-scaffold.js.map +1 -1
- package/dist/wire-token-search-fields.d.ts +65 -3
- package/dist/wire-token-search-fields.js +2 -1
- 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 +244 -9
- package/dist/workbench.js +17 -15
- package/dist/workbench.js.map +1 -1
- package/docs/accessibility.md +476 -24
- package/docs/app-layouts.md +106 -8
- package/docs/apple-hig.md +1 -0
- package/docs/catalog.md +483 -0
- package/docs/collapsible-panel.md +371 -0
- package/docs/component-contract.md +667 -56
- package/docs/component-integration.md +75 -0
- package/docs/component-selection.md +540 -95
- 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/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-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/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/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 +138 -0
- package/docs/design-philosophy.md +48 -20
- package/docs/device-class.md +10 -9
- package/docs/document-baseline.md +38 -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 +534 -59
- package/docs/nav-stack.md +138 -14
- package/docs/recipes.md +137 -54
- package/docs/split-view.md +74 -6
- package/docs/sunken-panel.md +87 -0
- package/docs/surface-scaffold.md +28 -0
- package/docs/tab-scaffold.md +99 -10
- package/docs/type-contracts.md +134 -0
- package/docs/ui-analyzer.md +384 -0
- package/docs/ui-doctor.md +153 -0
- package/docs/ui-evaluator.md +139 -0
- package/docs/ux-demo.md +41 -16
- package/docs/webawesome-theme.md +218 -16
- package/docs/workbench.md +608 -12
- package/doctor/cli.mjs +120 -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 +1364 -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 +445 -48
- package/package.json +249 -37
- 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 +282 -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 +79 -24
- 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/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-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-KJYXOTG3.js +0 -10
- package/dist/chunk-KJYXOTG3.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-N3SUXLLS.js +0 -23
- package/dist/chunk-N3SUXLLS.js.map +0 -1
- package/dist/chunk-PONXLV5U.js +0 -19
- package/dist/chunk-PONXLV5U.js.map +0 -1
- package/dist/chunk-TZNCCM5H.js +0 -20
- package/dist/chunk-TZNCCM5H.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 -28
- 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/ux-demo/recipes/master-detail-dialog.tsx +0 -45
- package/ux-demo/recipes/recipes.css +0 -355
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# Browser UI quality evaluator
|
|
2
|
+
|
|
3
|
+
`kerf-ui-evaluate` is the runtime half of Kerf's UI integration checks. The
|
|
4
|
+
static [`kerf-ui-analyze`](./ui-analyzer.md) command finds source-level ownership
|
|
5
|
+
mistakes; this Playwright-backed evaluator loads a running application and
|
|
6
|
+
records what a browser can establish about the rendered result.
|
|
7
|
+
|
|
8
|
+
Install Playwright beside `@kerfjs/ui` and install its browsers in CI:
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install --save-dev playwright
|
|
12
|
+
npx playwright install --with-deps chromium firefox webkit
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Start the application separately, then evaluate its URL from the project root:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx kerf-ui-evaluate \
|
|
19
|
+
--url http://127.0.0.1:4173 \
|
|
20
|
+
--root . \
|
|
21
|
+
--output artifacts/kerf-ui
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The command discovers and resolves the same `.kerf-ui-profile.json` layers as
|
|
25
|
+
the static analyzer. By default it runs Chromium, Firefox, and WebKit through
|
|
26
|
+
six contexts: wide, intermediate, narrow, a half-width CSS viewport representing
|
|
27
|
+
200% browser zoom, dark color scheme, and reduced motion. Use
|
|
28
|
+
`--browser chromium` for a fast local loop; keep all three engines in CI.
|
|
29
|
+
|
|
30
|
+
## Objective checks
|
|
31
|
+
|
|
32
|
+
The versioned JSON report uses stable `KUI-B###` codes and includes the context,
|
|
33
|
+
selector, measured evidence, and a repair-oriented message for each finding.
|
|
34
|
+
|
|
35
|
+
| Code | Browser fact |
|
|
36
|
+
| ---------- | -------------------------------------------------------------------------------- |
|
|
37
|
+
| `KUI-B001` | Navigation, timeout, or browser-context failure |
|
|
38
|
+
| `KUI-B010` | Horizontal page overflow |
|
|
39
|
+
| `KUI-B011` | Interactive content clipped by a hidden/clip owner or entirely off viewport |
|
|
40
|
+
| `KUI-B012` | An in-viewport action covered at its center point |
|
|
41
|
+
| `KUI-B020` | Positive `tabindex` overriding DOM focus order |
|
|
42
|
+
| `KUI-B021` | Stable per-element focus reaches an invisible control or causes no visual change |
|
|
43
|
+
| `KUI-B022` | Any ARIA widget role is absent from sequential keyboard order |
|
|
44
|
+
| `KUI-B023` | A representative action does not activate with Enter |
|
|
45
|
+
| `KUI-B030` | An interactive control has no text alternative |
|
|
46
|
+
| `KUI-B040` | Alpha-composited interactive text is below its WCAG AA contrast threshold |
|
|
47
|
+
| `KUI-B050` | A button-like target is smaller than 44 × 44 CSS pixels |
|
|
48
|
+
| `KUI-B060` | A pane or declared scroll scope has multiple active scroll owners |
|
|
49
|
+
| `KUI-B070` | Elements in an explicitly declared alignment group drift by more than one pixel |
|
|
50
|
+
| `KUI-B080` | A cataloged root computes geometry assigned to `none`, `parent`, or `child` |
|
|
51
|
+
|
|
52
|
+
For a representative application action that must be operated in the generic
|
|
53
|
+
evaluation, add `data-kui-evaluator-action` to its owning native control or
|
|
54
|
+
keyboard-operable custom control. The evaluator focuses it, presses Enter, and
|
|
55
|
+
accepts a click event or controlled `aria-expanded`, `aria-pressed`,
|
|
56
|
+
`aria-checked`, or `value` transition as evidence. This attribute is test
|
|
57
|
+
instrumentation, not an application event hook.
|
|
58
|
+
|
|
59
|
+
Alignment checks are similarly explicit: put `data-kui-align-group` on the
|
|
60
|
+
shared container and `data-kui-align-edge` on two or more elements whose logical
|
|
61
|
+
start edges must align. Use `data-kui-scroll-scope` only for an application-owned
|
|
62
|
+
scope that is not a `.kui-pane`.
|
|
63
|
+
|
|
64
|
+
Target size (`KUI-B050`) measures the area the pointer can actually reach, not
|
|
65
|
+
just the border box. When a control's box is under 44 × 44, the evaluator
|
|
66
|
+
hit-tests outward from its center with `elementFromPoint`, so a transparent hit
|
|
67
|
+
layer (a positioned `::before`/`::after` that receives pointer events, as on the
|
|
68
|
+
`ListHeader` action) counts toward the target, while a pseudo-element with
|
|
69
|
+
`pointer-events: none`, a clipping ancestor, or an overlapping neighbor does
|
|
70
|
+
not. Where the probe reaches the viewport edge it mirrors the opposite side's
|
|
71
|
+
reach; a control whose center is off-screen or covered keeps its border box.
|
|
72
|
+
The diagnostic evidence reports the measured `width`/`height` and the border
|
|
73
|
+
`box`.
|
|
74
|
+
|
|
75
|
+
Compact density is a documented exception. Inside `[data-density="compact"]` —
|
|
76
|
+
the compact `List`/`ListHeader` family, whose rows are 36px tall — a target
|
|
77
|
+
still needs the full 44px width but only the 36px row height, because a taller
|
|
78
|
+
hit layer would reach into the neighboring row. The evidence's `required` field
|
|
79
|
+
names the floor that applied (`44×44`, or `44×36` in compact density).
|
|
80
|
+
|
|
81
|
+
Accessible names follow ARIA/native naming inputs, including labels, referenced
|
|
82
|
+
content with `aria-hidden` descendants removed, and native input values.
|
|
83
|
+
Geometry checks use each catalog entry's explicit `boundaries.rootClass`; the
|
|
84
|
+
order of `publicClasses` has no runtime meaning.
|
|
85
|
+
|
|
86
|
+
Profile exceptions apply only when both the `KUI-B###` rule and `target` match
|
|
87
|
+
exactly. For the browser evaluator, `target` is the evaluated `startDirectory`
|
|
88
|
+
relative to `workspaceRoot` (for example `apps/settings`); wildcards and broad
|
|
89
|
+
workspace targets remain invalid.
|
|
90
|
+
|
|
91
|
+
## Report and artifacts
|
|
92
|
+
|
|
93
|
+
The public Node API is available at `@kerfjs/ui/evaluator`:
|
|
94
|
+
|
|
95
|
+
```js
|
|
96
|
+
import { evaluateUi } from '@kerfjs/ui/evaluator';
|
|
97
|
+
|
|
98
|
+
const abortController = new AbortController();
|
|
99
|
+
const report = await evaluateUi({
|
|
100
|
+
url: 'http://127.0.0.1:4173',
|
|
101
|
+
workspaceRoot: process.cwd(),
|
|
102
|
+
retention: 'on-failure',
|
|
103
|
+
signal: abortController.signal,
|
|
104
|
+
});
|
|
105
|
+
if (!report.summary.passed) process.exitCode = 1;
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
The default output is `kerf-ui-evidence/report.json`; its schema ships at
|
|
109
|
+
`@kerfjs/ui/evaluator/report.schema.json`. Every retained screenshot has a
|
|
110
|
+
SHA-256 digest. Retention is deterministic:
|
|
111
|
+
|
|
112
|
+
- `on-failure` (default) removes current and stale evaluator screenshots when
|
|
113
|
+
every objective check passes;
|
|
114
|
+
- `always` retains one full-page PNG per browser/context;
|
|
115
|
+
- `never` removes current and stale evaluator screenshots and writes only the
|
|
116
|
+
focused DOM/computed-style evidence in the report.
|
|
117
|
+
|
|
118
|
+
`--timeout` bounds navigation and browser operations, while `--settle` provides
|
|
119
|
+
one small explicit post-navigation delay for applications with asynchronous
|
|
120
|
+
startup. A timeout becomes `KUI-B001` evidence rather than an unstructured crash.
|
|
121
|
+
The Node API accepts an `AbortSignal`; cancellation closes the active browser,
|
|
122
|
+
removes screenshots from the interrupted run, does not write a partial report,
|
|
123
|
+
and rejects with `AbortError`.
|
|
124
|
+
The CLI exits `1` for objective failures, `2` for invocation/profile errors, and
|
|
125
|
+
`0` for a pass; `--no-fail` is available only for evidence-collection jobs.
|
|
126
|
+
|
|
127
|
+
## Human visual review stays human
|
|
128
|
+
|
|
129
|
+
Hierarchy, rhythm, density, aesthetic fit, and the perceived clarity of
|
|
130
|
+
alignment or scroll ownership are not inferred from computed pixels. Every
|
|
131
|
+
report carries the suite-v3 0–2 review rubric with `status: "not-recorded"` and
|
|
132
|
+
an empty rating list. An AI agent may use the retained screenshots as review
|
|
133
|
+
input, but it must record a named reviewer and rationale in the separate
|
|
134
|
+
human-visual evidence workflow; it must not turn a subjective rating into a
|
|
135
|
+
`KUI-B###` assertion.
|
|
136
|
+
|
|
137
|
+
The deterministic good/bad downstream fixtures and three-engine integration
|
|
138
|
+
suite live under `tests/fixtures/ui-evaluator/` and
|
|
139
|
+
`tests/integration/ui-evaluator-downstream.test.ts`.
|
package/docs/ux-demo.md
CHANGED
|
@@ -1,32 +1,57 @@
|
|
|
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
|
+
starts. `npm run test:e2e -- tests/browser/row.spec.ts` and a direct focused
|
|
7
|
+
`npx playwright test tests/browser/row.spec.ts` both run catalog generation and
|
|
8
|
+
demo-conformance preflights, build the package and production catalog, then
|
|
9
|
+
launch Chromium, Firefox, and WebKit. The build emits
|
|
10
|
+
`source-freshness.json`; browser coverage compares it with an independent hash
|
|
11
|
+
of the current `src/` and `ux-demo/` inputs, so a stale `dist-demo` cannot pass
|
|
12
|
+
after a route or component edit. `npm run demo:serve` remains a preview-only
|
|
13
|
+
command for an already-built catalog. The demo-conformance preflight also
|
|
14
|
+
rejects a component route that wraps its `CatalogExampleStack` in a card or
|
|
15
|
+
other container (`catalog-demo/wrapped-example-stack`): single-component demos
|
|
16
|
+
sit directly on the catalog grid, and only composition and recipe routes frame
|
|
17
|
+
their content.
|
|
18
|
+
|
|
19
|
+
Ten lazy production-composition routes live under the `Recipes` category.
|
|
6
20
|
Each `?component=recipe-*` route uses public package primitives, real wiring,
|
|
7
21
|
deterministic state, and semantic layout owners from the [recipe guide](./recipes.md).
|
|
8
22
|
|
|
9
23
|
- It imports public component subpaths, exercising their browser-selected reachable CSS rather than a catalog-only style path.
|
|
10
|
-
- The `
|
|
11
|
-
- The `
|
|
12
|
-
-
|
|
13
|
-
-
|
|
24
|
+
- The `ListActionRow` route demonstrates sibling primary/trailing native controls, independent disabled states, controlled selection, first-line leading-icon alignment for wrapped labels, and an application-owned native popover relationship without nesting controls. The `ListItem` route demonstrates the same multiline leading-icon anchor alongside its single-control navigation contract.
|
|
25
|
+
- The `PopupMenu` route's context example opens one app-owned menu either at the row's right-click point or below its adjacent, keyboard-operable Demand actions button. Its interactive row/button composition opts out of the catalog geometry overlay so the overlay's border and margin highlights do not masquerade as a row inset during activation. The Nested decisions example shows the automatic phone-width submenu placement above or below its parent list, with native ArrowLeft return, Escape dismissal, and child selection.
|
|
26
|
+
- The `AppTab` and `TabBar` routes are focused component specimens: AppTab shows its selected, compact, segmented, icon-only, truncation, placeholder, pending, metadata, and close-icon axes inside the required tablist context; TabBar shows its rail, segmented, inspector, allocation, placement, and accessory-zone axes, including an adjacent action plus a separately pinned end action whose tabs overflow at narrow widths, without application readouts. The separate `Application tabs` composition route demonstrates controlled selection, matching panel content, overflow, adding (a new tab opens `pending` with a spinner and stays selectable while its panel shows a `Skeleton` heading until a simulated load completes), closing, keyboard/pointer reordering, and application-owned ordering. The `ResizableRegion` route likewise replaces only the decorative handle glyph while retaining separator semantics and shared wiring.
|
|
27
|
+
- Every first-party visual component and every free Web Awesome 3.12 component has its own stable `?component=<id>` URL and focused demo. Composite header, menu, and feedback scenarios remain addressable alongside their subcomponents; the root opens the first Kerf component. The former aggregate Web Awesome theme specimen is intentionally omitted because its component families are covered by those focused routes.
|
|
28
|
+
- `ai/component-catalog.json` is the canonical catalog metadata. A deterministic checked-in projection supplies the demo's unique id, category, kind (`component`, `composition`, or `recipe`), source (`kerf` or `webawesome`), name, description, recommendation, direct `uses` dependencies, existing documentation path, and demo-source path; first-party, recipe, and Web Awesome renderer maps are exhaustively typed against its generated id unions. Functional groups follow their authored importance order; components precede compositions inside each group, equal-importance entries use alphabetical order, and the Recipes group comes last. Composition names stay concise and project a visible `Composition` sidebar tag. Non-supported Web Awesome recommendations project to a visible `Discouraged` tag, with Popup as the deliberate conditional exception. Demo paths resolve to the matching `ui/ux-demo/demos/<id>.tsx` or `ui/ux-demo/recipes/*.tsx` file, or to `ui/ux-demo/webawesome-demos.tsx` for Web Awesome entries. `ui/ux-demo/main.tsx` owns only the catalog shell, shared state, routing, and interaction wiring. First-party component entries additionally derive `ui/src/<public-subpath>.tsx` from their canonical `delivery.browserImport` or opt-in `delivery.moduleImport`.
|
|
14
29
|
- Every detail footer groups compact `Demo source` and `Guidance` actions; first-party component details also expose `Component source`. Web Awesome details say `Integration guidance` to distinguish the local integration contract from the upstream component implementation. Each button retains its repository-relative path in the DOM for verification and uses a deploy-safe absolute GitHub blob URL with a contextual new-tab name; the demo does not depend on a local source server or add a package runtime export. At phone widths, the resource group and related-component selector stack as full-width rows, with any resource overflow contained locally so labels cannot overlap the selector or widen the document.
|
|
15
|
-
- The master/detail shell groups first-party routes by category with production `
|
|
16
|
-
- The shell itself uses `@kerfjs/ui/layout.css`: sidebars, details, previews, dialogs, and resize specimens share unpadded panes plus self-contained content items. Its sidebar identity uses the Kerf logo beside a vertically centered title, with
|
|
17
|
-
- The composer-form recipe demonstrates one coherent visible form surface with
|
|
18
|
-
- The
|
|
30
|
+
- The master/detail shell groups first-party routes by category with production `ListHeader` and `ListItem` components. Catalog entries can supply short reusable trailing tags; the Web Awesome projection uses them to label exactly the 15 discouraged choices. The 70 ecosystem components live in a separate `Web Awesome` disclosure with seven subgroups, so they remain discoverable without being presented as first-class `@kerfjs/ui` exports. Direct Web Awesome routes open the disclosure and reveal the selected row at wide sizes; narrow layouts keep the expanded list in document flow rather than introducing a competing nested scroller.
|
|
31
|
+
- The shell itself uses `@kerfjs/ui/layout.css`: sidebars, details, previews, dialogs, and resize specimens share unpadded panes plus self-contained content items. Its sidebar identity uses the Kerf logo beside a vertically centered title, with supporting copy in its own aligned row; the current-view heading is also a toolbar. Collapsing the catalog removes the pane completely and moves its restore action to the main toolbar's leading edge instead of leaving an icon-only rail. The selected view description remains inset below the page toolbar. The checkerboard belongs to the preview scroll owner rather than a viewport-height stage or nested card, and one explicitly repeated SVG tile keeps the pattern continuous through below-fold content. A lightly separated footer keeps live status above compact source, guidance, and relationship groups. The focused `ResizableRegion` specimen stretches its surface through the available stage height and reports committed width in that shared status footer; narrow layouts retain local horizontal access when the pane is resized wider than the stage, and the split remains readable at 200% root scaling. Geometry coverage checks wide, intermediate, narrow, and 200% zoom layouts.
|
|
32
|
+
- The composer-form recipe demonstrates one coherent visible form surface with toolbar title/supporting-copy hierarchy, fields and actions on the shared 8px control gutter, and 24px major rhythm. Its conditional error or success `StateBanner` is the only nested semantic surface. Reset synchronizes the upgraded Web Awesome fields' live value properties with their empty controlled attributes and announces `Draft reset`; browser coverage preserves behavior and verifies wide, narrow, dark, validation, success, reset, 200% zoom, and forced-colors states.
|
|
33
|
+
- The list-detail dialog recipe is laid out like a `Workbench` on roomy devices: a headerless `DialogSurface` modal whose `SplitView` holds a full-height list sidebar `Pane` with its own toolbar beside a full-height detail `Pane` that carries the primary xl title, the `data-dialog="close"` control, and the record actions in its footer. Compact devices get a full-screen sheet with its own labeled header, footer actions, and a list-to-detail drill-down. Browser geometry coverage protects those relationships at wide and narrow widths.
|
|
19
34
|
- Catalog-only brand marks, preview dimensions, checkerboard tiles, and the compound display-settings control retain local geometry because they are specimen chrome or intrinsic control anatomy rather than reusable application spacing roles.
|
|
20
|
-
- The menu composition route demonstrates toolbar/content/footer anatomy, 24px major gaps, 8/1/8 child geometry, the full-width `
|
|
35
|
+
- The menu composition route demonstrates toolbar/content/footer anatomy, 24px major gaps, 8/1/8 child geometry, the full-width `ListHeader` count-or-badge/action split, logical-end 44px action targets with 18px visuals, and 44px row/header/toolbar targets. Its one chevron is a production 18px `DisclosureArrow` inside a controlled Tools header that actually reveals and hides content; ordinary Projects navigation has no false disclosure affordance. Browser assertions cover stable naming, expanded/content transitions, visual rotation, node identity, reduced motion, RTL alignment and containment, and wide, narrow, dark, and 200% layouts. The focused ListHeader route separately shows the shared neutral count pill for Attachments, Notes (including zero), and Duplicates plus a non-count legacy badge, full-width logical-end actions, and no disclosure without content.
|
|
21
36
|
- The `DisclosureArrow` route renders the production 18px root-scaled default without a catalog-only size override. Its two native buttons independently control the default right-to-down chevron and a recognizable right-facing replacement arrow with left-to-up custom directions; both use shortest-path rotation and their names stay stable while `aria-expanded` communicates state. Browser coverage verifies the custom clockwise path, pointer and native keyboard activation, focus, narrow and 200%-zoom stacking with contained labels, consumer sizing, and the independent `.5` Web Awesome glyph scale retained by Kerf `Select`.
|
|
22
|
-
- A detail with relationships renders one
|
|
23
|
-
-
|
|
24
|
-
- Scenarios use deterministic data and cover real variants, long content, disabled state, selection, progress, feedback, overlays, media, helpers, and stateful interactions.
|
|
25
|
-
-
|
|
37
|
+
- A detail with relationships renders one content-fitted `Components` footer selector: `Uses` links to direct dependencies and `Used by` links to reverse dependents. Its popup owns the standard surface inset so headings and even long component names stay clear of the menu border. Choosing either navigates to that component's demo. The relationship group is absent when both sets are empty; no duplicate summary is rendered.
|
|
38
|
+
- Focused demos ship no local stylesheets, inline styles, or styling-only class names. They compose Kerf components first, Web Awesome surfaces where Kerf has no equivalent, and ordinary semantic HTML for the remainder. The catalog-owned `CatalogExample.viewport` contract supplies the few specimen constraints needed to demonstrate layout behavior. Recipes follow the same rule: they ship no stylesheets, inline styles, or styling-only classes, and the catalog frames each one in the `CatalogExample` viewport its exported `presentation` declares (full-width application arrangements span the canvas measure; narrower recipes sit in the centered example column). Demo-only CSS is limited to the document-shell `style.css`, which carries no recipe rules. Decorative chrome and Web Awesome controls share the same semantic system palette instead of carrying a separate demo identity.
|
|
39
|
+
- Scenarios use deterministic data and cover real variants, long content, disabled state, selection, progress, feedback, overlays, media, helpers, and stateful interactions. Individual Web Awesome action, form, layout, navigation, feedback, media, and helper routes provide focused theme specimens without a redundant aggregate route; ListItem and ListHeader demonstrate typed domain metadata, protected native button/disclosure semantics, and a native popover trigger relationship without product props; the Headers composition demonstrates direct toolbar headings with an extra-large title, optional supporting copy, and grouped icon/actions; the Select route verifies that option icons survive unrelated Kerf rerenders and selected slot content follows value changes; the Animation route exposes preset, easing, duration, playback-rate, and transport controls with live lifecycle status; observer routes provide user-driven intersection, mutation, and resize events with live results; ToolbarControlGroup exposes all eight Hot Sheet 2 variants, loads the Web Awesome registrations needed by its popup specimen, and preserves the upgraded dropdown's managed light-DOM children across Kerf rerenders; the Toolbar route composes a collapsible TokenSearchField inside a group, animates between the empty iconic and complete field states, stays open while populated, and focuses the revealed editor; SegmentedControl covers toolbar, rounded-rectangle, pill, equal-width, and disabled presentations; TokenSearchField covers editable ordered chips, pointer and keyboard removal, caret-preserving controlled deletion, editing, clearing, free text, disabled state, and fixed first-line alignment while content wraps; StateBanner exposes every built-in tone with tone-tinted badges, a scoped override, and a placeholder with and without a badge, the badged placeholder in every tone so captures cover the solid badge skeleton; the Application tabs composition uses a Web Awesome card with semantic header/footer slots and Kerf `Text` while demonstrating overflow, edge autoscroll, and controlled pointer/keyboard reordering.
|
|
40
|
+
- The ToolbarControlGroup route also demonstrates the public compact/tight,
|
|
41
|
+
mixed-content, filled-selection, nested-dropdown, and avatar/scrim contracts
|
|
42
|
+
added for consumers that previously restyled group descendants. The compact
|
|
43
|
+
mixed specimen keeps its connected separator plus the standard 8px dropdown
|
|
44
|
+
trigger inset, label, and caret inside both pill and rounded group shapes.
|
|
45
|
+
Avatar images are chrome rather than nested `img`
|
|
46
|
+
elements: a lone avatar paints the group, while a multi-button avatar group
|
|
47
|
+
paints only the pressed selection, with contain fitting in both cases. Its
|
|
48
|
+
collapsible-search specimen follows the selected group shape with a
|
|
49
|
+
concentric inner radius in both collapsed and expanded states.
|
|
50
|
+
- Recipe ownership notes are hidden by default. A page-toolbar toggle reveals each recipe's note as its `CatalogExample` note above the framed specimen, so instructional copy never covers the composition.
|
|
26
51
|
- Settings exercise light/dark, increased contrast, and reduced motion without changing component code. The theme action starts from the operating system's effective color scheme, always names the appearance it will switch to, and installs an explicit light or dark override when activated; contrast and reduced motion expose their independent preferences through `aria-pressed`.
|
|
27
52
|
- The footer action log is an `aria-live` region, making interactions visible to both people and browser tests.
|
|
28
53
|
- 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.
|
|
29
54
|
- 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.
|
|
30
|
-
- 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
|
|
55
|
+
- 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.
|
|
31
56
|
|
|
32
57
|
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
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
free components and the Kerf/Hot Sheet 2 design system.
|
|
5
5
|
|
|
6
6
|
```ts
|
|
7
|
-
import type {} from
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import
|
|
7
|
+
import type {} from "@kerfjs/ui/webawesome";
|
|
8
|
+
import "@kerfjs/ui/webawesome.css";
|
|
9
|
+
import "@awesome.me/webawesome/dist/components/button/button.js";
|
|
10
|
+
import "@awesome.me/webawesome/dist/components/input/input.js";
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
The type-only package import augments `kerfjs/jsx-runtime` with the 70
|
|
@@ -54,6 +54,189 @@ pointer targets. Override `--kui-wa-carousel-icon-size`,
|
|
|
54
54
|
`--kui-wa-carousel-dot-hit-size` on a carousel or containing scope when a
|
|
55
55
|
product needs different geometry.
|
|
56
56
|
|
|
57
|
+
Code text uses Kerf's named monospace stack, `--kui-font-mono`
|
|
58
|
+
(`ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono",
|
|
59
|
+
monospace`), and the theme points `--wa-font-family-code` at it. Web Awesome's
|
|
60
|
+
own `ui-monospace, monospace` renders the generic face (Courier on macOS) in
|
|
61
|
+
Chromium, which does not recognize `ui-monospace`; because the generic
|
|
62
|
+
`monospace` ends any stack, Kerf's token owns the stack rather than appending
|
|
63
|
+
fallbacks after Web Awesome's. Override `--kui-font-mono` to change code text in
|
|
64
|
+
both Kerf and Web Awesome components.
|
|
65
|
+
|
|
66
|
+
Form fields carry the same content-item inset as the Kerf primitives: a 1px
|
|
67
|
+
border with 8px inside it (`--wa-form-control-border-width`,
|
|
68
|
+
`--wa-form-control-padding-block`, and `--wa-form-control-padding-inline` are set
|
|
69
|
+
to the `--kui-layout-item-border-width` / `--kui-layout-item-padding` values), so
|
|
70
|
+
the value sits 9px in from the field edge. Default-size single-line controls
|
|
71
|
+
share Kerf's 44px control height — the height of a Kerf `Select`, a toolbar
|
|
72
|
+
group, and a list row — so a `wa-input` or `wa-button` sits flush beside a Kerf
|
|
73
|
+
`Select`. The theme sets `--wa-form-control-height` to `2.75em` (44px at the
|
|
74
|
+
16px default) on Button, Color Picker, Input, Known Date, Number Input, Radio
|
|
75
|
+
Group, Select, Textarea (its minimum height), and Time Input, so `size="large"`
|
|
76
|
+
scales proportionally while `size="small"` keeps Web Awesome's compact secondary
|
|
77
|
+
height. The token is scoped to those controls rather than the root because Web
|
|
78
|
+
Awesome also derives tag, copy-button, and toast geometry from it. Buttons
|
|
79
|
+
inside a `ToolbarControlGroup` keep the group's 40px (32px compact) control
|
|
80
|
+
height. Each field's top label is inset by that same border +
|
|
81
|
+
padding (9px) so it lines up with the value inside the field, and is styled
|
|
82
|
+
exactly like a `ListHeader` label — uppercase, `--kui-font-xs`, weight 650, quiet
|
|
83
|
+
foreground. This applies to every free field that exposes a top label
|
|
84
|
+
(`::part(form-control-label)` plus the Slider's `::part(label)`). OTP Input
|
|
85
|
+
exposes `label` instead of `form-control-label`; the theme gives it the same
|
|
86
|
+
uppercase 12px/650 treatment. Inline control labels (Checkbox, Switch) keep
|
|
87
|
+
their natural sentence case.
|
|
88
|
+
|
|
89
|
+
On coarse touch devices, the editable part of small and extra-small Web Awesome
|
|
90
|
+
Input, Number Input, Time Input, Textarea, and Select has a 16px minimum text
|
|
91
|
+
size. Small field chrome keeps its compact height and desktop typography stays
|
|
92
|
+
small. This prevents Safari from magnifying the page just to focus text; it does
|
|
93
|
+
not constrain a user's own pinch zoom. App-owned native fields need the same
|
|
94
|
+
editable-text audit.
|
|
95
|
+
|
|
96
|
+
Known Date's field captions and bordered text-like field hints use the same 9px
|
|
97
|
+
inline inset, keeping secondary text aligned with the value rather than the
|
|
98
|
+
field's outer border. This covers Input, Known Date, Number Input, OTP Input,
|
|
99
|
+
Select, Textarea, and Time Input hints; unbordered group hints retain their own
|
|
100
|
+
natural geometry. OTP Input's label and hint both use the 9px field-text inset.
|
|
101
|
+
|
|
102
|
+
Checkbox Group and Radio Group option regions receive the shared 8px inline
|
|
103
|
+
outer inset through `::part(form-control-input)`. Unlike bordered fields, these
|
|
104
|
+
groups have no shell of their own, so the explicit margin places their controls
|
|
105
|
+
on the same content-item geometry without adding padding to each option. The
|
|
106
|
+
Color Picker trigger receives the same 8px inline outer inset because it also
|
|
107
|
+
has no bordered field shell. Slider's complete interactive region receives the
|
|
108
|
+
shared 8px logical inline outer inset through `::part(slider)`, keeping its
|
|
109
|
+
track, markers, references, and hint together without moving the label.
|
|
110
|
+
|
|
111
|
+
Non-field chrome follows explicit, overridable control, surface, and container
|
|
112
|
+
tiers:
|
|
113
|
+
|
|
114
|
+
- `--kui-wa-control-inset` defaults to the 8px content-item padding. It applies
|
|
115
|
+
to tabs, tree-item trailing content, tags, and dropdown items. Tree selection
|
|
116
|
+
also uses Kerf's 8px inline outer margin, so its background reads as an inset
|
|
117
|
+
list item instead of an edge-to-edge stripe. Buttons already consume the same
|
|
118
|
+
`--wa-form-control-padding-inline` 8px value at every size, so no extra part
|
|
119
|
+
override is needed.
|
|
120
|
+
- `--kui-wa-surface-margin` and `--kui-wa-surface-inset` default to 8px.
|
|
121
|
+
Accordion, Card, Details, Callout, and Include use the margin around their
|
|
122
|
+
complete surface and the inset within it. Accordion applies the outer margin
|
|
123
|
+
once to the group rather than separating connected items; Card's header,
|
|
124
|
+
body, and footer all receive the full inset.
|
|
125
|
+
- Plain Details use the 8px `--kui-wa-surface-inset` on the trigger and keep the
|
|
126
|
+
body flush; plain Accordion items use that 8px inset on both trigger and body.
|
|
127
|
+
Outlined and sunken Details use the 16px `--kui-wa-container-inset` on the
|
|
128
|
+
trigger and the 8px surface inset on the body, while framed Accordion items
|
|
129
|
+
use the 16px container inset for both regions.
|
|
130
|
+
- `appearance="sunken"` is a Kerf theme extension for Accordion, Card, and
|
|
131
|
+
Details. It removes raised chrome, paints the lowered semantic surface, and
|
|
132
|
+
uses the shared rounded-rectangle radius. Override
|
|
133
|
+
`--kui-wa-sunken-background` or `--kui-wa-sunken-radius` on an instance or
|
|
134
|
+
containing scope when that surface needs different tokens.
|
|
135
|
+
- `--kui-wa-container-inset` defaults to the 16px homogeneous-group step. Tab
|
|
136
|
+
Panel retains this roomier tier for unframed panel content. Dialog body uses
|
|
137
|
+
the 8px surface inset, while its footer uses the 16px container inset so
|
|
138
|
+
content stays compact and the action group has a clearer boundary. These two
|
|
139
|
+
parts do not inherit the dialog's shared `--spacing` value.
|
|
140
|
+
|
|
141
|
+
## Contextual transparency
|
|
142
|
+
|
|
143
|
+
Keep the shared `--kui-color-*` semantic fills, foregrounds, and borders opaque
|
|
144
|
+
by default. Their light and dark values mirror the Web Awesome theme, and the
|
|
145
|
+
contrast checks in `tests/browser/tone-contrast.spec.ts` assume known surfaces.
|
|
146
|
+
Compositing those tokens over arbitrary app backgrounds changes text contrast
|
|
147
|
+
and makes the same token mean a different visible color in each container.
|
|
148
|
+
|
|
149
|
+
The strongest candidate for transparency is a **component-scoped sunken
|
|
150
|
+
background**, through the existing `--kui-sunken-panel-background` and
|
|
151
|
+
`--kui-wa-sunken-background` overrides. A simple black overlay of 5.5% over
|
|
152
|
+
white approximates `#f1f1f1`, near the current light lowered surface; a second
|
|
153
|
+
nesting level becomes `#e4e4e4`. Matching the current dark lowered surface from
|
|
154
|
+
`#1c1c1e` takes about 39% black, and a second layer becomes near-black
|
|
155
|
+
`#0a0a0b`. An alpha that works for one level therefore needs a separate nesting
|
|
156
|
+
rule or a lighter dark treatment before it can become a default. The existing
|
|
157
|
+
opaque `--kui-color-surface-lowered` remains appropriate for page backgrounds.
|
|
158
|
+
|
|
159
|
+
| Candidate | Finding |
|
|
160
|
+
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
161
|
+
| Selected `ListItem` fill and border | A translucent brand layer would preserve a tinted or textured backdrop. Keep it in the component's existing `--kui-list-item-selected-*` overrides: making the shared brand fill translucent would also affect components that put `--kui-color-brand-on-fill` text on it. A 16% brand overlay gives about 4.35:1 for that text over the light lowered surface and 3.99:1 over a warm `#eee7dc` surface, below the 4.5:1 text target. |
|
|
162
|
+
| `ToolbarControlGroup` fill and border | A light 10% black layer approximates the current fill over white, and a dark 13% white layer approximates it over the dark surface. On a warm `#eee7dc` backdrop, the light layer puts the existing quiet text at about 3.31:1. Its dark tone already uses a translucent fill. Keep default control chrome opaque until a backdrop matrix validates its text, icons, borders, and selected state. |
|
|
163
|
+
| Quiet or disabled text and icons | Keep normal and quiet text/foreground tokens opaque; alpha changes their contrast with every backdrop. Disabled controls may use component-owned opacity, as they do now, without weakening shared foreground tokens. |
|
|
164
|
+
| Dividers and borders | Decorative separators can use scoped alpha over a known surface. Control boundaries and focus indicators need reliable contrast; do not replace the shared border or focus tokens with alpha globally. |
|
|
165
|
+
|
|
166
|
+
### Bounded translucent prototype
|
|
167
|
+
|
|
168
|
+
The opt-in catalog prototype (`SunkenPanel` → Backdrop-aware prototype) uses
|
|
169
|
+
the existing public background overrides on `SunkenPanel`, `Pane`, and Web
|
|
170
|
+
Awesome sunken Card/Details. It does not change shared semantic tokens or
|
|
171
|
+
component defaults. The application assigns a depth class to each
|
|
172
|
+
application-owned wrapper; the component inside inherits its public color
|
|
173
|
+
override:
|
|
174
|
+
|
|
175
|
+
| Depth | Light tint | Dark tint | Treatment |
|
|
176
|
+
| ---------------- | ----------- | ----------- | ----------------------------------------------- |
|
|
177
|
+
| First | 5.5% black | 12% black | Shows the backdrop through the lowered surface. |
|
|
178
|
+
| Second | 3.5% black | 5% black | Adds a smaller inset step. |
|
|
179
|
+
| Third and deeper | transparent | transparent | Caps accumulated darkening. |
|
|
180
|
+
|
|
181
|
+
Over default white, the light levels approximate `#f1f1f1` then `#e9e9e9`;
|
|
182
|
+
over dark default `#1c1c1e`, they approximate `#19191a` then `#171719`.
|
|
183
|
+
The dark lowered backdrop reaches roughly `#0f0f11` then `#0e0e10`, which is
|
|
184
|
+
still visually close to black. Warm and textured backdrops retain their tone
|
|
185
|
+
and pattern; the first and second layers remain discernible in light mode but
|
|
186
|
+
are subtle in dark mode. These values are sRGB estimates; actual rendering
|
|
187
|
+
depends on backdrop and browser.
|
|
188
|
+
|
|
189
|
+
The browser matrix covers one and two layers on default, lowered, warm, and
|
|
190
|
+
two textured stripe colors in light and dark, across Chromium, Firefox, and
|
|
191
|
+
WebKit. It composites computed text and control colors with each tint and
|
|
192
|
+
requires at least 4.5:1 for panel text, an opaque button, Card text, and
|
|
193
|
+
Details text. It also checks a visible focus outline with forced colors and
|
|
194
|
+
the third layer's transparent cap. Theme colors must finish transitioning
|
|
195
|
+
before contrast is measured. The prototype keeps controls on opaque semantic
|
|
196
|
+
surfaces for predictable contrast.
|
|
197
|
+
|
|
198
|
+
Keep this treatment opt-in. It needs explicit depth assignment, and the dark
|
|
199
|
+
lowered case has too little separation to replace the opaque default. A
|
|
200
|
+
future default would need a stronger depth and contrast rule for arbitrary
|
|
201
|
+
backdrops, especially dark textures and nested mixed components.
|
|
202
|
+
|
|
203
|
+
Add `class="hide-actions"` to a `wa-dialog` when the dialog supplies its own
|
|
204
|
+
dismissal affordance and should omit Web Awesome's header action region. The
|
|
205
|
+
theme sets `display: none` on the directly exported `header-actions` part; it
|
|
206
|
+
does not attempt to chain `::part()` through the internal `dialog` and `header`
|
|
207
|
+
parts, which CSS shadow parts do not support.
|
|
208
|
+
|
|
209
|
+
Badge remains intentionally compact at Web Awesome's intrinsic `0.375em` block /
|
|
210
|
+
`0.625em` inline padding (4.5px / 7.5px at its default 12px text size): it is a
|
|
211
|
+
short status or count, not a content item. A badge with `appearance="filled"` or
|
|
212
|
+
`appearance="filled-outlined"` uses its variant's quiet fill with normal text by
|
|
213
|
+
default so every shipped semantic variant meets WCAG AA for that small text;
|
|
214
|
+
filled-outlined keeps its normal variant border. Accent badges keep their loud
|
|
215
|
+
fills and their variant's `on-loud` foreground, which the theme sets to clear AA
|
|
216
|
+
on that fill in both themes: white on the light brand (`#0075db`) and danger
|
|
217
|
+
(`#eb0005`) fills, dark text on the success and warning fills and on the pale
|
|
218
|
+
dark-mode brand and danger fills.
|
|
219
|
+
Override
|
|
220
|
+
`--kui-wa-badge-filled-background` and `--kui-wa-badge-filled-foreground` on a
|
|
221
|
+
badge or containing scope when a product needs a different contrast-safe pair,
|
|
222
|
+
or `--kui-wa-badge-accent-foreground` for a reviewed accent foreground.
|
|
223
|
+
Breadcrumb has no bordered or filled container, and Scroller delegates item chrome
|
|
224
|
+
to its slotted children, so both retain their upstream geometry. Web Awesome
|
|
225
|
+
3.12's free catalog has
|
|
226
|
+
`wa-dropdown-item`, but no `wa-menu-item`; the theme therefore styles the
|
|
227
|
+
supported dropdown item rather than carrying a dead selector.
|
|
228
|
+
|
|
229
|
+
Override a tier for a product scope after importing the theme:
|
|
230
|
+
|
|
231
|
+
```css
|
|
232
|
+
.roomy-editor {
|
|
233
|
+
--kui-wa-control-inset: 0.75rem;
|
|
234
|
+
--kui-wa-surface-margin: 0.75rem;
|
|
235
|
+
--kui-wa-surface-inset: 0.75rem;
|
|
236
|
+
--kui-wa-container-inset: 1.5rem;
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
57
240
|
Accordion, Details, Breadcrumb, and Kerf Select share
|
|
58
241
|
`--kui-disclosure-icon-scale` (default `.5`) so disclosure and traversal
|
|
59
242
|
chevrons keep the same visual weight. The Accordion and Details components
|
|
@@ -62,8 +245,7 @@ their open state uses the independent `rotate` property.
|
|
|
62
245
|
|
|
63
246
|
That scale applies to each Web Awesome component's intrinsic glyph and is
|
|
64
247
|
independent of Kerf `DisclosureArrow`, whose default box is 18px relative to
|
|
65
|
-
the root font size and whose consumer override is
|
|
66
|
-
`--kui-disclosure-arrow-size`.
|
|
248
|
+
the root font size and whose consumer override is its typed `size` prop.
|
|
67
249
|
|
|
68
250
|
Tooltip and Popover use arrowless floating surfaces by default, matching Hot
|
|
69
251
|
Sheet 2. The theme sets Web Awesome's public `--wa-tooltip-arrow-size` token to
|
|
@@ -73,12 +255,12 @@ subtree, or for one instance after the theme import:
|
|
|
73
255
|
|
|
74
256
|
```css
|
|
75
257
|
:root {
|
|
76
|
-
--wa-tooltip-arrow-size: .375rem;
|
|
77
|
-
--kui-wa-popover-arrow-size: .375rem;
|
|
258
|
+
--wa-tooltip-arrow-size: 0.375rem;
|
|
259
|
+
--kui-wa-popover-arrow-size: 0.375rem;
|
|
78
260
|
}
|
|
79
261
|
|
|
80
262
|
.pointed-popover {
|
|
81
|
-
--arrow-size: .5rem;
|
|
263
|
+
--arrow-size: 0.5rem;
|
|
82
264
|
}
|
|
83
265
|
```
|
|
84
266
|
|
|
@@ -88,10 +270,9 @@ component should declare the no-arrow choice independent of theme context.
|
|
|
88
270
|
The UX catalog includes a focused, addressable specimen for every component in
|
|
89
271
|
this list. Because these are themed ecosystem components rather than
|
|
90
272
|
first-class `@kerfjs/ui` exports, the sidebar keeps them under a collapsible
|
|
91
|
-
`Web Awesome` heading with category subgroups.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
state at once.
|
|
273
|
+
`Web Awesome` heading with category subgroups. There is no aggregate theme
|
|
274
|
+
route: the focused modal, drawer, toast, media, and helper routes make each
|
|
275
|
+
component's behavior inspectable without opening every state at once.
|
|
95
276
|
|
|
96
277
|
## Badge and tag guidance
|
|
97
278
|
|
|
@@ -100,8 +281,9 @@ generic Kerf wrappers around them. Their variants and appearances already read
|
|
|
100
281
|
the semantic palette above, and importing their component modules remains
|
|
101
282
|
independent and tree-shakeable.
|
|
102
283
|
|
|
103
|
-
- Use `wa-badge pill` for compact status, count, or activity
|
|
104
|
-
2's pill-shaped ticket status treatment
|
|
284
|
+
- Use `wa-badge pill appearance="filled"` for compact status, count, or activity
|
|
285
|
+
labels. Hot Sheet 2's quiet, contrast-safe pill-shaped ticket status treatment
|
|
286
|
+
is the reference shape.
|
|
105
287
|
- Use the default, non-pill `wa-tag` for categories, filters, and removable
|
|
106
288
|
selections. Its medium-radius rounded rectangle keeps tags distinct from
|
|
107
289
|
status badges. Handle the bubbling `wa-remove` event in the feature that owns
|
|
@@ -178,15 +360,35 @@ smallest subtree that needs a different identity:
|
|
|
178
360
|
```css
|
|
179
361
|
:root {
|
|
180
362
|
--wa-color-brand-fill-loud: #7540a8;
|
|
363
|
+
--wa-color-brand-on-loud: #ffffff;
|
|
181
364
|
--wa-color-focus: #7540a8;
|
|
182
|
-
--wa-form-control-border-radius: .5rem;
|
|
365
|
+
--wa-form-control-border-radius: 0.5rem;
|
|
183
366
|
}
|
|
184
367
|
|
|
185
368
|
.billing-workspace {
|
|
186
369
|
--wa-color-success-fill-loud: #10a86b;
|
|
370
|
+
--wa-color-success-on-loud: #1d1d1f;
|
|
187
371
|
}
|
|
188
372
|
```
|
|
189
373
|
|
|
374
|
+
`TokenSearchField` with `presentation="form-field"` uses
|
|
375
|
+
`--wa-form-control-border-radius` for its control corners and
|
|
376
|
+
`--wa-form-control-required-content-color` and
|
|
377
|
+
`--wa-form-control-required-content-offset` for its required marker. These
|
|
378
|
+
tokens keep it aligned with a neighboring `wa-input` when a form theme changes.
|
|
379
|
+
|
|
380
|
+
The shipped theme pairs every `--wa-color-{variant}-fill-loud` with an
|
|
381
|
+
`--wa-color-{variant}-on-loud` that clears WCAG AA (4.5:1) in both color
|
|
382
|
+
schemes. When you override a loud fill, set its `on-loud` alongside it, in the
|
|
383
|
+
same selector and at-rule scope, to a foreground that clears 4.5:1 on the new
|
|
384
|
+
fill (white text on a bright fill usually does not: `#10a86b` above reaches
|
|
385
|
+
only 3.1:1 with white, 5.5:1 with `#1d1d1f`). `kerf-ui-analyze` and
|
|
386
|
+
`kerf-ui-doctor` report a loud fill override without a governing `on-loud`, or
|
|
387
|
+
a literal pair that measures below 4.5:1, as review finding
|
|
388
|
+
[`KUI-L018`](./ui-analyzer.md#loud-fill--on-loud-pairing-kui-l018); it cannot
|
|
389
|
+
measure a `var()` or `color-mix()` value, so choosing a readable one is still
|
|
390
|
+
yours.
|
|
391
|
+
|
|
190
392
|
Use `.wa-light`, `.wa-dark`, and `.wa-invert` for explicit appearance scopes.
|
|
191
393
|
Component-specific custom properties and documented `::part()` selectors from
|
|
192
394
|
Web Awesome remain available when a semantic theme token is not sufficiently
|