@kerfjs/ui 4.4.1 → 4.5.0-beta.1
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 +425 -42
- package/ai/application-ui-diagnostic-ids-v1.json +92 -0
- package/ai/application-ui-profile-sync.cjs +529 -0
- package/ai/application-ui-profile.d.mts +1 -0
- package/ai/application-ui-profile.d.ts +102 -0
- package/ai/application-ui-profile.defaults.json +41 -0
- package/ai/application-ui-profile.mjs +626 -0
- package/ai/application-ui-profile.schema.json +130 -0
- package/ai/catalog-authoring.json +25 -0
- package/ai/catalog-authoring.schema.json +61 -0
- package/ai/compile-time-contracts-v1.json +102 -0
- package/ai/compile-time-contracts-v1.schema.json +49 -0
- package/ai/component-catalog-extension-v2.d.ts +7 -0
- package/ai/component-catalog-extension-v2.schema.json +7 -0
- package/ai/component-catalog-extension.schema.json +79 -0
- package/ai/component-catalog-v2-overrides.json +319 -0
- package/ai/component-catalog-v2.d.ts +67 -0
- package/ai/component-catalog-v2.json +4675 -0
- package/ai/component-catalog-v2.schema.json +246 -0
- package/ai/component-catalog.json +5826 -0
- package/ai/component-catalog.schema.json +95 -0
- package/ai/public-api-signatures-v1.md +1719 -0
- package/ai/skill.md +129 -21
- package/ai/webawesome-jsx-signatures-v1.md +106 -0
- package/analyzer/cli.mjs +46 -0
- package/analyzer/index.d.mts +45 -0
- package/analyzer/index.mjs +737 -0
- package/analyzer/report.schema.json +66 -0
- package/dist/app-tab.d.ts +14 -2
- package/dist/app-tab.js +3 -1
- package/dist/browser/app-tab.js +3 -2
- package/dist/browser/disclosure-arrow.js +4 -0
- package/dist/browser/empty-state.js +3 -3
- package/dist/browser/floating-toolbar.js +3 -0
- package/dist/browser/list-action-row.js +4 -0
- package/dist/browser/list-header.js +6 -0
- package/dist/browser/list-inset-control.js +3 -0
- package/dist/browser/list-inset-text.js +3 -0
- package/dist/browser/list-item.js +4 -0
- package/dist/browser/list.js +3 -0
- package/dist/browser/loading-spinner.js +2 -2
- package/dist/browser/lucide-icon.js +2 -2
- package/dist/browser/pane.js +3 -0
- package/dist/browser/panel-header.js +7 -0
- package/dist/browser/resizable-region.js +2 -2
- package/dist/browser/segmented-control.js +3 -2
- package/dist/browser/select.js +4 -3
- package/dist/browser/skeleton.js +3 -0
- package/dist/browser/state-banner.js +3 -2
- package/dist/browser/sunken-panel.js +3 -0
- package/dist/browser/tab-bar.js +2 -2
- package/dist/browser/token-search-field.js +4 -0
- package/dist/browser/toolbar-control-group.js +2 -2
- package/dist/browser/toolbar-text.js +3 -2
- package/dist/browser/toolbar.js +2 -2
- package/dist/browser/value-table.js +3 -2
- package/dist/catalog-resources.d.ts +34 -0
- package/dist/catalog-resources.js +22 -0
- package/dist/catalog-resources.js.map +1 -0
- package/dist/catalog.d.ts +150 -0
- package/dist/catalog.js +377 -0
- package/dist/catalog.js.map +1 -0
- package/dist/chunk-5VTB2BKP.js +35 -0
- package/dist/chunk-5VTB2BKP.js.map +1 -0
- package/dist/chunk-6WTETUZ6.js +21 -0
- package/dist/chunk-6WTETUZ6.js.map +1 -0
- package/dist/chunk-7KEUJIIC.js +218 -0
- package/dist/chunk-7KEUJIIC.js.map +1 -0
- package/dist/chunk-7XRDUG4Y.js +58 -0
- package/dist/chunk-7XRDUG4Y.js.map +1 -0
- package/dist/chunk-B3A3IVO5.js +83 -0
- package/dist/chunk-B3A3IVO5.js.map +1 -0
- package/dist/chunk-DPDBVKNA.js +113 -0
- package/dist/chunk-DPDBVKNA.js.map +1 -0
- package/dist/chunk-FEAMR7S4.js +68 -0
- package/dist/chunk-FEAMR7S4.js.map +1 -0
- package/dist/chunk-FEY65TBV.js +15 -0
- package/dist/chunk-FEY65TBV.js.map +1 -0
- package/dist/{chunk-TRNBHPNW.js → chunk-IJBSZ4NX.js} +11 -8
- package/dist/chunk-IJBSZ4NX.js.map +1 -0
- package/dist/chunk-J5BFYY7Q.js +35 -0
- package/dist/chunk-J5BFYY7Q.js.map +1 -0
- package/dist/chunk-JRKSK2HX.js +79 -0
- package/dist/chunk-JRKSK2HX.js.map +1 -0
- package/dist/chunk-KWWR5VMS.js +45 -0
- package/dist/chunk-KWWR5VMS.js.map +1 -0
- package/dist/chunk-LPOMRC4C.js +25 -0
- package/dist/chunk-LPOMRC4C.js.map +1 -0
- package/dist/chunk-M7JBER5U.js +41 -0
- package/dist/chunk-M7JBER5U.js.map +1 -0
- package/dist/chunk-NENBUYX5.js +79 -0
- package/dist/chunk-NENBUYX5.js.map +1 -0
- package/dist/chunk-NWSEP5RT.js +117 -0
- package/dist/chunk-NWSEP5RT.js.map +1 -0
- package/dist/chunk-OJWWHFH3.js +426 -0
- package/dist/chunk-OJWWHFH3.js.map +1 -0
- package/dist/chunk-PSKN344N.js +114 -0
- package/dist/chunk-PSKN344N.js.map +1 -0
- package/dist/chunk-PX3YSS5C.js +32 -0
- package/dist/chunk-PX3YSS5C.js.map +1 -0
- package/dist/chunk-QO55FN2Y.js +20 -0
- package/dist/chunk-QO55FN2Y.js.map +1 -0
- package/dist/chunk-R7ZWUN64.js +38 -0
- package/dist/chunk-R7ZWUN64.js.map +1 -0
- package/dist/chunk-RKVQEH4J.js +61 -0
- package/dist/chunk-RKVQEH4J.js.map +1 -0
- package/dist/chunk-SRSJO5QE.js +40 -0
- package/dist/chunk-SRSJO5QE.js.map +1 -0
- package/dist/chunk-SYDMYBPG.js +31 -0
- package/dist/chunk-SYDMYBPG.js.map +1 -0
- package/dist/chunk-TB6DY7H5.js +25 -0
- package/dist/chunk-TB6DY7H5.js.map +1 -0
- package/dist/chunk-UFZKLBCF.js +108 -0
- package/dist/chunk-UFZKLBCF.js.map +1 -0
- package/dist/{chunk-MQIZAD4A.js → chunk-UKKSMZYT.js} +76 -22
- package/dist/chunk-UKKSMZYT.js.map +1 -0
- package/dist/chunk-W5L2JSBY.js +40 -0
- package/dist/chunk-W5L2JSBY.js.map +1 -0
- package/dist/chunk-Y45PPBDV.js +105 -0
- package/dist/chunk-Y45PPBDV.js.map +1 -0
- package/dist/chunk-Y6LYKFXY.js +43 -0
- package/dist/chunk-Y6LYKFXY.js.map +1 -0
- package/dist/collapsible-panel.d.ts +66 -0
- package/dist/collapsible-panel.js +63 -0
- package/dist/collapsible-panel.js.map +1 -0
- package/dist/device-class.d.ts +62 -0
- package/dist/device-class.js +103 -0
- package/dist/device-class.js.map +1 -0
- package/dist/disclosure-arrow.d.ts +14 -0
- package/dist/disclosure-arrow.js +4 -0
- package/dist/disclosure-arrow.js.map +1 -0
- package/dist/divider-sides-267FA7sY.d.ts +4 -0
- package/dist/empty-state.d.ts +1 -1
- package/dist/empty-state.js +1 -1
- package/dist/floating-toolbar.d.ts +28 -0
- package/dist/floating-toolbar.js +3 -0
- package/dist/floating-toolbar.js.map +1 -0
- package/dist/index.d.ts +20 -9
- package/dist/index.js +29 -18
- package/dist/list-action-row.d.ts +52 -0
- package/dist/list-action-row.js +5 -0
- package/dist/list-action-row.js.map +1 -0
- package/dist/list-header.d.ts +64 -0
- package/dist/list-header.js +7 -0
- package/dist/list-header.js.map +1 -0
- package/dist/list-inset-control.d.ts +16 -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 +25 -0
- package/dist/list-inset-text.js +3 -0
- package/dist/list-inset-text.js.map +1 -0
- package/dist/list-item.d.ts +33 -0
- package/dist/list-item.js +5 -0
- package/dist/list-item.js.map +1 -0
- package/dist/list.d.ts +19 -0
- package/dist/list.js +3 -0
- package/dist/list.js.map +1 -0
- package/dist/loading-spinner.js +1 -1
- package/dist/nav-stack.d.ts +38 -0
- package/dist/nav-stack.js +5 -0
- package/dist/nav-stack.js.map +1 -0
- package/dist/pane.d.ts +49 -0
- package/dist/pane.js +4 -0
- package/dist/pane.js.map +1 -0
- package/dist/panel-header.d.ts +42 -0
- package/dist/panel-header.js +7 -0
- package/dist/panel-header.js.map +1 -0
- package/dist/resizable-region.d.ts +3 -1
- package/dist/resizable-region.js +1 -1
- package/dist/segmented-control.d.ts +8 -6
- package/dist/segmented-control.js +2 -1
- package/dist/select-register.d.ts +5 -1
- package/dist/select-register.js +3 -0
- package/dist/select-register.js.map +1 -1
- package/dist/select.d.ts +15 -6
- package/dist/select.js +2 -1
- package/dist/skeleton.d.ts +24 -0
- package/dist/skeleton.js +3 -0
- package/dist/skeleton.js.map +1 -0
- package/dist/split-view.d.ts +42 -0
- package/dist/split-view.js +81 -0
- package/dist/split-view.js.map +1 -0
- package/dist/state-banner.d.ts +8 -3
- package/dist/state-banner.js +2 -1
- package/dist/styles/app-tab.css +152 -0
- package/dist/styles/catalog.css +575 -0
- package/dist/styles/collapsible-panel.css +146 -0
- package/dist/styles/disclosure-arrow.css +23 -0
- package/dist/styles/empty-state.css +47 -0
- package/dist/styles/floating-toolbar.css +38 -0
- package/dist/styles/foundation.css +362 -0
- package/dist/styles/layout.css +55 -0
- package/dist/styles/list-action-row.css +160 -0
- package/dist/styles/list-header.css +160 -0
- package/dist/styles/list-inset-control.css +7 -0
- package/dist/styles/list-inset-text.css +14 -0
- package/dist/styles/list-item.css +123 -0
- package/dist/styles/list.css +43 -0
- package/dist/styles/loading-spinner.css +21 -0
- package/dist/styles/lucide-icon.css +6 -0
- package/dist/styles/nav-stack.css +111 -0
- package/dist/styles/pane.css +62 -0
- package/dist/styles/panel-header.css +64 -0
- package/dist/styles/resizable-region.css +111 -0
- package/{src → dist/styles}/segmented-control.css +58 -31
- package/dist/styles/select.css +140 -0
- package/dist/styles/skeleton.css +31 -0
- package/dist/styles/split-view.css +35 -0
- package/dist/styles/state-banner.css +198 -0
- package/dist/styles/styles.css +24 -0
- package/dist/styles/sunken-panel.css +22 -0
- package/dist/styles/tab-bar.css +45 -0
- package/dist/styles/tab-scaffold.css +84 -0
- package/dist/styles/token-search-field.css +289 -0
- package/dist/styles/toolbar-control-group.css +225 -0
- package/dist/styles/toolbar-text.css +92 -0
- package/dist/styles/toolbar.css +97 -0
- package/dist/styles/value-table.css +75 -0
- package/dist/styles/webawesome.css +399 -0
- package/dist/styles/workbench.css +94 -0
- package/dist/sunken-panel.d.ts +19 -0
- package/dist/sunken-panel.js +3 -0
- package/dist/sunken-panel.js.map +1 -0
- package/dist/tab-bar.d.ts +10 -2
- package/dist/tab-bar.js +1 -1
- package/dist/tab-scaffold.d.ts +30 -0
- package/dist/tab-scaffold.js +51 -0
- package/dist/tab-scaffold.js.map +1 -0
- package/dist/token-search-field.d.ts +59 -0
- package/dist/token-search-field.js +4 -0
- package/dist/token-search-field.js.map +1 -0
- package/dist/toolbar-control-group.d.ts +11 -5
- package/dist/toolbar-control-group.js +1 -1
- package/dist/toolbar-text.d.ts +31 -4
- package/dist/toolbar-text.js +2 -1
- package/dist/toolbar.d.ts +5 -3
- package/dist/toolbar.js +1 -1
- package/dist/value-table.d.ts +13 -3
- package/dist/value-table.js +2 -1
- package/dist/webawesome.d.ts +100 -0
- package/dist/webawesome.js +3 -0
- package/dist/webawesome.js.map +1 -0
- package/dist/wire-catalog.d.ts +57 -0
- package/dist/wire-catalog.js +302 -0
- package/dist/wire-catalog.js.map +1 -0
- package/dist/wire-nav-stack.d.ts +15 -0
- package/dist/wire-nav-stack.js +103 -0
- package/dist/wire-nav-stack.js.map +1 -0
- package/dist/wire-resizable-regions.d.ts +1 -1
- package/dist/wire-resizable-regions.js +1 -1
- package/dist/wire-sidebar.d.ts +43 -0
- package/dist/wire-sidebar.js +128 -0
- package/dist/wire-sidebar.js.map +1 -0
- package/dist/wire-tab-bars.d.ts +18 -2
- package/dist/wire-tab-bars.js +1 -1
- package/dist/wire-tab-scaffold.d.ts +11 -0
- package/dist/wire-tab-scaffold.js +21 -0
- package/dist/wire-tab-scaffold.js.map +1 -0
- package/dist/wire-token-search-fields.d.ts +111 -0
- package/dist/wire-token-search-fields.js +5 -0
- package/dist/wire-token-search-fields.js.map +1 -0
- package/dist/workbench.d.ts +33 -0
- package/dist/workbench.js +64 -0
- package/dist/workbench.js.map +1 -0
- package/docs/accessibility.md +124 -4
- package/docs/app-layouts.md +61 -0
- package/docs/catalog.md +364 -0
- package/docs/collapsible-panel.md +129 -0
- package/docs/component-contract.md +312 -5
- package/docs/component-selection.md +219 -0
- 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/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/panel-header/icon-actions-dark.svg +1 -0
- package/docs/design/templates/panel-header/icon-actions.svg +1 -0
- package/docs/design/templates/panel-header/icon-summary-actions-dark.svg +1 -0
- package/docs/design/templates/panel-header/icon-summary-actions.svg +1 -0
- package/docs/design/templates/panel-header/no-icon-dark.svg +1 -0
- package/docs/design/templates/panel-header/no-icon.svg +1 -0
- package/docs/design/templates/panel-header/page-heading-dark.svg +1 -0
- package/docs/design/templates/panel-header/page-heading.svg +1 -0
- package/docs/design/templates/panel-header/title-only-dark.svg +1 -0
- package/docs/design/templates/panel-header/title-only.svg +1 -0
- package/docs/design/templates/panel-header-dark.svg +1 -0
- package/docs/design/templates/panel-header.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 +130 -0
- package/docs/design-philosophy.md +59 -1
- package/docs/device-class.md +54 -0
- package/docs/examples/application-ui-profile.json +60 -0
- package/docs/examples/command-palette-adapter.tsx +120 -0
- package/docs/examples/component-catalog-extension-v2.json +81 -0
- package/docs/examples/component-catalog-extension.json +45 -0
- package/docs/layout.md +150 -0
- package/docs/nav-stack.md +56 -0
- package/docs/recipes.md +167 -0
- package/docs/split-view.md +49 -0
- package/docs/sunken-panel.md +53 -0
- package/docs/tab-scaffold.md +50 -0
- package/docs/type-contracts.md +102 -0
- package/docs/ui-analyzer.md +86 -0
- package/docs/ui-doctor.md +84 -0
- package/docs/ui-evaluator.md +122 -0
- package/docs/ux-demo.md +23 -9
- package/docs/webawesome-theme.md +87 -7
- package/docs/workbench.md +73 -0
- package/doctor/cli.mjs +115 -0
- package/doctor/config.schema.json +68 -0
- package/doctor/eslint-diagnostics.d.mts +8 -0
- package/doctor/eslint-diagnostics.mjs +7 -0
- package/doctor/index.d.mts +116 -0
- package/doctor/index.mjs +1257 -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 +1138 -0
- package/evaluator/report.schema.json +152 -0
- package/llms.txt +197 -14
- package/package.json +228 -46
- package/traversal-exclusions.mjs +27 -0
- package/ux-demo/recipes/app-shell.tsx +228 -0
- package/ux-demo/recipes/collapsible-sidebar.tsx +223 -0
- package/ux-demo/recipes/compact-toolbar.tsx +145 -0
- package/ux-demo/recipes/composer-form.tsx +151 -0
- package/ux-demo/recipes/list-detail-dialog.tsx +181 -0
- package/ux-demo/recipes/list-workspace-states.tsx +183 -0
- package/ux-demo/recipes/loaders.ts +36 -0
- package/ux-demo/recipes/loading-inspector.tsx +164 -0
- package/ux-demo/recipes/mount-recipe.ts +64 -0
- package/ux-demo/recipes/navigation-sidebar.tsx +137 -0
- package/ux-demo/recipes/navigation-stack.tsx +118 -0
- package/ux-demo/recipes/recipes.css +448 -0
- package/ux-demo/recipes/types.ts +19 -0
- package/ux-demo/recipes/workspace-header.tsx +67 -0
- package/dist/browser/dialog-header.js +0 -3
- package/dist/browser/menu-header.js +0 -3
- package/dist/browser/menu-item.js +0 -3
- package/dist/browser/page-header.js +0 -3
- package/dist/chunk-2PES33HS.js +0 -13
- package/dist/chunk-2PES33HS.js.map +0 -1
- package/dist/chunk-3O7ZEUW2.js +0 -27
- package/dist/chunk-3O7ZEUW2.js.map +0 -1
- package/dist/chunk-4HHCYSGT.js +0 -79
- package/dist/chunk-4HHCYSGT.js.map +0 -1
- package/dist/chunk-55DATV3A.js +0 -10
- package/dist/chunk-55DATV3A.js.map +0 -1
- package/dist/chunk-723YNJBH.js +0 -17
- package/dist/chunk-723YNJBH.js.map +0 -1
- package/dist/chunk-DAFFDO33.js +0 -14
- package/dist/chunk-DAFFDO33.js.map +0 -1
- package/dist/chunk-GY5WH7TO.js +0 -10
- package/dist/chunk-GY5WH7TO.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.map +0 -1
- package/dist/chunk-NHXX4JI5.js +0 -28
- package/dist/chunk-NHXX4JI5.js.map +0 -1
- package/dist/chunk-OPCJRCYO.js +0 -19
- package/dist/chunk-OPCJRCYO.js.map +0 -1
- package/dist/chunk-T5XNMVOI.js +0 -24
- package/dist/chunk-T5XNMVOI.js.map +0 -1
- package/dist/chunk-TRNBHPNW.js.map +0 -1
- package/dist/chunk-VHW5YNIB.js +0 -17
- package/dist/chunk-VHW5YNIB.js.map +0 -1
- package/dist/chunk-VKH2JLDZ.js +0 -10
- package/dist/chunk-VKH2JLDZ.js.map +0 -1
- package/dist/chunk-WVPYVDXY.js +0 -15
- package/dist/chunk-WVPYVDXY.js.map +0 -1
- package/dist/chunk-WY4CAEPG.js +0 -14
- package/dist/chunk-WY4CAEPG.js.map +0 -1
- package/dist/dialog-header.d.ts +0 -14
- package/dist/dialog-header.js +0 -3
- package/dist/dialog-header.js.map +0 -1
- package/dist/menu-header.d.ts +0 -15
- package/dist/menu-header.js +0 -3
- package/dist/menu-header.js.map +0 -1
- package/dist/menu-item.d.ts +0 -22
- package/dist/menu-item.js +0 -3
- package/dist/menu-item.js.map +0 -1
- package/dist/page-header.d.ts +0 -9
- package/dist/page-header.js +0 -3
- package/dist/page-header.js.map +0 -1
- package/src/app-tab.css +0 -20
- package/src/dialog-header.css +0 -9
- package/src/empty-state.css +0 -6
- package/src/foundation.css +0 -106
- package/src/loading-spinner.css +0 -4
- package/src/lucide-icon.css +0 -1
- package/src/menu-header.css +0 -13
- package/src/menu-item.css +0 -12
- package/src/page-header.css +0 -3
- package/src/resizable-region.css +0 -19
- package/src/select.css +0 -18
- package/src/state-banner.css +0 -31
- package/src/styles.css +0 -18
- package/src/tab-bar.css +0 -4
- package/src/toolbar-control-group.css +0 -25
- package/src/toolbar-text.css +0 -4
- package/src/toolbar.css +0 -9
- package/src/value-table.css +0 -5
- package/src/webawesome.css +0 -178
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Design templates — components as self-contained SVGs
|
|
2
|
+
|
|
3
|
+
`docs/design/templates/` holds **SVG design templates** for `@kerfjs/ui`
|
|
4
|
+
components: a faithful, self-contained picture of each component in its common
|
|
5
|
+
presentation combinations, captured from the real rendered HTML/CSS (production
|
|
6
|
+
tokens and styles, representative sample data). They're for design review,
|
|
7
|
+
documentation, figma/paste hand-off, and any surface that wants an accurate
|
|
8
|
+
component picture without running the app.
|
|
9
|
+
|
|
10
|
+
## Coverage
|
|
11
|
+
|
|
12
|
+
Templated components (each with light + dark variants): `PanelHeader`,
|
|
13
|
+
`ToolbarControlGroup`, `Toolbar`, `ToolbarText`, `List`, `ListItem`, `ListHeader`,
|
|
14
|
+
`ListActionRow`, `ValueTable`, `StateBanner`, `EmptyState`, `Skeleton`,
|
|
15
|
+
`SegmentedControl`, `TabBar`/`AppTab`, and `TokenSearchField`.
|
|
16
|
+
|
|
17
|
+
Deliberately **not** templated (they don't read as a single static component
|
|
18
|
+
picture): `Select` renders a Web Awesome custom element that needs its runtime
|
|
19
|
+
registered, so it has no faithful static capture; `LucideIcon` and
|
|
20
|
+
`DisclosureArrow` are decorative primitives best seen inside the components that
|
|
21
|
+
use them; `ResizableRegion` and the whole-screen layouts (`NavStack`,
|
|
22
|
+
`SplitView`, `Workbench`, `TabScaffold`) and the `Catalog` shell are
|
|
23
|
+
interaction-/viewport-driven screens rather than component cards — the live UX
|
|
24
|
+
catalog and the app-layouts docs cover those.
|
|
25
|
+
|
|
26
|
+
## Layout
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
docs/design/templates/
|
|
30
|
+
panel-header.svg ← library: every variant, composed (light)
|
|
31
|
+
panel-header-dark.svg ← library: dark theme
|
|
32
|
+
panel-header/
|
|
33
|
+
icon-summary-actions.svg ← one self-contained variant (light)
|
|
34
|
+
icon-summary-actions-dark.svg ← the same variant, dark theme
|
|
35
|
+
icon-actions.svg
|
|
36
|
+
icon-actions-dark.svg
|
|
37
|
+
…
|
|
38
|
+
toolbar-control-group.svg
|
|
39
|
+
toolbar-control-group-dark.svg
|
|
40
|
+
toolbar-control-group/
|
|
41
|
+
…
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
- Each **variant** is captured in both themes — `<variant>.svg` (light) and
|
|
45
|
+
`<variant>-dark.svg` (dark) — a standalone SVG that scales crisply and drops
|
|
46
|
+
into an `<img>` anywhere. Dark is driven by domotion's `--color-scheme`, which
|
|
47
|
+
foundation.css's `light-dark()` tokens respond to. Captured with
|
|
48
|
+
`--text-mode system-font`, so text is emitted as authored `<text>` painted by the
|
|
49
|
+
viewer's system fonts: real, selectable, and small (no embedded font data). The
|
|
50
|
+
kerf UI design font stack is system-based, so the picture matches; a viewer
|
|
51
|
+
without those fonts falls back to its own.
|
|
52
|
+
- The **library** files (`<component>.svg` light, `<component>-dark.svg` dark) lay
|
|
53
|
+
the variants out with captions. The generator writes a temporary HTML page whose
|
|
54
|
+
`<img>` elements reference the individual variant SVGs, then captures that page
|
|
55
|
+
with domotion and `--flatten-nested-svg`. The final library is self-contained,
|
|
56
|
+
contains positioned groups rather than nested `<svg>` elements, and remains
|
|
57
|
+
reliable in design tools such as Sketch. The individual variant files stay
|
|
58
|
+
independently reusable.
|
|
59
|
+
|
|
60
|
+
## Building
|
|
61
|
+
|
|
62
|
+
```sh
|
|
63
|
+
npm run design-templates:build
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
This renders each component's real `SafeHtml` (with its CSS subpaths + `foundation.css`
|
|
67
|
+
tokens and representative sample data) into a standalone page and captures it with
|
|
68
|
+
[`domotion-svg`](https://github.com/brianwestphal/domotion)'s `domotion capture`.
|
|
69
|
+
The capture command uses `--flatten-nested-svg`, which converts safely flattenable
|
|
70
|
+
inline SVGs (including component icons) to groups so design tools such as Sketch do
|
|
71
|
+
not have to interpret nested `<svg>` elements.
|
|
72
|
+
`domotion` must be reachable: it resolves `DOMOTION_BIN`, then a local
|
|
73
|
+
`node_modules/.bin/domotion`, then a sibling `../domotion` checkout.
|
|
74
|
+
|
|
75
|
+
**Keep the templates current as components change.** The variants live in the
|
|
76
|
+
`COMPONENTS` manifest in `scripts/build-design-templates.mjs` — when a component
|
|
77
|
+
gains or changes a presentation combination (e.g. a new `PanelHeader` slot), add
|
|
78
|
+
or adjust its variant there and re-run the build. Cover the common cases: if a
|
|
79
|
+
component can render with or without an icon, include both.
|
|
80
|
+
|
|
81
|
+
`npm run check:design-templates` (part of `npm run check`) is an offline gate
|
|
82
|
+
that verifies every component + variant in the manifest has its committed output —
|
|
83
|
+
a light and dark SVG per variant plus the two per-component library files — and
|
|
84
|
+
that no stray template files linger for a removed component. It also rejects any
|
|
85
|
+
variant or library capture that still contains nested `<svg>` elements, guarding
|
|
86
|
+
the Sketch compatibility contract. It does **not**
|
|
87
|
+
re-render (that needs domotion + a browser), so it catches a manifest entry whose
|
|
88
|
+
templates were never generated or a half-regenerated set.
|
|
89
|
+
|
|
90
|
+
Deeper **visual drift** — a component changed but its template was not regenerated —
|
|
91
|
+
is caught by `npm run check:design-templates:drift`, a CI-only gate (it runs in a
|
|
92
|
+
dedicated macOS browser job, **not** in the offline `npm run check`). The committed
|
|
93
|
+
templates use system-font text, whose layout metrics differ by operating system, so
|
|
94
|
+
macOS is the canonical exact-render environment for both generation and comparison.
|
|
95
|
+
The capture fixture also pins its monospace token to `Courier New`; otherwise
|
|
96
|
+
`ui-monospace` resolves to different fonts on developer and hosted macOS machines.
|
|
97
|
+
The gate regenerates every template into a throwaway directory and fails if any
|
|
98
|
+
regenerated SVG differs from the committed one, after normalizing the bits that
|
|
99
|
+
legitimately vary between runs (XML comments and the auto-minted element ids / font
|
|
100
|
+
names). If it fails, run `npm run design-templates:build` on macOS and commit the
|
|
101
|
+
updated SVGs.
|
|
102
|
+
|
|
103
|
+
## Templating your own components
|
|
104
|
+
|
|
105
|
+
Apps that build on `@kerfjs/ui` can produce the same design templates for their
|
|
106
|
+
own application-level components. Copy `scripts/build-design-templates.mjs` as a
|
|
107
|
+
starting point and:
|
|
108
|
+
|
|
109
|
+
1. Import your component and render it to a `SafeHtml` string with realistic
|
|
110
|
+
sample data (pass icon/action slots as `SafeHtml`, e.g. `LucideIcon({ … })` or
|
|
111
|
+
`raw('<button …>')` — never plain strings, which kerf escapes).
|
|
112
|
+
2. List the component's CSS (its `@kerfjs/ui` subpaths plus `foundation.css` for
|
|
113
|
+
tokens and `layout.css`), and any of your own component CSS.
|
|
114
|
+
3. Enumerate the presentation combinations in the per-component manifest.
|
|
115
|
+
4. Capture each variant with `domotion capture <page.html> --selector <css>
|
|
116
|
+
--text-mode system-font --flatten-nested-svg -o <variant>.svg`, once per theme with
|
|
117
|
+
`--color-scheme light` / `--color-scheme dark` (if your components theme with
|
|
118
|
+
`light-dark()`).
|
|
119
|
+
5. Build a light and dark HTML library page that references the generated variants
|
|
120
|
+
with `<img src="./component/variant.svg">`, and capture each page with the same
|
|
121
|
+
domotion options, including `--flatten-nested-svg`. Let domotion own embedding,
|
|
122
|
+
id isolation, and flattening instead of hand-assembling SVG markup.
|
|
123
|
+
|
|
124
|
+
Maintaining these next to the components — and reviewing the captured SVGs on
|
|
125
|
+
every component change — keeps the design source of truth honest.
|
|
126
|
+
|
|
127
|
+
ListItem templates retain the shared 18px leading icon and 44px row target;
|
|
128
|
+
regenerate both themes and library sheets when that geometry changes. The browser
|
|
129
|
+
pane/sidebar geometry checks cover the resulting 43px icon-label offset from the
|
|
130
|
+
section edge (17px content inset + 18px icon + 8px gap).
|
|
@@ -18,12 +18,63 @@ A reference image defines hierarchy, relationships, and intended feel. It does n
|
|
|
18
18
|
|
|
19
19
|
### Continuity is correctness
|
|
20
20
|
|
|
21
|
-
Unrelated updates must not close controls, move focus, reset a draft, replace a selection, or jump scroll. Give every durable and transient state an explicit owner. Preserve DOM identity when meaning has not changed. Distinguish blocking foreground work from background synchronization.
|
|
21
|
+
Unrelated updates must not close controls, move focus, reset a draft, replace a selection, or jump scroll. Give every durable and transient state an explicit owner. The default owner is the application: domain data and persisted layout preferences — a navigation stack, a selection, a tab order, a pane size, a `collapsed`/`expanded` disclosure flag — are the app's signals, which it reads to render. A `wire…` helper owns only the _ephemeral mechanics_ around that state (a push/pop animation, overflow autoscroll, a live resize preview) and reports committed changes through callbacks. A helper takes over a piece of transient state itself only when hand-rolling that behavior is substantial and error-prone enough to cause real, inconsistent variation across apps — `wireTokenSearchFields`'s collapsible reveal/focus/Escape/blur-collapse is the bar; a one-line boolean toggle is not. Preserve DOM identity when meaning has not changed. Distinguish blocking foreground work from background synchronization.
|
|
22
22
|
|
|
23
23
|
### Hierarchy precedes decoration
|
|
24
24
|
|
|
25
25
|
Establish one reading order and one dominant action per decision point. Group first with alignment, spacing, typography, and shared surfaces. A border, fill, badge, or nested card must communicate a real distinction.
|
|
26
26
|
|
|
27
|
+
### Reach for the primitive, not for CSS
|
|
28
|
+
|
|
29
|
+
The package is designed to look right _unstyled_. A screen built from the
|
|
30
|
+
primitives, their props, and the semantic tokens should already read well, so
|
|
31
|
+
custom CSS is the exception. Before adding any `padding`, `margin`, `width`,
|
|
32
|
+
`height`, `border`, `background`, wrapper card, or decoration, check whether the
|
|
33
|
+
component, the pane, or the content-item already owns it — it almost always does,
|
|
34
|
+
and adding more usually **double-insets** or fights the component (the most common
|
|
35
|
+
mistake). Trust component defaults: render a control at its natural size and color
|
|
36
|
+
and fix the surrounding layout rather than overriding the control. Legitimate
|
|
37
|
+
custom CSS is limited to genuinely new structure, and even then may only join a
|
|
38
|
+
component's documented `publicClasses` or override documented `--kui-*` tokens at a
|
|
39
|
+
real composition boundary — never size, space, or re-skin a primitive by hand, and
|
|
40
|
+
never build a heading, toolbar, card, or pane geometry that a primitive provides.
|
|
41
|
+
|
|
42
|
+
### Panes share one child-owned geometry
|
|
43
|
+
|
|
44
|
+
Sidebars, main areas, inspectors, and dialogs use the same unpadded pane. Their
|
|
45
|
+
children own margin, border, background, padding, and radius, so a transparent
|
|
46
|
+
surface occupies exactly the same geometry as a visible one. Major content
|
|
47
|
+
groups use 24px vertical separation; the inside of an item and the gap between
|
|
48
|
+
toolbar groups use 8px. Rows and actions keep 44px targets.
|
|
49
|
+
|
|
50
|
+
Use the package composition so the geometry has one owner:
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
<Pane element="aside" contentElement="nav" label="Workspace" contentLabel="Workspace pages">
|
|
54
|
+
<section>
|
|
55
|
+
<ListHeader label="Workspace" />
|
|
56
|
+
<ListItem action="open" label="Inbox" icon={inboxIcon} />
|
|
57
|
+
<ListItem action="open" label="Drafts" />
|
|
58
|
+
</section>
|
|
59
|
+
<div class="kui-content-item">Panel contents</div>
|
|
60
|
+
</Pane>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Do not pad the pane and then pad every wrapper. That duplicates the geometry
|
|
64
|
+
and makes transparent borders behave differently from visible ones:
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
<aside class="pane padded">
|
|
68
|
+
<section class="padded">
|
|
69
|
+
<ListHeader label="Workspace" />
|
|
70
|
+
<div class="panel padded-again">Panel contents</div>
|
|
71
|
+
</section>
|
|
72
|
+
</aside>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Change the shared item tokens at a real composition boundary when a product
|
|
76
|
+
needs different geometry; do not compensate with one-off negative margins.
|
|
77
|
+
|
|
27
78
|
### Prefer directness
|
|
28
79
|
|
|
29
80
|
Use the shortest understandable, recoverable interaction. Avoid modes, dialogs, confirmations, and explicit saves when direct manipulation can safely express the same result. Low ceremony still requires a discoverable affordance, visible focus, and honest feedback.
|
|
@@ -42,6 +93,13 @@ foregrounds compatible with Hot Sheet 2 and Web Awesome. Consumers may replace
|
|
|
42
93
|
the global palette, one semantic role, or one component instance through
|
|
43
94
|
documented custom properties without rewriting component CSS.
|
|
44
95
|
|
|
96
|
+
Spacing is likewise a finite, semantic scale, not a free measurement. Five
|
|
97
|
+
canonical steps — 0, 4, 8, 16, and 24px, each a `--kui-space-*` token — map to a
|
|
98
|
+
single relationship apiece, chosen by how connected two elements are: no
|
|
99
|
+
separation, very minor air, standard within a group, between homogeneous groups,
|
|
100
|
+
and major between heterogeneous groups. Off-scale values (12px, 32px) are
|
|
101
|
+
deliberate exceptions. See [`layout.md`](layout.md) "Spacing scale".
|
|
102
|
+
|
|
45
103
|
### Responsive design reprioritizes
|
|
46
104
|
|
|
47
105
|
Protect primary content, readable type, recognizable icons, and usable targets. Relocate secondary information before compressing it below a usable scale. Keep one clear scroll owner per region and test narrow, wide, zoomed, and intermediate layouts.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Device class
|
|
2
|
+
|
|
3
|
+
`@kerfjs/ui/device-class` reports the current viewport as a reactive **device
|
|
4
|
+
class** — a size bucket × orientation × viewport-segment count — so a layout can
|
|
5
|
+
pick its presentation from one signal instead of hand-wiring `matchMedia`. It is
|
|
6
|
+
the foundation the app/dialog layouts build on (see
|
|
7
|
+
[`../../docs/23-app-layouts.md`](../../docs/23-app-layouts.md)).
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { deviceClass } from "@kerfjs/ui/device-class";
|
|
11
|
+
|
|
12
|
+
const device = deviceClass(); // ReadonlySignal<DeviceClass>
|
|
13
|
+
|
|
14
|
+
effect(() => {
|
|
15
|
+
if (device.value.compact) showStack();
|
|
16
|
+
else showSplit();
|
|
17
|
+
});
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## `DeviceClass`
|
|
21
|
+
|
|
22
|
+
| Field | Meaning |
|
|
23
|
+
| ------------------------------- | -------------------------------------------------------------------------- |
|
|
24
|
+
| `size` | `xs-mobile` \| `mobile` \| `tablet` \| `desktop` \| `xl-desktop` |
|
|
25
|
+
| `orientation` | `portrait` \| `landscape` |
|
|
26
|
+
| `segments` / `verticalSegments` | viewport segment counts (foldables / dual-screen); `1` on ordinary devices |
|
|
27
|
+
| `handset` | `xs-mobile` or `mobile` |
|
|
28
|
+
| `compact` | "one pane at a time" — a handset or a portrait tablet |
|
|
29
|
+
| `atLeast(size)` | true when the current size is `size` or larger |
|
|
30
|
+
|
|
31
|
+
Reading `device.value` inside an `effect`/`computed` re-runs when the viewport
|
|
32
|
+
crosses a breakpoint, rotates, or changes its segment count. One shared viewport
|
|
33
|
+
source backs every reader.
|
|
34
|
+
|
|
35
|
+
## Breakpoints
|
|
36
|
+
|
|
37
|
+
Default minimum widths (px): `mobile` 360, `tablet` 720, `desktop` 1024,
|
|
38
|
+
`xl-desktop` 1440. Override per reader:
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
const device = deviceClass({ breakpoints: { tablet: 900 } });
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The same numbers are mirrored as CSS custom properties in the foundation
|
|
45
|
+
(`--kui-bp-mobile`, `--kui-bp-tablet`, `--kui-bp-desktop`, `--kui-bp-xl-desktop`)
|
|
46
|
+
so CSS media queries and the JS signal read one source. `classifyViewport(width,
|
|
47
|
+
orientation, segments?, verticalSegments?, breakpoints?)` is exported as the
|
|
48
|
+
pure, DOM-free bucketing core.
|
|
49
|
+
|
|
50
|
+
## Server rendering
|
|
51
|
+
|
|
52
|
+
Without a DOM, `deviceClass()` resolves to an SSR default (1024×768, landscape,
|
|
53
|
+
one segment) and hydrates to the real class on the client. Override the assumed
|
|
54
|
+
viewport with `deviceClass({ ssr: { width, height } })`.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../ai/application-ui-profile.schema.json",
|
|
3
|
+
"schemaVersion": 1,
|
|
4
|
+
"scope": "workspace",
|
|
5
|
+
"catalogs": [
|
|
6
|
+
{
|
|
7
|
+
"package": "@kerfjs/ui",
|
|
8
|
+
"selection": {
|
|
9
|
+
"path": "../../ai/component-catalog.json",
|
|
10
|
+
"schemaVersion": 1
|
|
11
|
+
},
|
|
12
|
+
"composition": {
|
|
13
|
+
"path": "../../ai/component-catalog-v2.json",
|
|
14
|
+
"schemaVersion": 2
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"package": "@acme/ui",
|
|
19
|
+
"composition": {
|
|
20
|
+
"path": "./component-catalog-extension-v2.json",
|
|
21
|
+
"schemaVersion": 2
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"preferences": {
|
|
26
|
+
"application-shell": {
|
|
27
|
+
"preferred": "@kerfjs/ui:recipe-app-shell",
|
|
28
|
+
"rationale": "The workspace uses the standard resizable three-region shell."
|
|
29
|
+
},
|
|
30
|
+
"record-inspector": {
|
|
31
|
+
"preferred": "@acme/ui:inspector",
|
|
32
|
+
"rationale": "The application-owned inspector maps record policy onto Kerf panel primitives."
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"theme": {
|
|
36
|
+
"colorScheme": "light",
|
|
37
|
+
"allowedColorSchemes": ["light", "dark"],
|
|
38
|
+
"density": "standard",
|
|
39
|
+
"allowedDensities": ["standard"]
|
|
40
|
+
},
|
|
41
|
+
"tokens": {
|
|
42
|
+
"--kui-color-brand-fill-normal": "oklch(0.62 0.16 255)"
|
|
43
|
+
},
|
|
44
|
+
"layout": {
|
|
45
|
+
"shell": "@kerfjs/ui:recipe-app-shell",
|
|
46
|
+
"pane": "@kerfjs/ui:pane",
|
|
47
|
+
"responsiveStrategy": "device-class",
|
|
48
|
+
"compactNavigation": "nav-stack",
|
|
49
|
+
"scrollOwnership": "one-per-pane",
|
|
50
|
+
"spacingScale": "kerf-five-step"
|
|
51
|
+
},
|
|
52
|
+
"exceptions": [
|
|
53
|
+
{
|
|
54
|
+
"id": "legacy-report-grid",
|
|
55
|
+
"rules": ["KUI-C101"],
|
|
56
|
+
"target": "src/features/legacy-report/report-grid.tsx",
|
|
57
|
+
"rationale": "The embedded report engine owns this isolated toolbar-compatible control row."
|
|
58
|
+
}
|
|
59
|
+
]
|
|
60
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import '@kerfjs/ui/layout.css';
|
|
2
|
+
|
|
3
|
+
import { delegate, mount, signal } from 'kerfjs';
|
|
4
|
+
import { delegateActions } from 'kerfjs/actions';
|
|
5
|
+
|
|
6
|
+
export interface AppCommand {
|
|
7
|
+
id: string;
|
|
8
|
+
label: string;
|
|
9
|
+
keywords?: string[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface CommandPaletteCallbacks {
|
|
13
|
+
onClose(): void;
|
|
14
|
+
onRun(command: AppCommand): void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Application-local example, not an @kerfjs/ui export. The application owns
|
|
19
|
+
* ranking, history, shortcuts, focus policy, command availability, and copy.
|
|
20
|
+
*/
|
|
21
|
+
export function mountCommandPaletteAdapter(
|
|
22
|
+
root: HTMLElement,
|
|
23
|
+
commands: AppCommand[],
|
|
24
|
+
{ onClose, onRun }: CommandPaletteCallbacks,
|
|
25
|
+
): () => void {
|
|
26
|
+
const query = signal('');
|
|
27
|
+
const render = () => {
|
|
28
|
+
const needle = query.value.trim().toLocaleLowerCase();
|
|
29
|
+
const matches = commands.filter(
|
|
30
|
+
(command) =>
|
|
31
|
+
!needle ||
|
|
32
|
+
[command.label, ...(command.keywords ?? [])].some((value) =>
|
|
33
|
+
value.toLocaleLowerCase().includes(needle),
|
|
34
|
+
),
|
|
35
|
+
);
|
|
36
|
+
return (
|
|
37
|
+
<section
|
|
38
|
+
class="app-command-palette kui-content"
|
|
39
|
+
aria-label="Command palette"
|
|
40
|
+
>
|
|
41
|
+
<div class="kui-content-item">
|
|
42
|
+
<label for="app-command-query">Search commands</label>
|
|
43
|
+
<input
|
|
44
|
+
id="app-command-query"
|
|
45
|
+
type="search"
|
|
46
|
+
value={query.value}
|
|
47
|
+
autocomplete="off"
|
|
48
|
+
data-command-query
|
|
49
|
+
/>
|
|
50
|
+
</div>
|
|
51
|
+
<p class="kui-content-item" aria-live="polite">
|
|
52
|
+
{matches.length} matching commands
|
|
53
|
+
</p>
|
|
54
|
+
<ul class="kui-content-item" aria-label="Matching commands">
|
|
55
|
+
{matches.map((command) => (
|
|
56
|
+
<li>
|
|
57
|
+
<button
|
|
58
|
+
type="button"
|
|
59
|
+
data-action="run-command"
|
|
60
|
+
data-command-id={command.id}
|
|
61
|
+
>
|
|
62
|
+
{command.label}
|
|
63
|
+
</button>
|
|
64
|
+
</li>
|
|
65
|
+
))}
|
|
66
|
+
</ul>
|
|
67
|
+
<footer
|
|
68
|
+
class="kui-control-cluster kui-content-item"
|
|
69
|
+
aria-label="Command palette actions"
|
|
70
|
+
>
|
|
71
|
+
<button type="button" data-action="clear-query">
|
|
72
|
+
Clear search
|
|
73
|
+
</button>
|
|
74
|
+
<button type="button" data-action="close-palette">
|
|
75
|
+
Close
|
|
76
|
+
</button>
|
|
77
|
+
</footer>
|
|
78
|
+
</section>
|
|
79
|
+
);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const stopMount = mount(root, render);
|
|
83
|
+
const stopActions = delegateActions(root, 'click', {
|
|
84
|
+
'run-command': (_event, element) => {
|
|
85
|
+
const id = (element as HTMLElement).dataset.commandId;
|
|
86
|
+
const command = commands.find((candidate) => candidate.id === id);
|
|
87
|
+
if (command) onRun(command);
|
|
88
|
+
},
|
|
89
|
+
'clear-query': () => {
|
|
90
|
+
query.value = '';
|
|
91
|
+
root.querySelector<HTMLInputElement>('[data-command-query]')?.focus();
|
|
92
|
+
},
|
|
93
|
+
'close-palette': onClose,
|
|
94
|
+
});
|
|
95
|
+
const stopInput = delegate<HTMLInputElement>(
|
|
96
|
+
root,
|
|
97
|
+
'input',
|
|
98
|
+
'[data-command-query]',
|
|
99
|
+
(_event, input) => {
|
|
100
|
+
query.value = input.value;
|
|
101
|
+
},
|
|
102
|
+
);
|
|
103
|
+
const stopEscape = delegate(
|
|
104
|
+
root,
|
|
105
|
+
'keydown',
|
|
106
|
+
'[data-command-query]',
|
|
107
|
+
(event) => {
|
|
108
|
+
if ((event as KeyboardEvent).key === 'Escape') onClose();
|
|
109
|
+
},
|
|
110
|
+
);
|
|
111
|
+
let disposed = false;
|
|
112
|
+
return () => {
|
|
113
|
+
if (disposed) return;
|
|
114
|
+
disposed = true;
|
|
115
|
+
stopEscape();
|
|
116
|
+
stopInput();
|
|
117
|
+
stopActions();
|
|
118
|
+
stopMount();
|
|
119
|
+
};
|
|
120
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../ai/component-catalog-extension-v2.schema.json",
|
|
3
|
+
"schemaVersion": 2,
|
|
4
|
+
"package": "@acme/ui",
|
|
5
|
+
"compatibility": {
|
|
6
|
+
"v1Catalog": "./component-catalog-extension.json",
|
|
7
|
+
"identity": "package:id"
|
|
8
|
+
},
|
|
9
|
+
"entries": [
|
|
10
|
+
{
|
|
11
|
+
"key": "@acme/ui:inspector",
|
|
12
|
+
"package": "@acme/ui",
|
|
13
|
+
"id": "inspector",
|
|
14
|
+
"name": "Inspector",
|
|
15
|
+
"kind": "composition",
|
|
16
|
+
"source": "application",
|
|
17
|
+
"parents": { "mode": "listed", "entries": ["@kerfjs/ui:layout"] },
|
|
18
|
+
"contexts": ["record-detail"],
|
|
19
|
+
"zones": [
|
|
20
|
+
{
|
|
21
|
+
"id": "header",
|
|
22
|
+
"accepts": ["@kerfjs/ui:panel-header"],
|
|
23
|
+
"cardinality": { "min": 1, "max": 1 },
|
|
24
|
+
"exclusiveWith": []
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "facts",
|
|
28
|
+
"accepts": ["@kerfjs/ui:value-table"],
|
|
29
|
+
"cardinality": { "min": 1, "max": 1 },
|
|
30
|
+
"exclusiveWith": []
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"children": {
|
|
34
|
+
"mode": "listed",
|
|
35
|
+
"concepts": ["@kerfjs/ui:panel-header", "@kerfjs/ui:value-table"],
|
|
36
|
+
"requiredConcepts": [
|
|
37
|
+
"@kerfjs/ui:panel-header",
|
|
38
|
+
"@kerfjs/ui:value-table"
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
"state": [
|
|
42
|
+
{ "id": "selected-record", "owner": "application", "required": true }
|
|
43
|
+
],
|
|
44
|
+
"wiring": { "required": false, "helpers": [], "obligations": [] },
|
|
45
|
+
"responsive": {
|
|
46
|
+
"owner": "application",
|
|
47
|
+
"behaviors": [
|
|
48
|
+
"May move between inline-end pane and dialog at the application breakpoint."
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
"layout": {
|
|
52
|
+
"roles": ["inspector"],
|
|
53
|
+
"geometry": {
|
|
54
|
+
"margin": "parent",
|
|
55
|
+
"border": "child",
|
|
56
|
+
"padding": "child"
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"accessibility": {
|
|
60
|
+
"obligations": ["The header names the inspector region."]
|
|
61
|
+
},
|
|
62
|
+
"boundaries": {
|
|
63
|
+
"rootClass": "acme-inspector",
|
|
64
|
+
"publicClasses": ["acme-inspector"],
|
|
65
|
+
"publicTokens": []
|
|
66
|
+
},
|
|
67
|
+
"diagnostics": [
|
|
68
|
+
{
|
|
69
|
+
"id": "KUI-C901",
|
|
70
|
+
"severity": "error",
|
|
71
|
+
"when": "the header or facts zone is absent",
|
|
72
|
+
"message": "Inspector requires exactly one header and one facts region."
|
|
73
|
+
}
|
|
74
|
+
],
|
|
75
|
+
"provenance": {
|
|
76
|
+
"selection": "docs/inspector.md",
|
|
77
|
+
"composition": "docs/inspector.md#composition-contract"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../ai/component-catalog-extension.schema.json",
|
|
3
|
+
"schemaVersion": 1,
|
|
4
|
+
"package": "@acme/ui",
|
|
5
|
+
"description": "Application-owned components composed with Kerf UI.",
|
|
6
|
+
"entries": [
|
|
7
|
+
{
|
|
8
|
+
"id": "acme-filter-chip",
|
|
9
|
+
"name": "FilterChip",
|
|
10
|
+
"kind": "component",
|
|
11
|
+
"purpose": "A removable application filter displayed inside a token-search workflow.",
|
|
12
|
+
"useWhen": [
|
|
13
|
+
"A saved application filter needs a compact visible label and remove action."
|
|
14
|
+
],
|
|
15
|
+
"avoidWhen": [
|
|
16
|
+
"The value belongs to TokenSearchField's own controlled token collection."
|
|
17
|
+
],
|
|
18
|
+
"publicClasses": ["acme-filter-chip"],
|
|
19
|
+
"publicTokens": ["--acme-filter-chip-accent"],
|
|
20
|
+
"geometry": {
|
|
21
|
+
"margin": "none",
|
|
22
|
+
"border": "self",
|
|
23
|
+
"padding": "self"
|
|
24
|
+
},
|
|
25
|
+
"documentation": "docs/filter-chip.md"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": "acme-inspector",
|
|
29
|
+
"name": "Inspector",
|
|
30
|
+
"kind": "composition",
|
|
31
|
+
"purpose": "An application inspector composed from Kerf panel, content, and value primitives.",
|
|
32
|
+
"useWhen": ["A selected record needs a titled fact-and-action region."],
|
|
33
|
+
"avoidWhen": ["A ValueTable alone expresses the complete interaction."],
|
|
34
|
+
"geometry": {
|
|
35
|
+
"margin": "parent",
|
|
36
|
+
"border": "child",
|
|
37
|
+
"padding": "child",
|
|
38
|
+
"notes": [
|
|
39
|
+
"The embedding pane positions the inspector; PanelHeader, ValueTable, and action groups retain their own geometry."
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
"documentation": "docs/inspector.md"
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|