@kerfjs/ui 5.0.0-beta.16 → 5.0.0-beta.18

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.
Files changed (218) hide show
  1. package/README.md +111 -81
  2. package/ai/component-catalog-extension.schema.json +79 -0
  3. package/ai/component-catalog.json +499 -0
  4. package/ai/component-catalog.schema.json +15 -0
  5. package/ai/public-api-signatures-v1.md +86 -32
  6. package/ai/skill.md +60 -51
  7. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  8. package/dist/app-tab.d.ts +1 -1
  9. package/dist/app-tab.js +1 -1
  10. package/dist/catalog.d.ts +12 -3
  11. package/dist/catalog.js +283 -90
  12. package/dist/catalog.js.map +1 -1
  13. package/dist/chunk-43FUQH35.js +83 -0
  14. package/dist/chunk-43FUQH35.js.map +1 -0
  15. package/dist/{chunk-YGN7OMLT.js → chunk-4TRDV6RL.js} +2 -2
  16. package/dist/chunk-4TRDV6RL.js.map +1 -0
  17. package/dist/chunk-6ETZKKAE.js +38 -0
  18. package/dist/chunk-6ETZKKAE.js.map +1 -0
  19. package/dist/chunk-6WTETUZ6.js +21 -0
  20. package/dist/chunk-6WTETUZ6.js.map +1 -0
  21. package/dist/chunk-7L6EHUMV.js +31 -0
  22. package/dist/chunk-7L6EHUMV.js.map +1 -0
  23. package/dist/chunk-BBRXX6PF.js +108 -0
  24. package/dist/chunk-BBRXX6PF.js.map +1 -0
  25. package/dist/chunk-DPDBVKNA.js +113 -0
  26. package/dist/chunk-DPDBVKNA.js.map +1 -0
  27. package/dist/chunk-ELSJX4W7.js +68 -0
  28. package/dist/chunk-ELSJX4W7.js.map +1 -0
  29. package/dist/{chunk-LCOBDOCC.js → chunk-ENVTNLYC.js} +153 -67
  30. package/dist/chunk-ENVTNLYC.js.map +1 -0
  31. package/dist/{chunk-AHQI52QO.js → chunk-FEY65TBV.js} +6 -2
  32. package/dist/chunk-FEY65TBV.js.map +1 -0
  33. package/dist/chunk-JTHUXDN2.js +58 -0
  34. package/dist/chunk-JTHUXDN2.js.map +1 -0
  35. package/dist/chunk-LPOMRC4C.js +25 -0
  36. package/dist/chunk-LPOMRC4C.js.map +1 -0
  37. package/dist/chunk-NENBUYX5.js +79 -0
  38. package/dist/chunk-NENBUYX5.js.map +1 -0
  39. package/dist/{chunk-XXMOARTH.js → chunk-NVWXKU37.js} +57 -16
  40. package/dist/chunk-NVWXKU37.js.map +1 -0
  41. package/dist/chunk-PIDTEQ3U.js +105 -0
  42. package/dist/chunk-PIDTEQ3U.js.map +1 -0
  43. package/dist/chunk-PX3YSS5C.js +32 -0
  44. package/dist/chunk-PX3YSS5C.js.map +1 -0
  45. package/dist/chunk-PZQVSDLH.js +61 -0
  46. package/dist/chunk-PZQVSDLH.js.map +1 -0
  47. package/dist/chunk-QIRXYKCE.js +113 -0
  48. package/dist/chunk-QIRXYKCE.js.map +1 -0
  49. package/dist/chunk-QO55FN2Y.js +20 -0
  50. package/dist/chunk-QO55FN2Y.js.map +1 -0
  51. package/dist/chunk-QQFJMRIB.js +45 -0
  52. package/dist/chunk-QQFJMRIB.js.map +1 -0
  53. package/dist/chunk-S3HKPI7I.js +218 -0
  54. package/dist/chunk-S3HKPI7I.js.map +1 -0
  55. package/dist/chunk-S3PCZ7NV.js +38 -0
  56. package/dist/chunk-S3PCZ7NV.js.map +1 -0
  57. package/dist/{chunk-7BR3DO2A.js → chunk-SRSJO5QE.js} +13 -4
  58. package/dist/chunk-SRSJO5QE.js.map +1 -0
  59. package/dist/chunk-U5IFGQCD.js +117 -0
  60. package/dist/chunk-U5IFGQCD.js.map +1 -0
  61. package/dist/{chunk-56RJXPHG.js → chunk-Y6LYKFXY.js} +1 -1
  62. package/dist/{chunk-56RJXPHG.js.map → chunk-Y6LYKFXY.js.map} +1 -1
  63. package/dist/chunk-ZK2G3VR5.js +35 -0
  64. package/dist/chunk-ZK2G3VR5.js.map +1 -0
  65. package/dist/chunk-ZVI5YST2.js +41 -0
  66. package/dist/chunk-ZVI5YST2.js.map +1 -0
  67. package/dist/collapsible-panel.d.ts +2 -2
  68. package/dist/collapsible-panel.js +47 -6
  69. package/dist/collapsible-panel.js.map +1 -1
  70. package/dist/device-class.js +33 -5
  71. package/dist/device-class.js.map +1 -1
  72. package/dist/disclosure-arrow.js +1 -1
  73. package/dist/empty-state.d.ts +1 -1
  74. package/dist/empty-state.js +1 -1
  75. package/dist/floating-toolbar.d.ts +1 -1
  76. package/dist/floating-toolbar.js +1 -1
  77. package/dist/index.js +25 -25
  78. package/dist/list-action-row.d.ts +1 -1
  79. package/dist/list-action-row.js +1 -1
  80. package/dist/list-header.d.ts +1 -1
  81. package/dist/list-header.js +1 -1
  82. package/dist/list-inset-control.d.ts +1 -1
  83. package/dist/list-inset-control.js +1 -1
  84. package/dist/list-inset-text.d.ts +1 -1
  85. package/dist/list-inset-text.js +1 -1
  86. package/dist/list-item.d.ts +1 -1
  87. package/dist/list-item.js +1 -1
  88. package/dist/loading-spinner.js +1 -1
  89. package/dist/nav-stack.d.ts +1 -1
  90. package/dist/nav-stack.js +1 -1
  91. package/dist/panel-header.d.ts +1 -1
  92. package/dist/panel-header.js +1 -1
  93. package/dist/resizable-region.d.ts +1 -1
  94. package/dist/resizable-region.js +1 -1
  95. package/dist/segmented-control.js +1 -1
  96. package/dist/select.d.ts +1 -1
  97. package/dist/select.js +1 -1
  98. package/dist/skeleton.d.ts +1 -1
  99. package/dist/skeleton.js +1 -1
  100. package/dist/split-view.d.ts +1 -1
  101. package/dist/split-view.js +70 -10
  102. package/dist/split-view.js.map +1 -1
  103. package/dist/state-banner.d.ts +1 -1
  104. package/dist/state-banner.js +1 -1
  105. package/dist/styles/catalog.css +48 -1
  106. package/dist/styles/toolbar-text.css +54 -2
  107. package/dist/styles/webawesome.css +131 -0
  108. package/dist/tab-bar.d.ts +1 -1
  109. package/dist/tab-bar.js +1 -1
  110. package/dist/tab-scaffold.d.ts +1 -1
  111. package/dist/tab-scaffold.js +43 -8
  112. package/dist/tab-scaffold.js.map +1 -1
  113. package/dist/token-search-field.js +1 -1
  114. package/dist/toolbar-control-group.d.ts +1 -1
  115. package/dist/toolbar-control-group.js +1 -1
  116. package/dist/toolbar-text.d.ts +17 -1
  117. package/dist/toolbar-text.js +1 -1
  118. package/dist/toolbar.d.ts +1 -1
  119. package/dist/toolbar.js +1 -1
  120. package/dist/value-table.d.ts +2 -2
  121. package/dist/value-table.js +1 -1
  122. package/dist/wire-catalog.d.ts +31 -2
  123. package/dist/wire-catalog.js +203 -8
  124. package/dist/wire-catalog.js.map +1 -1
  125. package/dist/wire-nav-stack.js +22 -7
  126. package/dist/wire-nav-stack.js.map +1 -1
  127. package/dist/wire-resizable-regions.d.ts +1 -1
  128. package/dist/wire-resizable-regions.js +1 -1
  129. package/dist/wire-sidebar.js +52 -41
  130. package/dist/wire-sidebar.js.map +1 -1
  131. package/dist/wire-tab-bars.js +1 -1
  132. package/dist/wire-tab-scaffold.js +9 -4
  133. package/dist/wire-tab-scaffold.js.map +1 -1
  134. package/dist/wire-token-search-fields.d.ts +1 -1
  135. package/dist/wire-token-search-fields.js +1 -1
  136. package/dist/workbench.d.ts +1 -1
  137. package/dist/workbench.js +56 -9
  138. package/dist/workbench.js.map +1 -1
  139. package/docs/app-layouts.md +7 -7
  140. package/docs/catalog.md +110 -25
  141. package/docs/collapsible-panel.md +38 -11
  142. package/docs/component-contract.md +30 -2
  143. package/docs/component-selection.md +76 -65
  144. package/docs/design/templates.md +1 -1
  145. package/docs/design-philosophy.md +5 -5
  146. package/docs/device-class.md +8 -8
  147. package/docs/examples/command-palette-adapter.tsx +67 -17
  148. package/docs/examples/component-catalog-extension.json +45 -0
  149. package/docs/layout.md +19 -19
  150. package/docs/nav-stack.md +15 -6
  151. package/docs/recipes.md +4 -4
  152. package/docs/split-view.md +3 -3
  153. package/docs/tab-scaffold.md +16 -7
  154. package/docs/ux-demo.md +2 -2
  155. package/docs/webawesome-theme.md +73 -8
  156. package/docs/workbench.md +18 -5
  157. package/llms.txt +36 -15
  158. package/package.json +6 -4
  159. package/ux-demo/recipes/app-shell.tsx +206 -10
  160. package/ux-demo/recipes/collapsible-sidebar.tsx +167 -44
  161. package/ux-demo/recipes/compact-toolbar.tsx +114 -12
  162. package/ux-demo/recipes/composer-form.tsx +106 -18
  163. package/ux-demo/recipes/list-detail-dialog.tsx +144 -8
  164. package/ux-demo/recipes/list-workspace-states.tsx +165 -8
  165. package/ux-demo/recipes/loaders.ts +5 -2
  166. package/ux-demo/recipes/loading-inspector.tsx +124 -41
  167. package/ux-demo/recipes/mount-recipe.ts +27 -6
  168. package/ux-demo/recipes/navigation-sidebar.tsx +120 -9
  169. package/ux-demo/recipes/navigation-stack.tsx +61 -19
  170. package/ux-demo/recipes/types.ts +3 -1
  171. package/ux-demo/recipes/workspace-header.tsx +57 -2
  172. package/dist/chunk-2Z5TWHKQ.js +0 -34
  173. package/dist/chunk-2Z5TWHKQ.js.map +0 -1
  174. package/dist/chunk-37T3VNIZ.js +0 -19
  175. package/dist/chunk-37T3VNIZ.js.map +0 -1
  176. package/dist/chunk-55DATV3A.js +0 -10
  177. package/dist/chunk-55DATV3A.js.map +0 -1
  178. package/dist/chunk-5ATCDSQS.js +0 -42
  179. package/dist/chunk-5ATCDSQS.js.map +0 -1
  180. package/dist/chunk-5E2HVJ33.js +0 -10
  181. package/dist/chunk-5E2HVJ33.js.map +0 -1
  182. package/dist/chunk-7BR3DO2A.js.map +0 -1
  183. package/dist/chunk-7JB7VPRI.js +0 -34
  184. package/dist/chunk-7JB7VPRI.js.map +0 -1
  185. package/dist/chunk-7LDCTU7D.js +0 -134
  186. package/dist/chunk-7LDCTU7D.js.map +0 -1
  187. package/dist/chunk-AHQI52QO.js.map +0 -1
  188. package/dist/chunk-AQNKJRFH.js +0 -79
  189. package/dist/chunk-AQNKJRFH.js.map +0 -1
  190. package/dist/chunk-AVZHJN6C.js +0 -14
  191. package/dist/chunk-AVZHJN6C.js.map +0 -1
  192. package/dist/chunk-B24C4A6T.js +0 -22
  193. package/dist/chunk-B24C4A6T.js.map +0 -1
  194. package/dist/chunk-BLK3UEEI.js +0 -23
  195. package/dist/chunk-BLK3UEEI.js.map +0 -1
  196. package/dist/chunk-CH4SQ6H5.js +0 -39
  197. package/dist/chunk-CH4SQ6H5.js.map +0 -1
  198. package/dist/chunk-DAFFDO33.js +0 -14
  199. package/dist/chunk-DAFFDO33.js.map +0 -1
  200. package/dist/chunk-I7INRJO4.js +0 -17
  201. package/dist/chunk-I7INRJO4.js.map +0 -1
  202. package/dist/chunk-L4OKFDJY.js +0 -24
  203. package/dist/chunk-L4OKFDJY.js.map +0 -1
  204. package/dist/chunk-LCOBDOCC.js.map +0 -1
  205. package/dist/chunk-M5JRI6MN.js +0 -27
  206. package/dist/chunk-M5JRI6MN.js.map +0 -1
  207. package/dist/chunk-RNPGFQ33.js +0 -10
  208. package/dist/chunk-RNPGFQ33.js.map +0 -1
  209. package/dist/chunk-RUNWEPR4.js +0 -10
  210. package/dist/chunk-RUNWEPR4.js.map +0 -1
  211. package/dist/chunk-VPCTCUED.js +0 -10
  212. package/dist/chunk-VPCTCUED.js.map +0 -1
  213. package/dist/chunk-WVPYVDXY.js +0 -15
  214. package/dist/chunk-WVPYVDXY.js.map +0 -1
  215. package/dist/chunk-XE5ZLPCC.js +0 -20
  216. package/dist/chunk-XE5ZLPCC.js.map +0 -1
  217. package/dist/chunk-XXMOARTH.js.map +0 -1
  218. package/dist/chunk-YGN7OMLT.js.map +0 -1
