@kerfjs/ui 5.0.0-beta.17 → 5.0.0-beta.21

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 (274) hide show
  1. package/README.md +221 -81
  2. package/ai/application-ui-diagnostic-ids-v1.json +92 -0
  3. package/ai/application-ui-profile-sync.cjs +529 -0
  4. package/ai/application-ui-profile.d.mts +1 -0
  5. package/ai/application-ui-profile.d.ts +102 -0
  6. package/ai/application-ui-profile.defaults.json +41 -0
  7. package/ai/application-ui-profile.mjs +626 -0
  8. package/ai/application-ui-profile.schema.json +130 -0
  9. package/ai/catalog-authoring.json +25 -0
  10. package/ai/catalog-authoring.schema.json +61 -0
  11. package/ai/compile-time-contracts-v1.json +101 -0
  12. package/ai/compile-time-contracts-v1.schema.json +49 -0
  13. package/ai/component-catalog-extension-v2.d.ts +7 -0
  14. package/ai/component-catalog-extension-v2.schema.json +7 -0
  15. package/ai/component-catalog-extension.schema.json +79 -0
  16. package/ai/component-catalog-v2-overrides.json +326 -0
  17. package/ai/component-catalog-v2.d.ts +67 -0
  18. package/ai/component-catalog-v2.json +4441 -0
  19. package/ai/component-catalog-v2.schema.json +246 -0
  20. package/ai/component-catalog.json +649 -6
  21. package/ai/component-catalog.schema.json +15 -0
  22. package/ai/public-api-signatures-v1.md +357 -91
  23. package/ai/skill.md +95 -50
  24. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  25. package/analyzer/cli.mjs +46 -0
  26. package/analyzer/index.d.mts +45 -0
  27. package/analyzer/index.mjs +743 -0
  28. package/analyzer/report.schema.json +66 -0
  29. package/dist/app-tab.d.ts +1 -1
  30. package/dist/app-tab.js +1 -1
  31. package/dist/browser/pane.js +3 -0
  32. package/dist/browser/sunken-panel.js +3 -0
  33. package/dist/catalog-resources.d.ts +34 -0
  34. package/dist/catalog-resources.js +22 -0
  35. package/dist/catalog-resources.js.map +1 -0
  36. package/dist/catalog.d.ts +29 -4
  37. package/dist/catalog.js +302 -84
  38. package/dist/catalog.js.map +1 -1
  39. package/dist/chunk-5VTB2BKP.js +35 -0
  40. package/dist/chunk-5VTB2BKP.js.map +1 -0
  41. package/dist/chunk-6WTETUZ6.js +21 -0
  42. package/dist/chunk-6WTETUZ6.js.map +1 -0
  43. package/dist/chunk-7KEUJIIC.js +218 -0
  44. package/dist/chunk-7KEUJIIC.js.map +1 -0
  45. package/dist/chunk-7L6EHUMV.js +31 -0
  46. package/dist/chunk-7L6EHUMV.js.map +1 -0
  47. package/dist/{chunk-XXMOARTH.js → chunk-AASLYRGE.js} +57 -16
  48. package/dist/chunk-AASLYRGE.js.map +1 -0
  49. package/dist/chunk-BBRXX6PF.js +108 -0
  50. package/dist/chunk-BBRXX6PF.js.map +1 -0
  51. package/dist/{chunk-6NLRBSVX.js → chunk-CN2XNTAM.js} +129 -72
  52. package/dist/chunk-CN2XNTAM.js.map +1 -0
  53. package/dist/chunk-DPDBVKNA.js +113 -0
  54. package/dist/chunk-DPDBVKNA.js.map +1 -0
  55. package/dist/chunk-DSNIYOZ3.js +114 -0
  56. package/dist/chunk-DSNIYOZ3.js.map +1 -0
  57. package/dist/chunk-ELSJX4W7.js +68 -0
  58. package/dist/chunk-ELSJX4W7.js.map +1 -0
  59. package/dist/{chunk-AHQI52QO.js → chunk-FEY65TBV.js} +6 -2
  60. package/dist/chunk-FEY65TBV.js.map +1 -0
  61. package/dist/chunk-JRKSK2HX.js +79 -0
  62. package/dist/chunk-JRKSK2HX.js.map +1 -0
  63. package/dist/chunk-K57KRAOV.js +117 -0
  64. package/dist/chunk-K57KRAOV.js.map +1 -0
  65. package/dist/chunk-LPOMRC4C.js +25 -0
  66. package/dist/chunk-LPOMRC4C.js.map +1 -0
  67. package/dist/chunk-M7JBER5U.js +41 -0
  68. package/dist/chunk-M7JBER5U.js.map +1 -0
  69. package/dist/chunk-NENBUYX5.js +79 -0
  70. package/dist/chunk-NENBUYX5.js.map +1 -0
  71. package/dist/chunk-OHU6CI22.js +83 -0
  72. package/dist/chunk-OHU6CI22.js.map +1 -0
  73. package/dist/{chunk-YGN7OMLT.js → chunk-OZWU5ZPZ.js} +2 -2
  74. package/dist/chunk-OZWU5ZPZ.js.map +1 -0
  75. package/dist/chunk-PIDTEQ3U.js +105 -0
  76. package/dist/chunk-PIDTEQ3U.js.map +1 -0
  77. package/dist/chunk-PX3YSS5C.js +32 -0
  78. package/dist/chunk-PX3YSS5C.js.map +1 -0
  79. package/dist/chunk-PZQVSDLH.js +61 -0
  80. package/dist/chunk-PZQVSDLH.js.map +1 -0
  81. package/dist/chunk-QO55FN2Y.js +20 -0
  82. package/dist/chunk-QO55FN2Y.js.map +1 -0
  83. package/dist/chunk-QQFJMRIB.js +45 -0
  84. package/dist/chunk-QQFJMRIB.js.map +1 -0
  85. package/dist/chunk-RYRIFZCT.js +58 -0
  86. package/dist/chunk-RYRIFZCT.js.map +1 -0
  87. package/dist/{chunk-7BR3DO2A.js → chunk-SRSJO5QE.js} +13 -4
  88. package/dist/chunk-SRSJO5QE.js.map +1 -0
  89. package/dist/chunk-VLYV65LK.js +38 -0
  90. package/dist/chunk-VLYV65LK.js.map +1 -0
  91. package/dist/chunk-W4CXQYSG.js +23 -0
  92. package/dist/chunk-W4CXQYSG.js.map +1 -0
  93. package/dist/{chunk-WXMGNX2Y.js → chunk-W7YD6E4N.js} +2 -2
  94. package/dist/chunk-W7YD6E4N.js.map +1 -0
  95. package/dist/{chunk-56RJXPHG.js → chunk-Y6LYKFXY.js} +1 -1
  96. package/dist/{chunk-56RJXPHG.js.map → chunk-Y6LYKFXY.js.map} +1 -1
  97. package/dist/collapsible-panel.d.ts +2 -2
  98. package/dist/collapsible-panel.js +47 -6
  99. package/dist/collapsible-panel.js.map +1 -1
  100. package/dist/device-class.js +33 -5
  101. package/dist/device-class.js.map +1 -1
  102. package/dist/disclosure-arrow.js +1 -1
  103. package/dist/empty-state.d.ts +1 -1
  104. package/dist/empty-state.js +1 -1
  105. package/dist/floating-toolbar.d.ts +1 -1
  106. package/dist/floating-toolbar.js +1 -1
  107. package/dist/index.d.ts +6 -4
  108. package/dist/index.js +27 -25
  109. package/dist/list-action-row.d.ts +1 -1
  110. package/dist/list-action-row.js +1 -1
  111. package/dist/list-header.d.ts +30 -9
  112. package/dist/list-header.js +1 -1
  113. package/dist/list-inset-control.d.ts +1 -1
  114. package/dist/list-inset-control.js +1 -1
  115. package/dist/list-inset-text.d.ts +1 -1
  116. package/dist/list-inset-text.js +1 -1
  117. package/dist/list-item.d.ts +1 -1
  118. package/dist/list-item.js +1 -1
  119. package/dist/loading-spinner.js +1 -1
  120. package/dist/nav-stack.d.ts +1 -1
  121. package/dist/nav-stack.js +1 -1
  122. package/dist/pane.d.ts +49 -0
  123. package/dist/pane.js +4 -0
  124. package/dist/pane.js.map +1 -0
  125. package/dist/panel-header.d.ts +10 -4
  126. package/dist/panel-header.js +1 -1
  127. package/dist/resizable-region.d.ts +1 -1
  128. package/dist/resizable-region.js +1 -1
  129. package/dist/segmented-control.d.ts +6 -6
  130. package/dist/segmented-control.js +1 -1
  131. package/dist/select.d.ts +11 -5
  132. package/dist/select.js +1 -1
  133. package/dist/skeleton.d.ts +1 -1
  134. package/dist/skeleton.js +1 -1
  135. package/dist/split-view.d.ts +1 -1
  136. package/dist/split-view.js +70 -10
  137. package/dist/split-view.js.map +1 -1
  138. package/dist/state-banner.d.ts +4 -3
  139. package/dist/state-banner.js +1 -1
  140. package/dist/styles/catalog.css +32 -6
  141. package/dist/styles/layout.css +2 -20
  142. package/dist/styles/pane.css +62 -0
  143. package/dist/styles/segmented-control.css +3 -7
  144. package/dist/styles/sunken-panel.css +18 -0
  145. package/dist/sunken-panel.d.ts +16 -0
  146. package/dist/sunken-panel.js +3 -0
  147. package/dist/sunken-panel.js.map +1 -0
  148. package/dist/tab-bar.d.ts +4 -3
  149. package/dist/tab-bar.js +1 -1
  150. package/dist/tab-scaffold.d.ts +6 -6
  151. package/dist/tab-scaffold.js +43 -8
  152. package/dist/tab-scaffold.js.map +1 -1
  153. package/dist/token-search-field.d.ts +25 -9
  154. package/dist/token-search-field.js +1 -1
  155. package/dist/toolbar-control-group.d.ts +10 -6
  156. package/dist/toolbar-control-group.js +1 -1
  157. package/dist/toolbar-text.d.ts +10 -11
  158. package/dist/toolbar-text.js +1 -1
  159. package/dist/toolbar.d.ts +1 -1
  160. package/dist/toolbar.js +1 -1
  161. package/dist/value-table.d.ts +2 -2
  162. package/dist/value-table.js +1 -1
  163. package/dist/wire-catalog.d.ts +31 -2
  164. package/dist/wire-catalog.js +203 -8
  165. package/dist/wire-catalog.js.map +1 -1
  166. package/dist/wire-nav-stack.js +22 -7
  167. package/dist/wire-nav-stack.js.map +1 -1
  168. package/dist/wire-resizable-regions.d.ts +1 -1
  169. package/dist/wire-resizable-regions.js +1 -1
  170. package/dist/wire-sidebar.js +52 -41
  171. package/dist/wire-sidebar.js.map +1 -1
  172. package/dist/wire-tab-bars.d.ts +5 -2
  173. package/dist/wire-tab-bars.js +1 -1
  174. package/dist/wire-tab-scaffold.js +9 -4
  175. package/dist/wire-tab-scaffold.js.map +1 -1
  176. package/dist/wire-token-search-fields.d.ts +12 -7
  177. package/dist/wire-token-search-fields.js +1 -1
  178. package/dist/workbench.d.ts +1 -1
  179. package/dist/workbench.js +56 -9
  180. package/dist/workbench.js.map +1 -1
  181. package/docs/app-layouts.md +7 -7
  182. package/docs/catalog.md +249 -46
  183. package/docs/collapsible-panel.md +38 -11
  184. package/docs/component-contract.md +132 -7
  185. package/docs/component-selection.md +79 -67
  186. package/docs/design/templates.md +1 -1
  187. package/docs/design-philosophy.md +7 -9
  188. package/docs/device-class.md +8 -8
  189. package/docs/examples/application-ui-profile.json +60 -0
  190. package/docs/examples/command-palette-adapter.tsx +67 -17
  191. package/docs/examples/component-catalog-extension-v2.json +81 -0
  192. package/docs/examples/component-catalog-extension.json +45 -0
  193. package/docs/layout.md +51 -32
  194. package/docs/nav-stack.md +15 -6
  195. package/docs/recipes.md +4 -4
  196. package/docs/split-view.md +3 -3
  197. package/docs/sunken-panel.md +43 -0
  198. package/docs/tab-scaffold.md +16 -7
  199. package/docs/type-contracts.md +99 -0
  200. package/docs/ui-analyzer.md +81 -0
  201. package/docs/ui-doctor.md +77 -0
  202. package/docs/ui-evaluator.md +122 -0
  203. package/docs/webawesome-theme.md +8 -8
  204. package/docs/workbench.md +18 -5
  205. package/doctor/cli.mjs +115 -0
  206. package/doctor/config.schema.json +68 -0
  207. package/doctor/index.d.mts +116 -0
  208. package/doctor/index.mjs +1256 -0
  209. package/doctor/report.schema.json +118 -0
  210. package/evaluator/cli.mjs +89 -0
  211. package/evaluator/index.d.mts +90 -0
  212. package/evaluator/index.mjs +1138 -0
  213. package/evaluator/report.schema.json +152 -0
  214. package/llms.txt +58 -15
  215. package/package.json +70 -10
  216. package/ux-demo/recipes/app-shell.tsx +206 -10
  217. package/ux-demo/recipes/collapsible-sidebar.tsx +167 -44
  218. package/ux-demo/recipes/compact-toolbar.tsx +114 -12
  219. package/ux-demo/recipes/composer-form.tsx +106 -18
  220. package/ux-demo/recipes/list-detail-dialog.tsx +144 -8
  221. package/ux-demo/recipes/list-workspace-states.tsx +165 -8
  222. package/ux-demo/recipes/loaders.ts +5 -2
  223. package/ux-demo/recipes/loading-inspector.tsx +124 -41
  224. package/ux-demo/recipes/mount-recipe.ts +27 -6
  225. package/ux-demo/recipes/navigation-sidebar.tsx +120 -9
  226. package/ux-demo/recipes/navigation-stack.tsx +61 -19
  227. package/ux-demo/recipes/types.ts +3 -1
  228. package/ux-demo/recipes/workspace-header.tsx +57 -2
  229. package/dist/chunk-2Z5TWHKQ.js +0 -34
  230. package/dist/chunk-2Z5TWHKQ.js.map +0 -1
  231. package/dist/chunk-37T3VNIZ.js +0 -19
  232. package/dist/chunk-37T3VNIZ.js.map +0 -1
  233. package/dist/chunk-55DATV3A.js +0 -10
  234. package/dist/chunk-55DATV3A.js.map +0 -1
  235. package/dist/chunk-5ATCDSQS.js +0 -42
  236. package/dist/chunk-5ATCDSQS.js.map +0 -1
  237. package/dist/chunk-5E2HVJ33.js +0 -10
  238. package/dist/chunk-5E2HVJ33.js.map +0 -1
  239. package/dist/chunk-6NLRBSVX.js.map +0 -1
  240. package/dist/chunk-7BR3DO2A.js.map +0 -1
  241. package/dist/chunk-7JB7VPRI.js +0 -34
  242. package/dist/chunk-7JB7VPRI.js.map +0 -1
  243. package/dist/chunk-7LDCTU7D.js +0 -134
  244. package/dist/chunk-7LDCTU7D.js.map +0 -1
  245. package/dist/chunk-AHQI52QO.js.map +0 -1
  246. package/dist/chunk-AQNKJRFH.js +0 -79
  247. package/dist/chunk-AQNKJRFH.js.map +0 -1
  248. package/dist/chunk-AVZHJN6C.js +0 -14
  249. package/dist/chunk-AVZHJN6C.js.map +0 -1
  250. package/dist/chunk-B24C4A6T.js +0 -22
  251. package/dist/chunk-B24C4A6T.js.map +0 -1
  252. package/dist/chunk-CH4SQ6H5.js +0 -39
  253. package/dist/chunk-CH4SQ6H5.js.map +0 -1
  254. package/dist/chunk-DAFFDO33.js +0 -14
  255. package/dist/chunk-DAFFDO33.js.map +0 -1
  256. package/dist/chunk-I7INRJO4.js +0 -17
  257. package/dist/chunk-I7INRJO4.js.map +0 -1
  258. package/dist/chunk-L4OKFDJY.js +0 -24
  259. package/dist/chunk-L4OKFDJY.js.map +0 -1
  260. package/dist/chunk-M5JRI6MN.js +0 -27
  261. package/dist/chunk-M5JRI6MN.js.map +0 -1
  262. package/dist/chunk-RNPGFQ33.js +0 -10
  263. package/dist/chunk-RNPGFQ33.js.map +0 -1
  264. package/dist/chunk-VPCTCUED.js +0 -10
  265. package/dist/chunk-VPCTCUED.js.map +0 -1
  266. package/dist/chunk-WRTAQ7BZ.js +0 -23
  267. package/dist/chunk-WRTAQ7BZ.js.map +0 -1
  268. package/dist/chunk-WVPYVDXY.js +0 -15
  269. package/dist/chunk-WVPYVDXY.js.map +0 -1
  270. package/dist/chunk-WXMGNX2Y.js.map +0 -1
  271. package/dist/chunk-XXMOARTH.js.map +0 -1
  272. package/dist/chunk-YGN7OMLT.js.map +0 -1
  273. package/dist/chunk-ZQQ6P4SV.js +0 -20
  274. package/dist/chunk-ZQQ6P4SV.js.map +0 -1