package/docs/nav-stack.md CHANGED
@@ -8,9 +8,9 @@ a `NavStack` with one entry**. It is one of the opt-in app layouts (see
8
8
  Import the component and its companion stylesheet:
9
9
 
10
10
  ```ts
11
- import { NavStack, type NavStackView } from '@kerfjs/ui/nav-stack';
12
- import { wireNavStack } from '@kerfjs/ui/wire-nav-stack';
13
- import '@kerfjs/ui/nav-stack.css';
11
+ import { NavStack, type NavStackView } from "@kerfjs/ui/nav-stack";
12
+ import { wireNavStack } from "@kerfjs/ui/wire-nav-stack";
13
+ import "@kerfjs/ui/nav-stack.css";
14
14
  ```
15
15
 
16
16
  ## State lives in the app
@@ -20,16 +20,25 @@ stack as a `signal<NavStackView[]>`, `NavStack({ views })` renders it, and
20
20
  `wireNavStack` animates the transitions.
21
21
 
22
22
  ```tsx
23
- const views = signal<NavStackView[]>([{ key: 'inbox', title: 'Inbox', content: <InboxView /> }]);
23
+ const views = signal<NavStackView[]>([
24
+ { key: "inbox", title: "Inbox", content: <InboxView /> },
25
+ ]);
24
26
 
25
27
  // render inside mount():
26
28
  <NavStack id="mail" label="Mail" views={views.value} />;
27
29
 
28
30
  // once, after first render:
29
- const dispose = wireNavStack(root, { onBack: () => { views.value = views.value.slice(0, -1); } });
31
+ const dispose = wireNavStack(root, {
32
+ onBack: () => {
33
+ views.value = views.value.slice(0, -1);
34
+ },
35
+ });
30
36
 
31
37
  // push / pop by editing the signal:
32
- views.value = [...views.value, { key: id, title: 'Message', content: <MessageView id={id} /> }];
38
+ views.value = [
39
+ ...views.value,
40
+ { key: id, title: "Message", content: <MessageView id={id} /> },
41
+ ];
33
42
  ```
34
43
 
35
44
  `NavStack` renders every entry stacked, the last one active and the rest kept
package/docs/recipes.md CHANGED
@@ -14,12 +14,12 @@ the public `onCommit` callback, retains every disposer, and returns one
14
14
  idempotent disposer:
15
15
 
16
16
  ```ts
17
- import { createRecipe } from './navigation-sidebar.js';
18
- import { mountRecipe } from './mount-recipe.js';
17
+ import { createRecipe } from "./navigation-sidebar.js";
18
+ import { mountRecipe } from "./mount-recipe.js";
19
19
 
20
- const root = document.querySelector<HTMLElement>('#navigation')!;
20
+ const root = document.querySelector<HTMLElement>("#navigation")!;
21
21
  const stopRecipe = mountRecipe(root, createRecipe(announce));
22
- window.addEventListener('pagehide', stopRecipe, { once: true });
22
+ window.addEventListener("pagehide", stopRecipe, { once: true });
23
23
  ```
24
24
 
25
25
  The adapter is delivered as reference source, not a new package runtime export.
@@ -6,9 +6,9 @@ on compact ones. One of the opt-in app layouts (see
6
6
  [`../../docs/23-app-layouts.md`](../../docs/23-app-layouts.md)).
7
7
 
8
8
  ```ts
9
- import { SplitView } from '@kerfjs/ui/split-view';
10
- import { deviceClass } from '@kerfjs/ui/device-class';
11
- import '@kerfjs/ui/split-view.css';
9
+ import { SplitView } from "@kerfjs/ui/split-view";
10
+ import { deviceClass } from "@kerfjs/ui/device-class";
11
+ import "@kerfjs/ui/split-view.css";
12
12
  // plus nav-stack.css when the compact path is reachable, and
13
13
  // wireResizableRegions / wireNavStack for the interactive behavior.
14
14
  ```
@@ -7,9 +7,9 @@ opt-in app layouts (see [`../../docs/23-app-layouts.md`](../../docs/23-app-layou
7
7
  It is distinct from `TabBar` (document-oriented, reorderable strips).
8
8
 
9
9
  ```ts
10
- import { TabScaffold } from '@kerfjs/ui/tab-scaffold';
11
- import { wireTabScaffold } from '@kerfjs/ui/wire-tab-scaffold';
12
- import '@kerfjs/ui/tab-scaffold.css';
10
+ import { TabScaffold } from "@kerfjs/ui/tab-scaffold";
11
+ import { wireTabScaffold } from "@kerfjs/ui/wire-tab-scaffold";
12
+ import "@kerfjs/ui/tab-scaffold.css";
13
13
  ```
14
14
 
15
15
  ## Controlled selection
@@ -19,20 +19,29 @@ The app owns the active tab (a signal); `TabScaffold` renders every tab's scene
19
19
  clicks.
20
20
 
21
21
  ```tsx
22
- const active = signal('home');
22
+ const active = signal("home");
23
23
 
24
24
  <TabScaffold
25
25
  id="app"
26
26
  label="Sections"
27
27
  active={active.value}
28
28
  tabs={[
29
- { id: 'home', label: 'Home', icon: <HomeIcon />, content: <HomeStack /> },
30
- { id: 'search', label: 'Search', icon: <SearchIcon />, content: <SearchStack /> },
29
+ { id: "home", label: "Home", icon: <HomeIcon />, content: <HomeStack /> },
30
+ {
31
+ id: "search",
32
+ label: "Search",
33
+ icon: <SearchIcon />,
34
+ content: <SearchStack />,
35
+ },
31
36
  ]}
32
37
  />;
33
38
 
34
39
  // once, after first render:
35
- const dispose = wireTabScaffold(root, { onSelect: (id) => { active.value = id; } });
40
+ const dispose = wireTabScaffold(root, {
41
+ onSelect: (id) => {
42
+ active.value = id;
43
+ },
44
+ });
36
45
  ```
37
46
 
38
47
  Each `TabScaffoldTab` has an `id`, `label`, optional `icon`, and `content`. The
package/docs/ux-demo.md CHANGED
@@ -10,9 +10,9 @@ deterministic state, and semantic layout owners from the [recipe guide](./recipe
10
10
  - 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.
11
11
  - The `AppTab` route demonstrates a runtime-filtered domain metadata slot and a decorative replacement close icon without changing TabBar selection, close, reorder, or focus ownership. The `ResizableRegion` route likewise replaces only the decorative handle glyph while retaining separator semantics and shared wiring.
12
12
  - 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, feedback, and theme scenarios remain addressable alongside their subcomponents; the root opens the first Kerf component.
13
- - `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, 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. Demo paths resolve to `ui/ux-demo/main.tsx`, the matching `ui/ux-demo/recipes/*.tsx` file, or `ui/ux-demo/webawesome-demos.tsx` according to the canonical entry. First-party component entries additionally derive `ui/src/<browser-subpath>.tsx` from their canonical `delivery.browserImport`.
13
+ - `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. Non-supported Web Awesome recommendations project to a visible `Discouraged` sidebar 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/<browser-subpath>.tsx` from their canonical `delivery.browserImport`.
14
14
  - 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 `ListHeader` and `ListItem` components. 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.
15
+ - 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.
16
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 the subtitle in its own aligned row like `PanelHeader`; 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 complete scrollable preview region rather than a nested card. 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.
17
17
  - The composer-form recipe demonstrates one coherent visible form surface with `PanelHeader` title/summary 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.
18
18
  - The list-detail dialog recipe places its header directly on the dialog edge while preserving the header's internal inset, gives the selected project title the complete outer-plus-inner content gutter, lets the value table fill the available detail column between the shared outer margins, and keeps record actions on one outer gutter without an extra content-item inset. Browser geometry coverage protects those relationships at wide and narrow widths.
@@ -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 '@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';
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,71 @@ 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
+ Form fields carry the same content-item inset as the Kerf primitives: a 1px
58
+ border with 8px inside it (`--wa-form-control-border-width`,
59
+ `--wa-form-control-padding-block`, and `--wa-form-control-padding-inline` are set
60
+ to the `--kui-layout-item-border-width` / `--kui-layout-item-padding` values), so
61
+ a single-line control lands at the standard ~40px height and the value sits 9px
62
+ in from the field edge. Each field's top label is inset by that same border +
63
+ padding (9px) so it lines up with the value inside the field, and is styled
64
+ exactly like a `ListHeader` label — uppercase, `--kui-font-xs`, weight 650, quiet
65
+ foreground. This applies to every free field that exposes a top label
66
+ (`::part(form-control-label)` plus the Slider's `::part(label)`). OTP Input
67
+ exposes `label` instead of `form-control-label`; the theme gives it the same
68
+ uppercase 12px/650 treatment. Inline control labels (Checkbox, Switch) keep
69
+ their natural sentence case.
70
+
71
+ Known Date's field captions and bordered text-like field hints use the same 9px
72
+ inline inset, keeping secondary text aligned with the value rather than the
73
+ field's outer border. This covers Input, Known Date, Number Input, OTP Input,
74
+ Select, Textarea, and Time Input hints; unbordered group hints retain their own
75
+ natural geometry. OTP Input's label and hint both use the 9px field-text inset.
76
+
77
+ Checkbox Group and Radio Group option regions receive the shared 8px inline
78
+ outer inset through `::part(form-control-input)`. Unlike bordered fields, these
79
+ groups have no shell of their own, so the explicit margin places their controls
80
+ on the same content-item geometry without adding padding to each option. The
81
+ Color Picker trigger receives the same 8px inline outer inset because it also
82
+ has no bordered field shell. Slider's complete interactive region receives the
83
+ shared 8px logical inline outer inset through `::part(slider)`, keeping its
84
+ track, markers, references, and hint together without moving the label.
85
+
86
+ Non-field chrome follows explicit, overridable control, surface, and container
87
+ tiers:
88
+
89
+ - `--kui-wa-control-inset` defaults to the 8px content-item padding. It applies
90
+ to tabs, tree-item trailing content, tags, and dropdown items. Tree selection
91
+ also uses Kerf's 8px inline outer margin, so its background reads as an inset
92
+ list item instead of an edge-to-edge stripe. Buttons already consume the same
93
+ `--wa-form-control-padding-inline` 8px value at every size, so no extra part
94
+ override is needed.
95
+ - `--kui-wa-surface-margin` and `--kui-wa-surface-inset` default to 8px.
96
+ Accordion, Card, Details, Callout, and Include use the margin around their
97
+ complete surface and the inset within it. Accordion applies the outer margin
98
+ once to the group rather than separating connected items; Card's header,
99
+ body, and footer all receive the full inset.
100
+ - `--kui-wa-container-inset` defaults to the 16px homogeneous-group step. Tab
101
+ Panel retains this roomier tier for unframed panel content.
102
+
103
+ Badge remains intentionally compact at Web Awesome's intrinsic `0.375em` block /
104
+ `0.625em` inline padding (4.5px / 7.5px at its default 12px text size): it is a
105
+ short status or count, not a content item. Breadcrumb has no bordered or filled
106
+ container, and Scroller delegates item chrome to its slotted children, so both
107
+ retain their upstream geometry. Web Awesome 3.12's free catalog has
108
+ `wa-dropdown-item`, but no `wa-menu-item`; the theme therefore styles the
109
+ supported dropdown item rather than carrying a dead selector.
110
+
111
+ Override a tier for a product scope after importing the theme:
112
+
113
+ ```css
114
+ .roomy-editor {
115
+ --kui-wa-control-inset: 0.75rem;
116
+ --kui-wa-surface-margin: 0.75rem;
117
+ --kui-wa-surface-inset: 0.75rem;
118
+ --kui-wa-container-inset: 1.5rem;
119
+ }
120
+ ```
121
+
57
122
  Accordion, Details, Breadcrumb, and Kerf Select share
58
123
  `--kui-disclosure-icon-scale` (default `.5`) so disclosure and traversal
59
124
  chevrons keep the same visual weight. The Accordion and Details components
@@ -73,12 +138,12 @@ subtree, or for one instance after the theme import:
73
138
 
74
139
  ```css
75
140
  :root {
76
- --wa-tooltip-arrow-size: .375rem;
77
- --kui-wa-popover-arrow-size: .375rem;
141
+ --wa-tooltip-arrow-size: 0.375rem;
142
+ --kui-wa-popover-arrow-size: 0.375rem;
78
143
  }
79
144
 
80
145
  .pointed-popover {
81
- --arrow-size: .5rem;
146
+ --arrow-size: 0.5rem;
82
147
  }
83
148
  ```
84
149
 
@@ -179,7 +244,7 @@ smallest subtree that needs a different identity:
179
244
  :root {
180
245
  --wa-color-brand-fill-loud: #7540a8;
181
246
  --wa-color-focus: #7540a8;
182
- --wa-form-control-border-radius: .5rem;
247
+ --wa-form-control-border-radius: 0.5rem;
183
248
  }
184
249
 
185
250
  .billing-workspace {
package/docs/workbench.md CHANGED
@@ -8,8 +8,8 @@ sidebar. One of the opt-in app layouts (see
8
8
  desktop-class devices.
9
9
 
10
10
  ```ts
11
- import { Workbench } from '@kerfjs/ui/workbench';
12
- import '@kerfjs/ui/workbench.css';
11
+ import { Workbench } from "@kerfjs/ui/workbench";
12
+ import "@kerfjs/ui/workbench.css";
13
13
  ```
14
14
 
15
15
  ## State lives in the app
@@ -25,9 +25,22 @@ const navCollapsed = signal(false);
25
25
  id="studio"
26
26
  label="Studio"
27
27
  main={<Editor />}
28
- leftRail={{ content: <Navigator />, label: 'Navigator', collapsed: navCollapsed.value, size: 280 }}
29
- rightRail={{ content: <Inspector />, label: 'Inspector', collapsed: inspectorCollapsed.value }}
30
- bottomDrawer={{ content: <Console />, label: 'Console', collapsed: consoleCollapsed.value }}
28
+ leftRail={{
29
+ content: <Navigator />,
30
+ label: "Navigator",
31
+ collapsed: navCollapsed.value,
32
+ size: 280,
33
+ }}
34
+ rightRail={{
35
+ content: <Inspector />,
36
+ label: "Inspector",
37
+ collapsed: inspectorCollapsed.value,
38
+ }}
39
+ bottomDrawer={{
40
+ content: <Console />,
41
+ label: "Console",
42
+ collapsed: consoleCollapsed.value,
43
+ }}
31
44
  />;
32
45
  ```
33
46
 
package/llms.txt CHANGED
@@ -6,7 +6,7 @@
6
6
  > generate correct, good-looking kerf UI — it is not a catalog to browse.
7
7
 
8
8
  ```bash
9
- npm install kerfjs @kerfjs/ui # kerfjs is a peer; Web Awesome is an optional peer
9
+ npm install kerfjs @kerfjs/ui # kerfjs is a peer; Web Awesome is an optional peer
10
10
  ```
11
11
 
12
12
  Import each component from its own subpath (`@kerfjs/ui/list-item`, `@kerfjs/ui/toolbar`,
@@ -22,15 +22,18 @@ maintain a central style list. Configure JSX with `"jsxImportSource": "kerfjs"`.
22
22
  [public-api-signatures-v1.md](./ai/public-api-signatures-v1.md) (real prop names,
23
23
  callback shapes, disposer return types).
24
24
  3. **For exhaustive, structured facts** (ids, exports, variants, `publicClasses`,
25
- relationships, side effects) load the
25
+ relationships, side effects, and geometry ownership) load the
26
26
  [Machine-readable component catalog](./ai/component-catalog.json) — the
27
- canonical checked-in source; its schema is alongside it.
27
+ canonical checked-in source; its schema is alongside it. Also load the
28
+ consuming application's catalog extension when present; generate one from the
29
+ [Consumer catalog extension schema](./ai/component-catalog-extension.schema.json)
30
+ when app-owned components must participate in selection or alignment.
28
31
  4. **Apply the rules below and in** [skill.md](./ai/skill.md).
29
32
 
30
33
  ## Core rules (do the right thing)
31
34
 
32
35
  - **Reach for the primitive, not for CSS.** The package is built to look right
33
- *unstyled*. Before adding `padding`, `margin`, `width`, `height`, `border`,
36
+ _unstyled_. Before adding `padding`, `margin`, `width`, `height`, `border`,
34
37
  `background`, a wrapper card, or a decoration, check whether the component, the
35
38
  pane, or the content-item already owns it — it almost always does. Prefer a
36
39
  component prop or a `--kui-*` token; write CSS only for genuinely new structure,
@@ -40,6 +43,21 @@ maintain a central style list. Configure JSX with `"jsxImportSource": "kerfjs"`.
40
43
  own the geometry (8px inline margin + 1px border + 8px padding). Do not add a
41
44
  container padding on top of a content-item's own margin — pick one owner. Use
42
45
  `.kui-content` for 24px major vertical rhythm.
46
+ - **Keep Web Awesome on the shared inset tiers.** `webawesome.css` uses
47
+ `--kui-wa-control-inset` (8px controls/items) and
48
+ `--kui-wa-surface-margin` / `--kui-wa-surface-inset` (8px around/inside
49
+ Accordion, Card, Details, Callout, and Include), while
50
+ `--kui-wa-container-inset` keeps Tab Panel at 16px. Override the tier at the
51
+ narrowest useful scope instead of restyling individual shadow parts.
52
+ Checkbox and Radio Group option regions also receive the shared 8px inline
53
+ outer inset because those groups have no bordered field shell. The Color
54
+ Picker trigger receives the same inset for the same unbordered geometry.
55
+ Slider's complete interactive region uses the shared 8px logical inline outer
56
+ inset without shifting its already-aligned label.
57
+ Known Date's Month/Day/Year captions and bordered text-like field hints align
58
+ with field values at the shared 9px border-plus-padding inset. OTP Input's
59
+ label uses the same uppercase xs/650 treatment and its label and hint share
60
+ that 9px alignment.
43
61
  - **Trust the defaults.** Render a control at its natural size and color (a
44
62
  `LucideIcon` is 24px); if it looks wrong, fix the surrounding layout, not the
45
63
  control. Never force a component's width/height to size it — that leaves a halo
@@ -54,7 +72,7 @@ maintain a central style list. Configure JSX with `"jsxImportSource": "kerfjs"`.
54
72
  popup menu. A toolbar popup menu is a `single` `ToolbarControlGroup` around a
55
73
  `wa-dropdown` (its `slot="trigger"` `wa-button` is the toolbar button, kept under
56
74
  `data-morph-skip-children`).
57
- - **`PanelHeader` is *the* panel/dialog/page heading.** A plain toolbar with an
75
+ - **`PanelHeader` is _the_ panel/dialog/page heading.** A plain toolbar with an
58
76
  optional bordered icon group, an extra-large `ToolbarText` title, the trailing
59
77
  controls you pass, and an optional subtitle below — do not hand-build a heading
60
78
  row or restyle a toolbar into one.
@@ -75,7 +93,7 @@ maintain a central style list. Configure JSX with `"jsxImportSource": "kerfjs"`.
75
93
  - **App state is domain/persisted; helpers own only ephemeral mechanics.** Keep
76
94
  navigation stacks, tab selection and order, pane sizes, and `collapsed`/`expanded`
77
95
  disclosure flags in the app — they are data or persisted layout, and the app reads
78
- them to render. The `wire…` helpers own the *ephemeral* parts: `wireNavStack` the
96
+ them to render. The `wire…` helpers own the _ephemeral_ parts: `wireNavStack` the
79
97
  push/pop animation, `wireTabBars` the overflow autoscroll and drag preview,
80
98
  `wireResizableRegions` the live drag preview; they report committed changes via
81
99
  callbacks. The one richer case is `wireTokenSearchFields`, which manages the
@@ -113,13 +131,16 @@ tree-shakeable, declarative with `wire…` helpers, each with a companion CSS im
113
131
  `NavStack`, `SplitView`, `Workbench`, `TabScaffold`, driven by `deviceClass()` from
114
132
  `@kerfjs/ui/device-class`. For a standalone collapsible rail/drawer outside a full
115
133
  shell, `@kerfjs/ui/collapsible-panel` (`CollapsiblePanel`, `CollapsiblePanelToggle`)
116
- + `@kerfjs/ui/wire-sidebar` (`wireSidebar`: toggle, focus, compact overlay, persistence).
117
- `@kerfjs/ui/catalog` is another opt-in shell a
118
- `Catalog` component + `wireCatalog` helper for building a component-gallery catalog
119
- (collapsible category sidebar + preview stage + resources footer) from your own
120
- entries; controlled/stateless like the layouts. `@kerfjs/ui/webawesome` is a
121
- type-only boundary for `wa-*` JSX; `@kerfjs/ui/select/register` and the CSS are the
122
- declared side effects.
134
+
135
+ - `@kerfjs/ui/wire-sidebar` (`wireSidebar`: toggle, focus, compact overlay, persistence).
136
+ `@kerfjs/ui/catalog` is another opt-in shell a
137
+ `Catalog` component + `wireCatalog` helper for building a component-gallery catalog
138
+ (collapsible category sidebar + preview stage + resources footer, with an opt-in
139
+ transparent-bound and margin geometry overlay plus focus-preserving active-row
140
+ reveal for long desktop sidebars) from your own
141
+ entries; controlled/stateless like the layouts. `@kerfjs/ui/webawesome` is a
142
+ type-only boundary for `wa-*` JSX; `@kerfjs/ui/select/register` and the CSS are the
143
+ declared side effects.
123
144
 
124
145
  ## Reference
125
146
 
@@ -130,6 +151,6 @@ declared side effects.
130
151
  - [accessibility.md](./docs/accessibility.md): keyboard and ARIA contracts per component.
131
152
  - [recipes.md](./docs/recipes.md): production compositions (app shell, list-detail dialog, composer form, …) as copyable references.
132
153
  - [app-layouts.md](./docs/app-layouts.md): choosing `NavStack`/`SplitView`/`Workbench`/`TabScaffold` by data + interaction + device, and dialog presentation.
133
- - [webawesome-theme.md](./docs/webawesome-theme.md): the optional Web Awesome theme; catalog coverage means themed-and-supported, not preferred (prefer the Kerf primitive when one exists).
134
- - [component-catalog.json](./ai/component-catalog.json) + [public-api-signatures-v1.md](./ai/public-api-signatures-v1.md) + [webawesome-jsx-signatures-v1.md](./ai/webawesome-jsx-signatures-v1.md): machine-readable facts and exact signatures.
154
+ - [webawesome-theme.md](./docs/webawesome-theme.md): the optional Web Awesome theme; catalog coverage means themed-and-supported, not preferred (prefer the Kerf primitive when one exists). The UX sidebar visibly tags superseded and exceptional Web Awesome choices as `Discouraged`; Popup remains an available conditional positioning primitive.
155
+ - [component-catalog.json](./ai/component-catalog.json) + [component-catalog-extension.schema.json](./ai/component-catalog-extension.schema.json) + [public-api-signatures-v1.md](./ai/public-api-signatures-v1.md) + [webawesome-jsx-signatures-v1.md](./ai/webawesome-jsx-signatures-v1.md): machine-readable facts, a reusable app-component extension contract, and exact signatures.
135
156
  - [README.md](./README.md): package overview and the component subpath table.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kerfjs/ui",
3
- "version": "5.0.0-beta.16",
3
+ "version": "5.0.0-beta.18",
4
4
  "description": "Accessible, composable UI primitives for kerf applications.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -272,8 +272,9 @@
272
272
  "dev": "npm run build && vite --config ux-demo/vite.config.ts",
273
273
  "demo:build": "npm run build && vite build --config ux-demo/vite.config.ts && node scripts/check-demo-bundle.mjs",
274
274
  "demo:serve": "vite preview --config ux-demo/vite.config.ts",
275
+ "format": "prettier --write . --ignore-unknown",
275
276
  "format:css": "prettier --write \"src/**/*.css\" \"ux-demo/**/*.css\"",
276
- "check:format": "prettier --check \"src/**/*.css\" \"ux-demo/**/*.css\"",
277
+ "check:format": "prettier --check . --ignore-unknown",
277
278
  "catalog:sync": "node scripts/sync-component-catalog.mjs",
278
279
  "check:catalog": "node scripts/sync-component-catalog.mjs --check && node scripts/check-component-catalog.mjs",
279
280
  "check:recipes": "node scripts/check-recipes.mjs",
@@ -285,14 +286,15 @@
285
286
  "ai:regressions:record": "node scripts/record-ai-regression-run.mjs",
286
287
  "ai:regressions:score": "node scripts/score-ai-regression.mjs",
287
288
  "check:guidance": "node scripts/check-decision-guidance.mjs",
288
- "lint": "eslint src tests ux-demo docs/examples --max-warnings 0",
289
+ "lint:eslint": "eslint src tests ux-demo docs/examples --max-warnings 0",
290
+ "lint": "npm run lint:eslint && npm run check:format",
289
291
  "typecheck": "node node_modules/typescript7/bin/tsc --noEmit",
290
292
  "test": "npm run test:unit && npm run test:bundle",
291
293
  "test:unit": "vitest run tests/unit --coverage",
292
294
  "test:bundle": "npm run build && vitest run tests/bundle",
293
295
  "test:consumer-types": "npm run build && node node_modules/typescript7/bin/tsc -p tests/consumer-types/webawesome/tsconfig.json",
294
296
  "test:e2e": "npm run demo:build && playwright test",
295
- "check": "npm run check:format && npm run check:catalog && npm run check:recipes && npm run check:guidance && npm run check:ai-regressions && npm run lint && npm run typecheck && npm test && npm run test:consumer-types && npm run check:ai-signatures && npm run demo:build && npm run check:design-templates && npm pack --dry-run",
297
+ "check": "npm run check:catalog && npm run check:recipes && npm run check:guidance && npm run check:ai-regressions && npm run lint && npm run typecheck && npm test && npm run test:consumer-types && npm run check:ai-signatures && npm run demo:build && npm run check:design-templates && npm pack --dry-run",
296
298
  "prepublishOnly": "npm run check",
297
299
  "check:design-templates": "node scripts/check-design-templates.mjs",
298
300
  "check:design-templates:drift": "node scripts/check-design-templates-drift.mjs",