package/README.md CHANGED
@@ -4,6 +4,13 @@ Accessible, composable UI primitives for [kerf](https://github.com/brianwestphal
4
4
 
5
5
  Start interface work with the [need-first component selection matrix](./docs/component-selection.md). It distinguishes direct reuse, composition, thin application adapters, and genuinely custom semantics, with imports, required wiring, application ownership, alternatives, and recipes for every public primitive.
6
6
 
7
+ When authoring a component gallery, follow the single
8
+ [Catalog demo authoring contract](./docs/catalog.md#catalog-demo-authoring-contract)
9
+ for focused-versus-composition modes, helper nesting, specimen selection,
10
+ geometry inspection, and metadata ownership. AI tools can discover that
11
+ contract and its public imports through the shipped
12
+ [`catalog-authoring.json`](./ai/catalog-authoring.json) artifact.
13
+
7
14
  For connective application patterns, use the seven [production composition
8
15
  recipes](./docs/recipes.md). Each has a stable catalog route, runnable state,
9
16
  public-subpath source, semantic layout ownership, and explicit application
@@ -23,56 +30,71 @@ npm install kerfjs @kerfjs/ui
23
30
  ```
24
31
 
25
32
  ```tsx
26
- import { ListItem } from '@kerfjs/ui/list-item';
27
- import { ListHeader } from '@kerfjs/ui/list-header';
28
- import { ListActionRow } from '@kerfjs/ui/list-action-row';
29
- import { Toolbar } from '@kerfjs/ui/toolbar';
30
- import { ToolbarControlGroup } from '@kerfjs/ui/toolbar-control-group';
31
- import { ToolbarText } from '@kerfjs/ui/toolbar-text';
32
-
33
- mount(root, () => <>
34
- <Toolbar label="Document" leading={<ToolbarControlGroup appearance="borderless" single><ToolbarText text="Notes" /></ToolbarControlGroup>} />
35
- <section>
36
- <ListHeader
37
- label="Workspace"
38
- action="show-workspace-actions"
39
- actionLabel="Workspace actions"
40
- rootAttributes={{ 'data-section-id': 'workspace' }}
41
- triggerAttributes={{
42
- popoverTarget: 'workspace-actions',
43
- popoverTargetAction: 'toggle',
44
- 'aria-controls': 'workspace-actions',
45
- 'aria-haspopup': 'dialog',
46
- }}
47
- />
48
- <ListItem
49
- action="open-notes"
50
- label="Notes"
51
- selected
52
- rootAttributes={{ 'data-command-color': 'blue', 'data-drop-status': 'ready' }}
53
- />
54
- <ListActionRow
55
- action="open-file"
56
- itemId="src/main.ts"
57
- label="src/main.ts"
58
- trailingAction="open-file-actions"
59
- trailingActionLabel="Actions for src/main.ts"
60
- trailingActionIcon={moreIcon}
33
+ import { ListItem } from "@kerfjs/ui/list-item";
34
+ import { ListHeader } from "@kerfjs/ui/list-header";
35
+ import { ListActionRow } from "@kerfjs/ui/list-action-row";
36
+ import { Toolbar } from "@kerfjs/ui/toolbar";
37
+ import { ToolbarControlGroup } from "@kerfjs/ui/toolbar-control-group";
38
+ import { ToolbarText } from "@kerfjs/ui/toolbar-text";
39
+
40
+ mount(root, () => (
41
+ <>
42
+ <Toolbar
43
+ label="Document"
44
+ leading={
45
+ <ToolbarControlGroup appearance="borderless" single>
46
+ <ToolbarText text="Notes" />
47
+ </ToolbarControlGroup>
48
+ }
61
49
  />
62
- <div id="workspace-actions" popover="auto">Application-owned actions</div>
63
- </section>
64
- </>);
50
+ <section>
51
+ <ListHeader
52
+ label="Workspace"
53
+ action="show-workspace-actions"
54
+ actionLabel="Workspace actions"
55
+ rootAttributes={{ "data-section-id": "workspace" }}
56
+ triggerAttributes={{
57
+ popoverTarget: "workspace-actions",
58
+ popoverTargetAction: "toggle",
59
+ "aria-controls": "workspace-actions",
60
+ "aria-haspopup": "dialog",
61
+ }}
62
+ />
63
+ <ListItem
64
+ action="open-notes"
65
+ label="Notes"
66
+ selected
67
+ rootAttributes={{
68
+ "data-command-color": "blue",
69
+ "data-drop-status": "ready",
70
+ }}
71
+ />
72
+ <ListActionRow
73
+ action="open-file"
74
+ itemId="src/main.ts"
75
+ label="src/main.ts"
76
+ trailingAction="open-file-actions"
77
+ trailingActionLabel="Actions for src/main.ts"
78
+ trailingActionIcon={moreIcon}
79
+ />
80
+ <div id="workspace-actions" popover="auto">
81
+ Application-owned actions
82
+ </div>
83
+ </section>
84
+ </>
85
+ ));
65
86
  ```
66
87
 
67
88
  Components return Kerf `SafeHtml`. They do not own application state or attach transient listeners. Actions are stable `data-action` hooks; the application wires them once with `delegate()` or `delegateActions()` and retains the disposer.
68
89
 
69
90
  `ListItem.rootAttributes`, `ListHeader.rootAttributes`,
70
- `ListActionRow.rootAttributes`, and `AppTab.rootAttributes` carry typed
91
+ `ListActionRow.rootAttributes`, `AppTab.rootAttributes`,
92
+ `CatalogExample.rootAttributes`, and `CatalogExampleStack.rootAttributes` carry typed
71
93
  application `data-*` metadata without
72
94
  teaching the package domain fields. `ListHeader.triggerAttributes` and
73
95
  `ListActionRow.trailingActionAttributes` additionally support native popover
74
96
  target and relationship attributes. Roles and component-owned action, selection,
75
- disclosure, naming, disabled, and icon semantics remain protected props; an
97
+ disclosure, naming, disabled, icon, and catalog-structure semantics remain protected props; an
76
98
  isolated `role="menuitem"` is not an extension shortcut.
77
99
  The slots are also filtered at runtime, so structurally widened objects and
78
100
  JavaScript callers cannot bypass those protections with case-variant names.
@@ -92,35 +114,37 @@ as a `New` marker.
92
114
 
93
115
  ## Component subpaths
94
116
 
95
- | Component | Browser import (includes reachable CSS) | Manual CSS export |
96
- | --- | --- | --- |
97
- | `LucideIcon` | `@kerfjs/ui/lucide-icon` | `@kerfjs/ui/lucide-icon.css` |
98
- | `DisclosureArrow` | `@kerfjs/ui/disclosure-arrow` | `@kerfjs/ui/disclosure-arrow.css` |
99
- | `Toolbar` | `@kerfjs/ui/toolbar` | `@kerfjs/ui/toolbar.css` |
100
- | `ToolbarControlGroup` | `@kerfjs/ui/toolbar-control-group` | `@kerfjs/ui/toolbar-control-group.css` |
101
- | `FloatingToolbar` | `@kerfjs/ui/floating-toolbar` | `@kerfjs/ui/floating-toolbar.css` |
102
- | `ToolbarText` | `@kerfjs/ui/toolbar-text` | `@kerfjs/ui/toolbar-text.css` |
103
- | `ListActionRow` | `@kerfjs/ui/list-action-row` | `@kerfjs/ui/list-action-row.css` |
104
- | `ListItem` | `@kerfjs/ui/list-item` | `@kerfjs/ui/list-item.css` |
105
- | `ListHeader` | `@kerfjs/ui/list-header` | `@kerfjs/ui/list-header.css` |
106
- | `ListInsetControl` | `@kerfjs/ui/list-inset-control` | `@kerfjs/ui/list-inset-control.css` |
107
- | `ListInsetText` | `@kerfjs/ui/list-inset-text` | `@kerfjs/ui/list-inset-text.css` |
108
- | Pane, content, and navigation composition | | `@kerfjs/ui/layout.css` |
109
- | `ResizableRegion` | `@kerfjs/ui/resizable-region` | `@kerfjs/ui/resizable-region.css` |
110
- | `wireResizableRegions` | `@kerfjs/ui/wire-resizable-regions` | |
111
- | `AppTab` | `@kerfjs/ui/app-tab` | `@kerfjs/ui/app-tab.css` |
112
- | `TabBar` | `@kerfjs/ui/tab-bar` | `@kerfjs/ui/tab-bar.css` |
113
- | `wireTabBars`, `reorderTabs` | `@kerfjs/ui/wire-tab-bars` | |
114
- | `LoadingSpinner` | `@kerfjs/ui/loading-spinner` | `@kerfjs/ui/loading-spinner.css` |
115
- | `Skeleton` | `@kerfjs/ui/skeleton` | `@kerfjs/ui/skeleton.css` |
116
- | `Select` | `@kerfjs/ui/select` | `@kerfjs/ui/select.css` |
117
- | `SegmentedControl` | `@kerfjs/ui/segmented-control` | `@kerfjs/ui/segmented-control.css` |
118
- | `TokenSearchField`, `readTokenSearchField`, `placeTokenSearchCaret` | `@kerfjs/ui/token-search-field` | `@kerfjs/ui/token-search-field.css` |
119
- | `wireTokenSearchFields` | `@kerfjs/ui/wire-token-search-fields` | |
120
- | `StateBanner` | `@kerfjs/ui/state-banner` | `@kerfjs/ui/state-banner.css` |
121
- | `EmptyState` | `@kerfjs/ui/empty-state` | `@kerfjs/ui/empty-state.css` |
122
- | `PanelHeader` | `@kerfjs/ui/panel-header` | `@kerfjs/ui/panel-header.css` |
123
- | `ValueTable`, `ValueTableRow` | `@kerfjs/ui/value-table` | `@kerfjs/ui/value-table.css` |
117
+ | Component | Browser import (includes reachable CSS) | Manual CSS export |
118
+ | ------------------------------------------------------------------- | --------------------------------------- | -------------------------------------- |
119
+ | `LucideIcon` | `@kerfjs/ui/lucide-icon` | `@kerfjs/ui/lucide-icon.css` |
120
+ | `DisclosureArrow` | `@kerfjs/ui/disclosure-arrow` | `@kerfjs/ui/disclosure-arrow.css` |
121
+ | `Toolbar` | `@kerfjs/ui/toolbar` | `@kerfjs/ui/toolbar.css` |
122
+ | `ToolbarControlGroup` | `@kerfjs/ui/toolbar-control-group` | `@kerfjs/ui/toolbar-control-group.css` |
123
+ | `FloatingToolbar` | `@kerfjs/ui/floating-toolbar` | `@kerfjs/ui/floating-toolbar.css` |
124
+ | `ToolbarText` | `@kerfjs/ui/toolbar-text` | `@kerfjs/ui/toolbar-text.css` |
125
+ | `ListActionRow` | `@kerfjs/ui/list-action-row` | `@kerfjs/ui/list-action-row.css` |
126
+ | `ListItem` | `@kerfjs/ui/list-item` | `@kerfjs/ui/list-item.css` |
127
+ | `ListHeader` | `@kerfjs/ui/list-header` | `@kerfjs/ui/list-header.css` |
128
+ | `ListInsetControl` | `@kerfjs/ui/list-inset-control` | `@kerfjs/ui/list-inset-control.css` |
129
+ | `ListInsetText` | `@kerfjs/ui/list-inset-text` | `@kerfjs/ui/list-inset-text.css` |
130
+ | `Pane` | `@kerfjs/ui/pane` | `@kerfjs/ui/pane.css` |
131
+ | Content and navigation composition | — | `@kerfjs/ui/layout.css` |
132
+ | `ResizableRegion` | `@kerfjs/ui/resizable-region` | `@kerfjs/ui/resizable-region.css` |
133
+ | `wireResizableRegions` | `@kerfjs/ui/wire-resizable-regions` | |
134
+ | `AppTab` | `@kerfjs/ui/app-tab` | `@kerfjs/ui/app-tab.css` |
135
+ | `TabBar` | `@kerfjs/ui/tab-bar` | `@kerfjs/ui/tab-bar.css` |
136
+ | `wireTabBars`, `reorderTabs` | `@kerfjs/ui/wire-tab-bars` | |
137
+ | `LoadingSpinner` | `@kerfjs/ui/loading-spinner` | `@kerfjs/ui/loading-spinner.css` |
138
+ | `Skeleton` | `@kerfjs/ui/skeleton` | `@kerfjs/ui/skeleton.css` |
139
+ | `SunkenPanel` | `@kerfjs/ui/sunken-panel` | `@kerfjs/ui/sunken-panel.css` |
140
+ | `Select` | `@kerfjs/ui/select` | `@kerfjs/ui/select.css` |
141
+ | `SegmentedControl` | `@kerfjs/ui/segmented-control` | `@kerfjs/ui/segmented-control.css` |
142
+ | `TokenSearchField`, `readTokenSearchField`, `placeTokenSearchCaret` | `@kerfjs/ui/token-search-field` | `@kerfjs/ui/token-search-field.css` |
143
+ | `wireTokenSearchFields` | `@kerfjs/ui/wire-token-search-fields` | |
144
+ | `StateBanner` | `@kerfjs/ui/state-banner` | `@kerfjs/ui/state-banner.css` |
145
+ | `EmptyState` | `@kerfjs/ui/empty-state` | `@kerfjs/ui/empty-state.css` |
146
+ | `PanelHeader` | `@kerfjs/ui/panel-header` | `@kerfjs/ui/panel-header.css` |
147
+ | `ValueTable`, `ValueTableRow` | `@kerfjs/ui/value-table` | `@kerfjs/ui/value-table.css` |
124
148
 
125
149
  `PanelHeader` is a plain `Toolbar` used as a panel, dialog, or page heading: an
126
150
  optional icon control group (given a brand fill with a matching border), the
@@ -156,7 +180,122 @@ delivery and side effects, companion wiring, application-owned policy,
156
180
  variants, accessibility obligations, public CSS hooks, routes, and current
157
181
  documentation/recipe links. The adjacent
158
182
  [`component-catalog.schema.json`](./ai/component-catalog.schema.json) describes
159
- the versioned format.
183
+ the versioned format. Every visual entry also declares who owns its margin,
184
+ border, and padding, so a generator can fit it into Kerf's alignment model
185
+ without guessing from a screenshot or private CSS.
186
+
187
+ Catalog demo authoring is deliberately separate from the entry inventory. Load
188
+ [`catalog-authoring.json`](./ai/catalog-authoring.json) to discover the
189
+ authoritative [Catalog demo authoring contract](./docs/catalog.md#catalog-demo-authoring-contract),
190
+ the exact API-signature context, public imports/helpers, and sanctioned metadata
191
+ slot. Keeping this as a companion artifact prevents per-entry selection facts
192
+ from duplicating presentation rules.
193
+
194
+ Tools that evaluate composition may additionally load
195
+ [`component-catalog-v2.json`](./ai/component-catalog-v2.json). It is a
196
+ deterministic, package-qualified projection of every v1 entry with formal
197
+ parent/context, zone/cardinality, child, state ownership, wiring, responsive,
198
+ layout, accessibility, public-boundary, and stable-diagnostic fields. V1
199
+ remains the selection and delivery compatibility surface. V2 defaults are
200
+ deliberately permissive; only documented objective rules receive an
201
+ authoritative override and enforceable diagnostic. The adjacent schema and
202
+ [`component-catalog-v2.d.ts`](./ai/component-catalog-v2.d.ts) types describe
203
+ the same contract.
204
+
205
+ Applications and downstream design systems should publish the same facts for
206
+ their own components. Start from the reusable
207
+ [`component-catalog-extension.schema.json`](./ai/component-catalog-extension.schema.json)
208
+ and the checked
209
+ [`component-catalog-extension.json`](./docs/examples/component-catalog-extension.json)
210
+ example. Give each app-owned component or composition a stable id, selection
211
+ guidance, public hooks, and explicit geometry ownership; then concatenate its
212
+ `entries` with Kerf's shipped `entries` in the AI context. Keep package/source
213
+ identity alongside each input when ids could collide. This makes a combined
214
+ tool reason about both sides of a composition using one vocabulary without
215
+ pretending app-local components are `@kerfjs/ui` exports.
216
+
217
+ Composition-aware consumers use
218
+ [`component-catalog-extension-v2.schema.json`](./ai/component-catalog-extension-v2.schema.json),
219
+ its shipped TypeScript types, and the checked
220
+ [`component-catalog-extension-v2.json`](./docs/examples/component-catalog-extension-v2.json)
221
+ example. Preserve each catalog's package and qualify every identity and
222
+ cross-catalog reference as `package:id`; never merge entries by bare id.
223
+
224
+ [`compile-time-contracts-v1.json`](./ai/compile-time-contracts-v1.json) is the
225
+ matching declaration contract: stable `KUI-T###` ids identify the invalid prop,
226
+ state, identity, accessibility, and protected-attribute combinations TypeScript
227
+ rejects. The package gate compiles one positive/negative consumer fixture against
228
+ both source and declarations extracted from the real packed tarball. The
229
+ [compile-time contract guide](./docs/type-contracts.md) documents migrations and
230
+ the dynamic DOM/children relationships that remain runtime or catalog checks.
231
+ Packages scaffolded by `create-kerf-component` maintain this v2 input from
232
+ `kerf.components.json`: `npm run catalog:generate` emits the catalog and
233
+ `npm run catalog:check` verifies source files, named public exports, explicit
234
+ author decisions, and byte-for-byte drift. Tools index the generated consumer
235
+ entries and this catalog by full key, reject duplicate full keys, search the
236
+ consumer package first, and retain package identity across every reference.
237
+ They must not infer missing semantics or geometry from rendered appearance.
238
+
239
+ ### Application UI profile
240
+
241
+ Applications can check in `.kerf-ui-profile.json` so tools do not have to infer
242
+ project-wide UI policy. Start from the shipped
243
+ [`application-ui-profile.defaults.json`](./ai/application-ui-profile.defaults.json)
244
+ and the checked
245
+ [`application-ui-profile.json`](./docs/examples/application-ui-profile.json)
246
+ workspace example. The versioned
247
+ [`application-ui-profile.schema.json`](./ai/application-ui-profile.schema.json)
248
+ and [`application-ui-profile.d.ts`](./ai/application-ui-profile.d.ts) cover
249
+ catalog locations, concept preferences, allowed theme/density choices, semantic
250
+ token overrides, layout/responsive conventions, and narrow rule exceptions.
251
+ Profiles contain policy only—never product records, user data, or broad styling
252
+ waivers.
253
+
254
+ Catalog declarations always provide a v2 `composition` location. Consumer
255
+ packages generated with composition-only metadata omit `selection`;
256
+ `@kerfjs/ui` continues to require its v1 selection catalog.
257
+
258
+ Node-based AI and static-analysis tools may import the shipped discovery API
259
+ from `@kerfjs/ui/ai/application-ui-profile.mjs`. It discovers package defaults,
260
+ then the workspace profile, then directory profiles from parent to child;
261
+ `mergeApplicationUiProfiles()` applies later scalar/map values, replaces a
262
+ catalog by package and an exception by id, and preserves source provenance.
263
+ `loadApplicationUiProfile()` resolves catalogs and returns diagnostics with the
264
+ originating file plus JSON path. Unknown/stale components, tokens, rules, and
265
+ catalog locations are errors. Every layer is checked against its then-effective
266
+ catalogs, including parent references and catalog paths later overridden by a
267
+ child profile. Synchronous integrations can require the shipped
268
+ `application-ui-profile-sync.cjs` projection and call
269
+ `loadApplicationUiProfileSync()` with already-discovered layers. Consumers that define additional stable
270
+ diagnostics pass their ids through the additive `knownRules` option; those ids
271
+ are merged with catalog diagnostics before exception validation.
272
+
273
+ ### Static CSS and layout ownership analysis
274
+
275
+ Run `kerf-ui-analyze --root . src` (or import
276
+ `@kerfjs/ui/analyzer`) to evaluate cross-file integration facts against the
277
+ composition catalogs and application profile. It catches provable private
278
+ selector reach-through, unknown tokens, competing geometry owners, and nested
279
+ scroll owners; it reports forced dimensions, repeated insets, off-scale literal
280
+ spacing, and dynamic classes separately as review findings. Text, versioned JSON,
281
+ and SARIF outputs carry stable `KUI-L###` ids, repository-relative locations,
282
+ evidence, and ownership chains. See the [analyzer guide](./docs/ui-analyzer.md).
283
+
284
+ ### Browser-backed integration evaluation
285
+
286
+ Run `kerf-ui-evaluate --url <running-app>` (or import
287
+ `@kerfjs/ui/evaluator`) after the static analyzer. Its Playwright-backed
288
+ wide/intermediate/narrow/200%-zoom, light/dark, and reduced-motion matrix checks
289
+ rendered overflow, clipping, reachability, focus/keyboard behavior, accessible
290
+ names, contrast, hit targets, scrolling, alignment, and cataloged runtime
291
+ geometry. The versioned report carries stable `KUI-B###` diagnostics, focused
292
+ DOM/computed-style evidence, hashed screenshot artifacts, explicit timeout and
293
+ retention policy, and a separate unscored human-visual rubric. See the
294
+ [browser evaluator guide](./docs/ui-evaluator.md).
295
+
296
+ ### Unified repair-loop doctor
297
+
298
+ Use `kerf-ui-doctor` for the supported application repair loop across profile/catalog validation, TypeScript, the Kerf UI ESLint preset, static layout analysis, and an optional explicitly authorized browser evaluation. It emits one portable versioned JSON report with deterministic exit codes, exact suppressions, monorepo package selection, changed/full modes, caching, and local-path redaction. See the [UI doctor guide](./docs/ui-doctor.md).
160
299
 
161
300
  For code generation, pair catalog selection guidance with the checked-in
162
301
  [`public-api-signatures-v1.md`](./ai/public-api-signatures-v1.md) declaration
@@ -240,10 +379,10 @@ Apps using Web Awesome's free components can opt into the same visual universe
240
379
  with one CSS import:
241
380
 
242
381
  ```ts
243
- import type {} from '@kerfjs/ui/webawesome';
244
- import '@kerfjs/ui/webawesome.css';
245
- import '@awesome.me/webawesome/dist/components/button/button.js';
246
- import '@awesome.me/webawesome/dist/components/input/input.js';
382
+ import type {} from "@kerfjs/ui/webawesome";
383
+ import "@kerfjs/ui/webawesome.css";
384
+ import "@awesome.me/webawesome/dist/components/button/button.js";
385
+ import "@awesome.me/webawesome/dist/components/input/input.js";
247
386
  ```
248
387
 
249
388
  The type-only `@kerfjs/ui/webawesome` import adds Kerf JSX intrinsic-element
@@ -269,7 +408,7 @@ classes for explicit appearance boundaries:
269
408
  ```css
270
409
  :root {
271
410
  --wa-color-brand-fill-loud: #7540a8;
272
- --wa-form-control-border-radius: .5rem;
411
+ --wa-form-control-border-radius: 0.5rem;
273
412
  }
274
413
  ```
275
414
 
@@ -309,8 +448,8 @@ standalone `filled`/`outlined` appearance with `shape="rounded"` or
309
448
  appearance="toolbar"
310
449
  shape="pill"
311
450
  choices={[
312
- { value: 'list', label: 'List' },
313
- { value: 'columns', label: 'Columns' },
451
+ { value: "list", label: "List" },
452
+ { value: "columns", label: "Columns" },
314
453
  ]}
315
454
  />
316
455
  ```
@@ -364,8 +503,8 @@ close button retains all close interaction.
364
503
  `Select` uses Web Awesome but does not register anything by itself. Install the optional peer, import the shared theme if desired, and explicitly import the registration entry in the application:
365
504
 
366
505
  ```ts
367
- import '@kerfjs/ui/webawesome.css';
368
- import '@kerfjs/ui/select/register';
506
+ import "@kerfjs/ui/webawesome.css";
507
+ import "@kerfjs/ui/select/register";
369
508
  ```
370
509
 
371
510
  That boundary keeps Web Awesome and its custom-element side effects out of bundles that use unrelated components. Automated consumer-bundle tests enforce it.
@@ -400,8 +539,9 @@ than default patterns. The detailed rationale lives in the theme contract.
400
539
 
401
540
  Run `npm run dev` from this directory for the category-grouped master/detail catalog. Every public visual component has a focused route; all 70 free Web Awesome 3.12 components have focused routes under the collapsible ecosystem section. Every detail visibly links its first-party demo source and existing guidance while showing the repository-relative paths; first-party components also link their implementation source, and Web Awesome entries label local guidance as Kerf integration guidance. One grouped `Related components` selector contains derived `Uses` / `Used by` navigation across both sets. Run `npm run check` for static/unit/bundle gates and `npm run test:e2e` for the real-browser suite.
402
541
 
403
- Run `npm run format:css` after editing styles. The normal `npm run check` gate
404
- uses Prettier to reject unformatted CSS in `src/` and `ux-demo/`.
542
+ Run `npm run format` after editing source or structured content. The narrower
543
+ `npm run format:css` command remains available for style-only work. The normal
544
+ `npm run lint` and `npm run check` gates use Prettier to reject formatting drift.
405
545
 
406
546
  For dimensions that should scale with the root font size, author pixels with
407
547
  `remify()`: `gap: remify(17px)` builds to `gap: 1.0625rem` using a fixed 16px
@@ -0,0 +1,92 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "ids": [
4
+ "KUI-B001",
5
+ "KUI-B010",
6
+ "KUI-B011",
7
+ "KUI-B012",
8
+ "KUI-B020",
9
+ "KUI-B021",
10
+ "KUI-B022",
11
+ "KUI-B023",
12
+ "KUI-B030",
13
+ "KUI-B040",
14
+ "KUI-B050",
15
+ "KUI-B060",
16
+ "KUI-B070",
17
+ "KUI-B080",
18
+ "KUI-C101",
19
+ "KUI-C102",
20
+ "KUI-C103",
21
+ "KUI-C104",
22
+ "KUI-C105",
23
+ "KUI-C106",
24
+ "KUI-C107",
25
+ "KUI-C108",
26
+ "KUI-D001",
27
+ "KUI-D002",
28
+ "KUI-D003",
29
+ "KUI-D010",
30
+ "KUI-D011",
31
+ "KUI-D020",
32
+ "KUI-L001",
33
+ "KUI-L002",
34
+ "KUI-L003",
35
+ "KUI-L004",
36
+ "KUI-L005",
37
+ "KUI-L006",
38
+ "KUI-L007",
39
+ "KUI-L008",
40
+ "KUI-L009",
41
+ "KUI-L090",
42
+ "KUI-L101",
43
+ "KUI-L102",
44
+ "KUI-L201",
45
+ "KUI-L202",
46
+ "KUI-L203",
47
+ "KUI-L301",
48
+ "KUI-L401",
49
+ "KUI-L402",
50
+ "KUI-P001",
51
+ "KUI-P002",
52
+ "KUI-P003",
53
+ "KUI-P004",
54
+ "KUI-P005",
55
+ "KUI-P006",
56
+ "KUI-P007",
57
+ "KUI-P008",
58
+ "KUI-P009",
59
+ "KUI-P010",
60
+ "KUI-P011",
61
+ "KUI-P012",
62
+ "KUI-P013",
63
+ "KUI-P014",
64
+ "KUI-P015",
65
+ "KUI-P016",
66
+ "KUI-P017",
67
+ "KUI-P018",
68
+ "KUI-P019",
69
+ "KUI-P020",
70
+ "KUI-P021",
71
+ "KUI-P022",
72
+ "KUI-P023",
73
+ "KUI-P024",
74
+ "KUI-P025",
75
+ "KUI-P026",
76
+ "KUI-P027",
77
+ "KUI-P028",
78
+ "KUI-P029",
79
+ "KUI-P030",
80
+ "KUI-T001",
81
+ "KUI-T002",
82
+ "KUI-T003",
83
+ "KUI-T004",
84
+ "KUI-T005",
85
+ "KUI-T006",
86
+ "KUI-T007",
87
+ "KUI-T008",
88
+ "KUI-T009",
89
+ "KUI-T010",
90
+ "KUI-T011"
91
+ ]
92
+ }