@kerfjs/ui 5.0.0-beta.11 → 5.0.0-beta.110

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 (1358) hide show
  1. package/README.md +707 -160
  2. package/ai/application-ui-diagnostic-ids-v1.json +115 -0
  3. package/ai/application-ui-profile-sync.cjs +548 -0
  4. package/ai/application-ui-profile.d.mts +1 -0
  5. package/ai/application-ui-profile.d.ts +106 -0
  6. package/ai/application-ui-profile.defaults.json +222 -0
  7. package/ai/application-ui-profile.mjs +653 -0
  8. package/ai/application-ui-profile.schema.json +140 -0
  9. package/ai/catalog-authoring.json +34 -0
  10. package/ai/catalog-authoring.schema.json +105 -0
  11. package/ai/compile-time-contracts-v1.json +149 -0
  12. package/ai/compile-time-contracts-v1.schema.json +52 -0
  13. package/ai/component-catalog-extension.schema.json +104 -0
  14. package/ai/component-catalog.json +9111 -1376
  15. package/ai/component-catalog.schema.json +94 -1
  16. package/ai/component-class-owners.cjs +83 -0
  17. package/ai/component-composition-extension.d.ts +7 -0
  18. package/ai/component-composition-extension.schema.json +7 -0
  19. package/ai/component-composition-rules.json +570 -0
  20. package/ai/component-composition.d.ts +143 -0
  21. package/ai/component-composition.json +10437 -0
  22. package/ai/component-composition.schema.json +444 -0
  23. package/ai/components/README.md +206 -0
  24. package/ai/components/anchored-surface.md +99 -0
  25. package/ai/components/application-tabs.md +65 -0
  26. package/ai/components/backdrop-image.md +84 -0
  27. package/ai/components/badge.md +77 -0
  28. package/ai/components/button.md +94 -0
  29. package/ai/components/checkbox-group.md +89 -0
  30. package/ai/components/checkbox.md +90 -0
  31. package/ai/components/chip.md +80 -0
  32. package/ai/components/choice-chips.md +93 -0
  33. package/ai/components/collapsible-panel.md +103 -0
  34. package/ai/components/color-field.md +92 -0
  35. package/ai/components/color-picker.md +93 -0
  36. package/ai/components/color-swatches.md +82 -0
  37. package/ai/components/column-track.md +78 -0
  38. package/ai/components/combobox.md +90 -0
  39. package/ai/components/content-item.md +101 -0
  40. package/ai/components/content-swap.md +78 -0
  41. package/ai/components/corner-status.md +88 -0
  42. package/ai/components/disclosure-arrow.md +77 -0
  43. package/ai/components/disclosure.md +88 -0
  44. package/ai/components/document-baseline.md +77 -0
  45. package/ai/components/edge-activity-indicator.md +81 -0
  46. package/ai/components/empty-state.md +80 -0
  47. package/ai/components/feedback.md +71 -0
  48. package/ai/components/file-picker.md +89 -0
  49. package/ai/components/floating-toolbar.md +82 -0
  50. package/ai/components/foundation.md +65 -0
  51. package/ai/components/framed-list.md +80 -0
  52. package/ai/components/grid.md +101 -0
  53. package/ai/components/headers.md +63 -0
  54. package/ai/components/layout.md +75 -0
  55. package/ai/components/list-action-row.md +108 -0
  56. package/ai/components/list-detail-dialog.md +90 -0
  57. package/ai/components/list-header.md +91 -0
  58. package/ai/components/list-inset-control.md +74 -0
  59. package/ai/components/list-inset-text.md +72 -0
  60. package/ai/components/list-item.md +108 -0
  61. package/ai/components/list.md +127 -0
  62. package/ai/components/loading-spinner.md +73 -0
  63. package/ai/components/lucide-icon.md +99 -0
  64. package/ai/components/message-composer.md +85 -0
  65. package/ai/components/nav-stack.md +120 -0
  66. package/ai/components/pane.md +127 -0
  67. package/ai/components/popup-menu.md +174 -0
  68. package/ai/components/progress-bar.md +82 -0
  69. package/ai/components/progress-ring.md +80 -0
  70. package/ai/components/radio-group.md +89 -0
  71. package/ai/components/recipe-app-shell.md +57 -0
  72. package/ai/components/recipe-collapsible-sidebar.md +57 -0
  73. package/ai/components/recipe-compact-toolbar.md +57 -0
  74. package/ai/components/recipe-composer-form.md +57 -0
  75. package/ai/components/recipe-list-detail-dialog.md +57 -0
  76. package/ai/components/recipe-list-workspace-states.md +57 -0
  77. package/ai/components/recipe-loading-inspector.md +57 -0
  78. package/ai/components/recipe-media-detail.md +57 -0
  79. package/ai/components/recipe-navigation-sidebar.md +57 -0
  80. package/ai/components/recipe-navigation-stack.md +57 -0
  81. package/ai/components/recipe-workspace-header.md +57 -0
  82. package/ai/components/resize.md +106 -0
  83. package/ai/components/row.md +96 -0
  84. package/ai/components/search-field.md +108 -0
  85. package/ai/components/segmented-control.md +83 -0
  86. package/ai/components/select.md +118 -0
  87. package/ai/components/skeleton.md +84 -0
  88. package/ai/components/slider.md +84 -0
  89. package/ai/components/spacer.md +86 -0
  90. package/ai/components/split-button.md +83 -0
  91. package/ai/components/split-view.md +105 -0
  92. package/ai/components/state-banner.md +96 -0
  93. package/ai/components/summary-row.md +85 -0
  94. package/ai/components/sunken-panel.md +79 -0
  95. package/ai/components/surface-scaffold.md +117 -0
  96. package/ai/components/switch.md +81 -0
  97. package/ai/components/tab-bar.md +114 -0
  98. package/ai/components/tab-navigator.md +105 -0
  99. package/ai/components/tabs.md +95 -0
  100. package/ai/components/tag-field.md +86 -0
  101. package/ai/components/text-field.md +102 -0
  102. package/ai/components/text.md +93 -0
  103. package/ai/components/toast.md +85 -0
  104. package/ai/components/toolbar-control-group.md +127 -0
  105. package/ai/components/toolbar-text.md +100 -0
  106. package/ai/components/toolbar.md +103 -0
  107. package/ai/components/tooltip.md +81 -0
  108. package/ai/components/value-table.md +80 -0
  109. package/ai/components/wa-accordion-item.md +61 -0
  110. package/ai/components/wa-accordion.md +71 -0
  111. package/ai/components/wa-animated-image.md +56 -0
  112. package/ai/components/wa-animation.md +56 -0
  113. package/ai/components/wa-avatar.md +56 -0
  114. package/ai/components/wa-badge.md +62 -0
  115. package/ai/components/wa-breadcrumb-item.md +54 -0
  116. package/ai/components/wa-breadcrumb.md +56 -0
  117. package/ai/components/wa-button-group.md +62 -0
  118. package/ai/components/wa-button.md +61 -0
  119. package/ai/components/wa-callout.md +60 -0
  120. package/ai/components/wa-card.md +67 -0
  121. package/ai/components/wa-carousel-item.md +54 -0
  122. package/ai/components/wa-carousel.md +56 -0
  123. package/ai/components/wa-checkbox-group.md +62 -0
  124. package/ai/components/wa-checkbox.md +61 -0
  125. package/ai/components/wa-color-picker.md +63 -0
  126. package/ai/components/wa-comparison.md +56 -0
  127. package/ai/components/wa-copy-button.md +56 -0
  128. package/ai/components/wa-details.md +67 -0
  129. package/ai/components/wa-dialog.md +65 -0
  130. package/ai/components/wa-divider.md +54 -0
  131. package/ai/components/wa-drawer.md +62 -0
  132. package/ai/components/wa-dropdown-item.md +62 -0
  133. package/ai/components/wa-dropdown.md +62 -0
  134. package/ai/components/wa-format-bytes.md +54 -0
  135. package/ai/components/wa-format-date.md +54 -0
  136. package/ai/components/wa-format-number.md +54 -0
  137. package/ai/components/wa-icon.md +59 -0
  138. package/ai/components/wa-include.md +55 -0
  139. package/ai/components/wa-input.md +62 -0
  140. package/ai/components/wa-intersection-observer.md +54 -0
  141. package/ai/components/wa-known-date.md +54 -0
  142. package/ai/components/wa-markdown.md +54 -0
  143. package/ai/components/wa-mutation-observer.md +54 -0
  144. package/ai/components/wa-number-input.md +56 -0
  145. package/ai/components/wa-option.md +61 -0
  146. package/ai/components/wa-otp-input.md +54 -0
  147. package/ai/components/wa-page.md +62 -0
  148. package/ai/components/wa-pagination.md +56 -0
  149. package/ai/components/wa-popover.md +61 -0
  150. package/ai/components/wa-popup.md +60 -0
  151. package/ai/components/wa-progress-bar.md +60 -0
  152. package/ai/components/wa-progress-ring.md +60 -0
  153. package/ai/components/wa-qr-code.md +54 -0
  154. package/ai/components/wa-radio-group.md +67 -0
  155. package/ai/components/wa-radio.md +61 -0
  156. package/ai/components/wa-random-content.md +54 -0
  157. package/ai/components/wa-rating.md +56 -0
  158. package/ai/components/wa-relative-time.md +54 -0
  159. package/ai/components/wa-resize-observer.md +54 -0
  160. package/ai/components/wa-scroller.md +61 -0
  161. package/ai/components/wa-select.md +65 -0
  162. package/ai/components/wa-skeleton.md +60 -0
  163. package/ai/components/wa-slider.md +61 -0
  164. package/ai/components/wa-spinner.md +60 -0
  165. package/ai/components/wa-split-panel.md +60 -0
  166. package/ai/components/wa-step.md +56 -0
  167. package/ai/components/wa-stepper.md +56 -0
  168. package/ai/components/wa-switch.md +60 -0
  169. package/ai/components/wa-tab-group.md +71 -0
  170. package/ai/components/wa-tab-panel.md +62 -0
  171. package/ai/components/wa-tab.md +61 -0
  172. package/ai/components/wa-tag-input.md +62 -0
  173. package/ai/components/wa-tag.md +62 -0
  174. package/ai/components/wa-textarea.md +60 -0
  175. package/ai/components/wa-time-input.md +56 -0
  176. package/ai/components/wa-toast-item.md +62 -0
  177. package/ai/components/wa-toast.md +62 -0
  178. package/ai/components/wa-tooltip.md +61 -0
  179. package/ai/components/wa-tree-item.md +56 -0
  180. package/ai/components/wa-tree.md +56 -0
  181. package/ai/components/wa-zoomable-frame.md +56 -0
  182. package/ai/components/workbench-dialog.md +90 -0
  183. package/ai/components/workbench.md +120 -0
  184. package/ai/public-api-signatures-v1.md +6114 -445
  185. package/ai/skill.md +545 -65
  186. package/ai/webawesome-jsx-signatures-v1.md +12 -2
  187. package/analyzer/cli.mjs +49 -0
  188. package/analyzer/component-ownership.d.mts +72 -0
  189. package/analyzer/component-ownership.mjs +429 -0
  190. package/analyzer/index.d.mts +53 -0
  191. package/analyzer/index.mjs +2375 -0
  192. package/analyzer/loud-pairs.d.mts +49 -0
  193. package/analyzer/loud-pairs.mjs +357 -0
  194. package/analyzer/report.schema.json +66 -0
  195. package/analyzer/selectors.d.mts +21 -0
  196. package/analyzer/selectors.mjs +212 -0
  197. package/catalog-projection-cli.mjs +96 -0
  198. package/catalog-projection.d.mts +55 -0
  199. package/catalog-projection.mjs +62 -0
  200. package/dist/anchored-surface.d.ts +69 -0
  201. package/dist/anchored-surface.js +3 -0
  202. package/dist/anchored-surface.js.map +1 -0
  203. package/dist/backdrop-image.d.ts +132 -0
  204. package/dist/backdrop-image.js +5 -0
  205. package/dist/backdrop-image.js.map +1 -0
  206. package/dist/badge.d.ts +91 -0
  207. package/dist/badge.js +4 -0
  208. package/dist/badge.js.map +1 -0
  209. package/dist/browser/anchored-surface.js +3 -0
  210. package/dist/browser/backdrop-image.js +3 -0
  211. package/dist/browser/badge.js +3 -0
  212. package/dist/browser/button.js +5 -0
  213. package/dist/browser/catalog.js +29 -0
  214. package/dist/browser/checkbox-group.js +5 -0
  215. package/dist/browser/checkbox.js +4 -0
  216. package/dist/browser/chip.js +3 -0
  217. package/dist/browser/choice-chips.js +3 -0
  218. package/dist/browser/collapsible-panel.js +9 -0
  219. package/dist/browser/color-field.js +4 -0
  220. package/dist/browser/color-picker.js +5 -0
  221. package/dist/browser/color-swatches.js +3 -0
  222. package/dist/browser/column-track.js +3 -0
  223. package/dist/browser/combobox.js +3 -0
  224. package/dist/browser/content-item.js +3 -0
  225. package/dist/browser/content-swap.js +3 -0
  226. package/dist/browser/corner-status.js +3 -0
  227. package/dist/browser/disclosure.js +5 -0
  228. package/dist/browser/edge-activity-indicator.js +3 -0
  229. package/dist/browser/file-picker.js +3 -0
  230. package/dist/browser/framed-list.js +3 -0
  231. package/dist/browser/grid.js +3 -0
  232. package/dist/browser/list-action-row.js +3 -0
  233. package/dist/browser/list-detail-dialog.js +14 -0
  234. package/dist/browser/list-header.js +3 -1
  235. package/dist/browser/list-inset-control.js +3 -0
  236. package/dist/browser/list-inset-text.js +3 -0
  237. package/dist/browser/list-item.js +1 -0
  238. package/dist/browser/list.js +3 -0
  239. package/dist/browser/message-composer.js +5 -0
  240. package/dist/browser/nav-stack.js +11 -0
  241. package/dist/browser/pane.js +3 -0
  242. package/dist/browser/popup-menu.js +4 -0
  243. package/dist/browser/progress-bar.js +3 -0
  244. package/dist/browser/progress-ring.js +3 -0
  245. package/dist/browser/radio-group.js +3 -0
  246. package/dist/browser/row.js +3 -0
  247. package/dist/browser/search-field.js +4 -0
  248. package/dist/browser/segmented-control.js +0 -1
  249. package/dist/browser/select.js +2 -1
  250. package/dist/browser/slider.js +3 -0
  251. package/dist/browser/spacer.js +3 -0
  252. package/dist/browser/split-button.js +5 -0
  253. package/dist/browser/split-view.js +13 -0
  254. package/dist/browser/state-banner.js +1 -0
  255. package/dist/browser/summary-row.js +3 -0
  256. package/dist/browser/sunken-panel.js +3 -0
  257. package/dist/browser/surface-scaffold.js +4 -0
  258. package/dist/browser/switch.js +3 -0
  259. package/dist/browser/tab-bar-item.js +4 -0
  260. package/dist/browser/tab-navigator.js +4 -0
  261. package/dist/browser/tag-field.js +5 -0
  262. package/dist/browser/text-field.js +4 -0
  263. package/dist/browser/text.js +3 -0
  264. package/dist/browser/toolbar-control-group.js +1 -0
  265. package/dist/browser/workbench-dialog.js +15 -0
  266. package/dist/browser/workbench.js +14 -0
  267. package/dist/button.d.ts +121 -0
  268. package/dist/button.js +7 -0
  269. package/dist/button.js.map +1 -0
  270. package/dist/catalog-resources.d.ts +50 -0
  271. package/dist/catalog-resources.js +22 -0
  272. package/dist/catalog-resources.js.map +1 -0
  273. package/dist/catalog.d.ts +134 -101
  274. package/dist/catalog.js +700 -108
  275. package/dist/catalog.js.map +1 -1
  276. package/dist/checkbox-group.d.ts +70 -0
  277. package/dist/checkbox-group.js +7 -0
  278. package/dist/checkbox-group.js.map +1 -0
  279. package/dist/checkbox.d.ts +45 -0
  280. package/dist/checkbox.js +6 -0
  281. package/dist/checkbox.js.map +1 -0
  282. package/dist/chip.d.ts +117 -0
  283. package/dist/chip.js +4 -0
  284. package/dist/chip.js.map +1 -0
  285. package/dist/choice-chips.d.ts +116 -0
  286. package/dist/choice-chips.js +3 -0
  287. package/dist/choice-chips.js.map +1 -0
  288. package/dist/chunk-2FW7D4IG.js +52 -0
  289. package/dist/chunk-2FW7D4IG.js.map +1 -0
  290. package/dist/chunk-2GOCOLQL.js +270 -0
  291. package/dist/chunk-2GOCOLQL.js.map +1 -0
  292. package/dist/chunk-2LM3PYHA.js +300 -0
  293. package/dist/chunk-2LM3PYHA.js.map +1 -0
  294. package/dist/chunk-36HVQ72F.js +123 -0
  295. package/dist/chunk-36HVQ72F.js.map +1 -0
  296. package/dist/chunk-3GLYIIFR.js +230 -0
  297. package/dist/chunk-3GLYIIFR.js.map +1 -0
  298. package/dist/chunk-3VZ6SFD4.js +8 -0
  299. package/dist/chunk-3VZ6SFD4.js.map +1 -0
  300. package/dist/chunk-3WYREXW4.js +120 -0
  301. package/dist/chunk-3WYREXW4.js.map +1 -0
  302. package/dist/chunk-3Z7N2NAZ.js +385 -0
  303. package/dist/chunk-3Z7N2NAZ.js.map +1 -0
  304. package/dist/chunk-4OV272LF.js +93 -0
  305. package/dist/chunk-4OV272LF.js.map +1 -0
  306. package/dist/chunk-4RECPEHI.js +67 -0
  307. package/dist/chunk-4RECPEHI.js.map +1 -0
  308. package/dist/chunk-4UB5Z3ZZ.js +68 -0
  309. package/dist/chunk-4UB5Z3ZZ.js.map +1 -0
  310. package/dist/chunk-5J6Z4BWY.js +141 -0
  311. package/dist/chunk-5J6Z4BWY.js.map +1 -0
  312. package/dist/chunk-5USKCWGL.js +113 -0
  313. package/dist/chunk-5USKCWGL.js.map +1 -0
  314. package/dist/chunk-6C6DLP3W.js +31 -0
  315. package/dist/chunk-6C6DLP3W.js.map +1 -0
  316. package/dist/chunk-6CDILXF4.js +204 -0
  317. package/dist/chunk-6CDILXF4.js.map +1 -0
  318. package/dist/chunk-6VVIW7VB.js +69 -0
  319. package/dist/chunk-6VVIW7VB.js.map +1 -0
  320. package/dist/chunk-7AK5I7U7.js +55 -0
  321. package/dist/chunk-7AK5I7U7.js.map +1 -0
  322. package/dist/chunk-7K6U6FCN.js +122 -0
  323. package/dist/chunk-7K6U6FCN.js.map +1 -0
  324. package/dist/chunk-AMIHGFLP.js +59 -0
  325. package/dist/chunk-AMIHGFLP.js.map +1 -0
  326. package/dist/chunk-AN5IWMTM.js +24 -0
  327. package/dist/chunk-AN5IWMTM.js.map +1 -0
  328. package/dist/chunk-ATGAJVZ6.js +268 -0
  329. package/dist/chunk-ATGAJVZ6.js.map +1 -0
  330. package/dist/chunk-AYPGXR2E.js +20 -0
  331. package/dist/chunk-AYPGXR2E.js.map +1 -0
  332. package/dist/chunk-B53PS2LE.js +34 -0
  333. package/dist/chunk-B53PS2LE.js.map +1 -0
  334. package/dist/chunk-BKUMG2KB.js +95 -0
  335. package/dist/chunk-BKUMG2KB.js.map +1 -0
  336. package/dist/chunk-C26Q6P4Q.js +76 -0
  337. package/dist/chunk-C26Q6P4Q.js.map +1 -0
  338. package/dist/chunk-CEJ5FK6G.js +288 -0
  339. package/dist/chunk-CEJ5FK6G.js.map +1 -0
  340. package/dist/chunk-CIAUILRR.js +222 -0
  341. package/dist/chunk-CIAUILRR.js.map +1 -0
  342. package/dist/chunk-CNM6ZWP2.js +38 -0
  343. package/dist/chunk-CNM6ZWP2.js.map +1 -0
  344. package/dist/chunk-CPSGUGAY.js +527 -0
  345. package/dist/chunk-CPSGUGAY.js.map +1 -0
  346. package/dist/chunk-CTQUDCY5.js +26 -0
  347. package/dist/chunk-CTQUDCY5.js.map +1 -0
  348. package/dist/chunk-CVD5IZGB.js +66 -0
  349. package/dist/chunk-CVD5IZGB.js.map +1 -0
  350. package/dist/chunk-D4MXSAMI.js +50 -0
  351. package/dist/chunk-D4MXSAMI.js.map +1 -0
  352. package/dist/chunk-D5RGM3XA.js +38 -0
  353. package/dist/chunk-D5RGM3XA.js.map +1 -0
  354. package/dist/chunk-DZJ4GBSP.js +59 -0
  355. package/dist/chunk-DZJ4GBSP.js.map +1 -0
  356. package/dist/chunk-EIET4QLK.js +51 -0
  357. package/dist/chunk-EIET4QLK.js.map +1 -0
  358. package/dist/chunk-EKHDLBRP.js +86 -0
  359. package/dist/chunk-EKHDLBRP.js.map +1 -0
  360. package/dist/chunk-EYDXFOSH.js +457 -0
  361. package/dist/chunk-EYDXFOSH.js.map +1 -0
  362. package/dist/chunk-G3J7JDP6.js +29 -0
  363. package/dist/chunk-G3J7JDP6.js.map +1 -0
  364. package/dist/chunk-GS2QD3N7.js +14 -0
  365. package/dist/chunk-GS2QD3N7.js.map +1 -0
  366. package/dist/chunk-GXSX6Q6O.js +42 -0
  367. package/dist/chunk-GXSX6Q6O.js.map +1 -0
  368. package/dist/chunk-HDXUHLTQ.js +90 -0
  369. package/dist/chunk-HDXUHLTQ.js.map +1 -0
  370. package/dist/chunk-HJXVVFBT.js +108 -0
  371. package/dist/chunk-HJXVVFBT.js.map +1 -0
  372. package/dist/chunk-HQZG3OFL.js +158 -0
  373. package/dist/chunk-HQZG3OFL.js.map +1 -0
  374. package/dist/chunk-HTERKONR.js +49 -0
  375. package/dist/chunk-HTERKONR.js.map +1 -0
  376. package/dist/chunk-HU5IHXCI.js +73 -0
  377. package/dist/chunk-HU5IHXCI.js.map +1 -0
  378. package/dist/chunk-IKS72C6P.js +53 -0
  379. package/dist/chunk-IKS72C6P.js.map +1 -0
  380. package/dist/chunk-IO27YTL3.js +73 -0
  381. package/dist/chunk-IO27YTL3.js.map +1 -0
  382. package/dist/chunk-IQSRHXZR.js +164 -0
  383. package/dist/chunk-IQSRHXZR.js.map +1 -0
  384. package/dist/chunk-ITUQC4FW.js +163 -0
  385. package/dist/chunk-ITUQC4FW.js.map +1 -0
  386. package/dist/chunk-JCCN3U6X.js +176 -0
  387. package/dist/chunk-JCCN3U6X.js.map +1 -0
  388. package/dist/chunk-K57NINLH.js +137 -0
  389. package/dist/chunk-K57NINLH.js.map +1 -0
  390. package/dist/chunk-KC6WUSNS.js +34 -0
  391. package/dist/chunk-KC6WUSNS.js.map +1 -0
  392. package/dist/chunk-KCS6NJ3O.js +82 -0
  393. package/dist/chunk-KCS6NJ3O.js.map +1 -0
  394. package/dist/chunk-KDQZ3E5C.js +75 -0
  395. package/dist/chunk-KDQZ3E5C.js.map +1 -0
  396. package/dist/chunk-KH4KEMSP.js +71 -0
  397. package/dist/chunk-KH4KEMSP.js.map +1 -0
  398. package/dist/chunk-KK3S5OTW.js +98 -0
  399. package/dist/chunk-KK3S5OTW.js.map +1 -0
  400. package/dist/chunk-KPINJHIC.js +122 -0
  401. package/dist/chunk-KPINJHIC.js.map +1 -0
  402. package/dist/chunk-LMHN2TJL.js +167 -0
  403. package/dist/chunk-LMHN2TJL.js.map +1 -0
  404. package/dist/chunk-LTBVP6VN.js +59 -0
  405. package/dist/chunk-LTBVP6VN.js.map +1 -0
  406. package/dist/{chunk-YGN7OMLT.js → chunk-LZUUUHNH.js} +13 -6
  407. package/dist/chunk-LZUUUHNH.js.map +1 -0
  408. package/dist/chunk-MHMWQ7RB.js +19 -0
  409. package/dist/chunk-MHMWQ7RB.js.map +1 -0
  410. package/dist/chunk-MJ5RU6XT.js +173 -0
  411. package/dist/chunk-MJ5RU6XT.js.map +1 -0
  412. package/dist/chunk-MVKHSAKE.js +169 -0
  413. package/dist/chunk-MVKHSAKE.js.map +1 -0
  414. package/dist/chunk-NB6POCFH.js +103 -0
  415. package/dist/chunk-NB6POCFH.js.map +1 -0
  416. package/dist/chunk-NR6O74ST.js +169 -0
  417. package/dist/chunk-NR6O74ST.js.map +1 -0
  418. package/dist/chunk-OHPYT2BH.js +82 -0
  419. package/dist/chunk-OHPYT2BH.js.map +1 -0
  420. package/dist/chunk-OQP3PFKQ.js +341 -0
  421. package/dist/chunk-OQP3PFKQ.js.map +1 -0
  422. package/dist/chunk-OZ6X76G5.js +547 -0
  423. package/dist/chunk-OZ6X76G5.js.map +1 -0
  424. package/dist/chunk-P7EJ4CAD.js +147 -0
  425. package/dist/chunk-P7EJ4CAD.js.map +1 -0
  426. package/dist/chunk-QDSZTQXL.js +28 -0
  427. package/dist/chunk-QDSZTQXL.js.map +1 -0
  428. package/dist/chunk-QH5KOFNS.js +39 -0
  429. package/dist/chunk-QH5KOFNS.js.map +1 -0
  430. package/dist/chunk-QPTJ5DOO.js +87 -0
  431. package/dist/chunk-QPTJ5DOO.js.map +1 -0
  432. package/dist/chunk-QYMJHS4K.js +36 -0
  433. package/dist/chunk-QYMJHS4K.js.map +1 -0
  434. package/dist/chunk-RMWNO6BA.js +89 -0
  435. package/dist/chunk-RMWNO6BA.js.map +1 -0
  436. package/dist/chunk-S2XULQEK.js +52 -0
  437. package/dist/chunk-S2XULQEK.js.map +1 -0
  438. package/dist/chunk-S3ECMF23.js +33 -0
  439. package/dist/chunk-S3ECMF23.js.map +1 -0
  440. package/dist/chunk-S4Y3YTAI.js +35 -0
  441. package/dist/chunk-S4Y3YTAI.js.map +1 -0
  442. package/dist/chunk-S4ZGTDSG.js +18 -0
  443. package/dist/chunk-S4ZGTDSG.js.map +1 -0
  444. package/dist/chunk-SCDWURBO.js +136 -0
  445. package/dist/chunk-SCDWURBO.js.map +1 -0
  446. package/dist/chunk-SOFPUW3O.js +196 -0
  447. package/dist/chunk-SOFPUW3O.js.map +1 -0
  448. package/dist/chunk-SQ5DH66U.js +37 -0
  449. package/dist/chunk-SQ5DH66U.js.map +1 -0
  450. package/dist/chunk-T74YB76U.js +547 -0
  451. package/dist/chunk-T74YB76U.js.map +1 -0
  452. package/dist/chunk-TI2GV36S.js +90 -0
  453. package/dist/chunk-TI2GV36S.js.map +1 -0
  454. package/dist/{chunk-56RJXPHG.js → chunk-TKNVL53O.js} +7 -4
  455. package/dist/chunk-TKNVL53O.js.map +1 -0
  456. package/dist/chunk-TNJLNLVE.js +115 -0
  457. package/dist/chunk-TNJLNLVE.js.map +1 -0
  458. package/dist/chunk-TUID42UE.js +15 -0
  459. package/dist/chunk-TUID42UE.js.map +1 -0
  460. package/dist/chunk-UMNHJSIO.js +848 -0
  461. package/dist/chunk-UMNHJSIO.js.map +1 -0
  462. package/dist/chunk-VEME3D7K.js +298 -0
  463. package/dist/chunk-VEME3D7K.js.map +1 -0
  464. package/dist/chunk-WPNIKZMJ.js +507 -0
  465. package/dist/chunk-WPNIKZMJ.js.map +1 -0
  466. package/dist/chunk-WSEJ2FDE.js +162 -0
  467. package/dist/chunk-WSEJ2FDE.js.map +1 -0
  468. package/dist/chunk-WVS6CUCT.js +48 -0
  469. package/dist/chunk-WVS6CUCT.js.map +1 -0
  470. package/dist/chunk-XWNXGFX3.js +381 -0
  471. package/dist/chunk-XWNXGFX3.js.map +1 -0
  472. package/dist/chunk-Y6KT7ZTR.js +109 -0
  473. package/dist/chunk-Y6KT7ZTR.js.map +1 -0
  474. package/dist/chunk-YMUIQRWK.js +44 -0
  475. package/dist/chunk-YMUIQRWK.js.map +1 -0
  476. package/dist/chunk-ZCDRLN3B.js +138 -0
  477. package/dist/chunk-ZCDRLN3B.js.map +1 -0
  478. package/dist/chunk-ZKKO4MHC.js +25 -0
  479. package/dist/chunk-ZKKO4MHC.js.map +1 -0
  480. package/dist/chunk-ZN7KUMPY.js +48 -0
  481. package/dist/chunk-ZN7KUMPY.js.map +1 -0
  482. package/dist/chunk-ZNROKDSZ.js +54 -0
  483. package/dist/chunk-ZNROKDSZ.js.map +1 -0
  484. package/dist/chunk-ZX2QQJXD.js +249 -0
  485. package/dist/chunk-ZX2QQJXD.js.map +1 -0
  486. package/dist/collapsible-panel.d.ts +96 -17
  487. package/dist/collapsible-panel.js +133 -14
  488. package/dist/collapsible-panel.js.map +1 -1
  489. package/dist/color-field.d.ts +51 -0
  490. package/dist/color-field.js +92 -0
  491. package/dist/color-field.js.map +1 -0
  492. package/dist/color-picker.d.ts +113 -0
  493. package/dist/color-picker.js +8 -0
  494. package/dist/color-picker.js.map +1 -0
  495. package/dist/color-swatches.d.ts +56 -0
  496. package/dist/color-swatches.js +4 -0
  497. package/dist/color-swatches.js.map +1 -0
  498. package/dist/column-track.d.ts +41 -0
  499. package/dist/column-track.js +4 -0
  500. package/dist/column-track.js.map +1 -0
  501. package/dist/combobox.d.ts +40 -0
  502. package/dist/combobox.js +3 -0
  503. package/dist/combobox.js.map +1 -0
  504. package/dist/content-item.d.ts +128 -0
  505. package/dist/content-item.js +4 -0
  506. package/dist/content-item.js.map +1 -0
  507. package/dist/content-swap.d.ts +34 -0
  508. package/dist/content-swap.js +3 -0
  509. package/dist/content-swap.js.map +1 -0
  510. package/dist/corner-status.d.ts +36 -0
  511. package/dist/corner-status.js +3 -0
  512. package/dist/corner-status.js.map +1 -0
  513. package/dist/css-values.d.ts +127 -0
  514. package/dist/css-values.js +3 -0
  515. package/dist/css-values.js.map +1 -0
  516. package/dist/device-class.js +34 -6
  517. package/dist/device-class.js.map +1 -1
  518. package/dist/disclosure-arrow.d.ts +6 -1
  519. package/dist/disclosure-arrow.js +2 -1
  520. package/dist/disclosure.d.ts +66 -0
  521. package/dist/disclosure.js +51 -0
  522. package/dist/disclosure.js.map +1 -0
  523. package/dist/edge-activity-indicator.d.ts +28 -0
  524. package/dist/edge-activity-indicator.js +3 -0
  525. package/dist/edge-activity-indicator.js.map +1 -0
  526. package/dist/empty-state.d.ts +5 -2
  527. package/dist/empty-state.js +2 -1
  528. package/dist/extension-attributes-mu8MFUl0.d.ts +13 -0
  529. package/dist/file-picker.d.ts +54 -0
  530. package/dist/file-picker.js +3 -0
  531. package/dist/file-picker.js.map +1 -0
  532. package/dist/flex-alignment-4ms8ZbV8.d.ts +5 -0
  533. package/dist/floating-toolbar.d.ts +29 -6
  534. package/dist/floating-toolbar.js +1 -1
  535. package/dist/framed-list.d.ts +47 -0
  536. package/dist/framed-list.js +4 -0
  537. package/dist/framed-list.js.map +1 -0
  538. package/dist/grid.d.ts +58 -0
  539. package/dist/grid.js +6 -0
  540. package/dist/grid.js.map +1 -0
  541. package/dist/help-tags-register.d.ts +13 -0
  542. package/dist/help-tags-register.js +10 -0
  543. package/dist/help-tags-register.js.map +1 -0
  544. package/dist/index.d.ts +72 -17
  545. package/dist/index.js +84 -25
  546. package/dist/list-action-row.d.ts +69 -12
  547. package/dist/list-action-row.js +8 -1
  548. package/dist/list-detail-dialog.d.ts +123 -0
  549. package/dist/list-detail-dialog.js +167 -0
  550. package/dist/list-detail-dialog.js.map +1 -0
  551. package/dist/list-header.d.ts +72 -10
  552. package/dist/list-header.js +4 -1
  553. package/dist/list-icon-tile-B8dr97OW.d.ts +18 -0
  554. package/dist/list-inset-control.d.ts +22 -0
  555. package/dist/list-inset-control.js +3 -0
  556. package/dist/list-inset-control.js.map +1 -0
  557. package/dist/list-inset-text.d.ts +30 -0
  558. package/dist/list-inset-text.js +4 -0
  559. package/dist/list-inset-text.js.map +1 -0
  560. package/dist/list-item.d.ts +49 -5
  561. package/dist/list-item.js +4 -1
  562. package/dist/list.d.ts +149 -0
  563. package/dist/list.js +7 -0
  564. package/dist/list.js.map +1 -0
  565. package/dist/loading-spinner.d.ts +12 -2
  566. package/dist/loading-spinner.js +2 -1
  567. package/dist/lucide-icon.d.ts +23 -3
  568. package/dist/lucide-icon.js +2 -1
  569. package/dist/message-composer.d.ts +70 -0
  570. package/dist/message-composer.js +6 -0
  571. package/dist/message-composer.js.map +1 -0
  572. package/dist/nav-stack-CU_0dKtI.d.ts +194 -0
  573. package/dist/nav-stack.d.ts +15 -38
  574. package/dist/nav-stack.js +14 -1
  575. package/dist/pane.d.ts +258 -0
  576. package/dist/pane.js +6 -0
  577. package/dist/pane.js.map +1 -0
  578. package/dist/panel-toolbar-vg6Ir5Dy.d.ts +77 -0
  579. package/dist/popup-menu-register.d.ts +11 -0
  580. package/dist/popup-menu-register.js +13 -0
  581. package/dist/popup-menu-register.js.map +1 -0
  582. package/dist/popup-menu.d.ts +153 -0
  583. package/dist/popup-menu.js +7 -0
  584. package/dist/popup-menu.js.map +1 -0
  585. package/dist/progress-bar.d.ts +52 -0
  586. package/dist/progress-bar.js +68 -0
  587. package/dist/progress-bar.js.map +1 -0
  588. package/dist/progress-ring.d.ts +44 -0
  589. package/dist/progress-ring.js +73 -0
  590. package/dist/progress-ring.js.map +1 -0
  591. package/dist/radio-group.d.ts +62 -0
  592. package/dist/radio-group.js +4 -0
  593. package/dist/radio-group.js.map +1 -0
  594. package/dist/resizable-region.d.ts +32 -3
  595. package/dist/resizable-region.js +1 -1
  596. package/dist/row.d.ts +53 -0
  597. package/dist/row.js +7 -0
  598. package/dist/row.js.map +1 -0
  599. package/dist/scroll-clearance-BikHljTc.d.ts +14 -0
  600. package/dist/search-field-CrGTN5sa.d.ts +208 -0
  601. package/dist/search-field-model.d.ts +3 -0
  602. package/dist/search-field-model.js +3 -0
  603. package/dist/search-field-model.js.map +1 -0
  604. package/dist/search-field.d.ts +3 -0
  605. package/dist/search-field.js +5 -0
  606. package/dist/search-field.js.map +1 -0
  607. package/dist/segmented-control.d.ts +14 -9
  608. package/dist/segmented-control.js +1 -2
  609. package/dist/select-register.d.ts +6 -3
  610. package/dist/select-register.js +402 -8
  611. package/dist/select-register.js.map +1 -1
  612. package/dist/select.d.ts +128 -9
  613. package/dist/select.js +6 -1
  614. package/dist/selection.d.ts +54 -0
  615. package/dist/selection.js +3 -0
  616. package/dist/selection.js.map +1 -0
  617. package/dist/semantic-content-BbzjvSu9.d.ts +14 -0
  618. package/dist/semantic-tone-CdW013KF.d.ts +4 -0
  619. package/dist/sides-BPSWde0A.d.ts +4 -0
  620. package/dist/skeleton.d.ts +14 -7
  621. package/dist/skeleton.js +2 -1
  622. package/dist/slider.d.ts +74 -0
  623. package/dist/slider.js +103 -0
  624. package/dist/slider.js.map +1 -0
  625. package/dist/spacer.d.ts +18 -0
  626. package/dist/spacer.js +4 -0
  627. package/dist/spacer.js.map +1 -0
  628. package/dist/split-button.d.ts +69 -0
  629. package/dist/split-button.js +7 -0
  630. package/dist/split-button.js.map +1 -0
  631. package/dist/split-view.d.ts +66 -6
  632. package/dist/split-view.js +14 -15
  633. package/dist/split-view.js.map +1 -1
  634. package/dist/state-banner.d.ts +41 -7
  635. package/dist/state-banner.js +4 -1
  636. package/dist/styles/anchored-surface.css +44 -0
  637. package/dist/styles/backdrop-image.css +241 -0
  638. package/dist/styles/badge.css +157 -0
  639. package/dist/styles/button.css +293 -0
  640. package/dist/styles/catalog/components/catalog-example-stack.css +14 -0
  641. package/dist/styles/catalog/components/catalog-example.css +250 -0
  642. package/dist/styles/catalog/components/catalog-stage.css +61 -0
  643. package/dist/styles/catalog/components/catalog.css +26 -0
  644. package/dist/styles/catalog.css +5 -522
  645. package/dist/styles/checkbox-group.css +63 -0
  646. package/dist/styles/checkbox.css +122 -0
  647. package/dist/styles/chip.css +234 -0
  648. package/dist/styles/choice-chips.css +205 -0
  649. package/dist/styles/collapsible-panel.css +450 -16
  650. package/dist/styles/color-field.css +125 -0
  651. package/dist/styles/color-picker.css +366 -0
  652. package/dist/styles/color-swatches.css +122 -0
  653. package/dist/styles/column-track.css +57 -0
  654. package/dist/styles/combobox.css +115 -0
  655. package/dist/styles/components/actions/button/button.css +293 -0
  656. package/dist/styles/components/actions/floating-toolbar/floating-toolbar.css +119 -0
  657. package/dist/styles/components/actions/popup-menu/popup-menu.css +498 -0
  658. package/dist/styles/components/actions/split-button/split-button.css +141 -0
  659. package/dist/styles/components/actions/toolbar/toolbar.css +483 -0
  660. package/dist/styles/components/actions/toolbar-control-group/toolbar-control-group.css +1188 -0
  661. package/dist/styles/components/actions/toolbar-text/toolbar-text.css +256 -0
  662. package/dist/styles/components/collections/framed-list/framed-list.css +53 -0
  663. package/dist/styles/components/collections/list/list.css +293 -0
  664. package/dist/styles/components/collections/list-action-row/list-action-row.css +466 -0
  665. package/dist/styles/components/collections/list-header/list-header.css +236 -0
  666. package/dist/styles/components/collections/list-inset-control/list-inset-control.css +30 -0
  667. package/dist/styles/components/collections/list-inset-text/list-inset-text.css +29 -0
  668. package/dist/styles/components/collections/list-item/list-item.css +461 -0
  669. package/dist/styles/components/collections/summary-row/summary-row.css +161 -0
  670. package/dist/styles/components/data-display/value-table/value-table.css +183 -0
  671. package/dist/styles/components/feedback/anchored-surface/anchored-surface.css +44 -0
  672. package/dist/styles/components/feedback/badge/badge.css +157 -0
  673. package/dist/styles/components/feedback/chip/chip.css +234 -0
  674. package/dist/styles/components/feedback/corner-status/corner-status.css +60 -0
  675. package/dist/styles/components/feedback/edge-activity-indicator/edge-activity-indicator.css +127 -0
  676. package/dist/styles/components/feedback/empty-state/empty-state.css +47 -0
  677. package/dist/styles/components/feedback/loading-spinner/loading-spinner.css +25 -0
  678. package/dist/styles/components/feedback/progress-bar/progress-bar.css +168 -0
  679. package/dist/styles/components/feedback/progress-ring/progress-ring.css +91 -0
  680. package/dist/styles/components/feedback/skeleton/skeleton.css +92 -0
  681. package/dist/styles/components/feedback/state-banner/state-banner.css +312 -0
  682. package/dist/styles/components/forms/checkbox/checkbox.css +122 -0
  683. package/dist/styles/components/forms/checkbox-group/checkbox-group.css +63 -0
  684. package/dist/styles/components/forms/choice-chips/choice-chips.css +205 -0
  685. package/dist/styles/components/forms/color-field/color-field.css +125 -0
  686. package/dist/styles/components/forms/color-picker/color-picker.css +366 -0
  687. package/dist/styles/components/forms/color-swatches/color-swatches.css +122 -0
  688. package/dist/styles/components/forms/combobox/combobox.css +115 -0
  689. package/dist/styles/components/forms/file-picker/file-picker.css +81 -0
  690. package/dist/styles/components/forms/message-composer/message-composer.css +84 -0
  691. package/dist/styles/components/forms/radio-group/radio-group.css +158 -0
  692. package/dist/styles/components/forms/search-field/search-field.css +441 -0
  693. package/dist/styles/components/forms/segmented-control/segmented-control.css +196 -0
  694. package/dist/styles/components/forms/select/select.css +580 -0
  695. package/dist/styles/components/forms/slider/slider.css +241 -0
  696. package/dist/styles/components/forms/switch/switch.css +132 -0
  697. package/dist/styles/components/forms/tag-field/tag-field.css +8 -0
  698. package/dist/styles/components/forms/text-field/text-field.css +193 -0
  699. package/dist/styles/components/layout/collapsible-panel/collapsible-panel.css +580 -0
  700. package/dist/styles/components/layout/column-track/column-track.css +57 -0
  701. package/dist/styles/components/layout/content-swap/content-swap.css +154 -0
  702. package/dist/styles/components/layout/grid/grid.css +88 -0
  703. package/dist/styles/components/layout/pane/pane.css +780 -0
  704. package/dist/styles/components/layout/resizable-region/resizable-region.css +546 -0
  705. package/dist/styles/components/layout/row/row.css +125 -0
  706. package/dist/styles/components/layout/spacer/spacer.css +11 -0
  707. package/dist/styles/components/layout/split-view/split-view.css +171 -0
  708. package/dist/styles/components/layout/workbench/workbench.css +1098 -0
  709. package/dist/styles/components/media/lucide-icon/lucide-icon.css +15 -0
  710. package/dist/styles/components/navigation/disclosure-arrow/disclosure-arrow.css +43 -0
  711. package/dist/styles/components/navigation/nav-stack/nav-stack.css +619 -0
  712. package/dist/styles/components/navigation/tab-bar/tab-bar.css +203 -0
  713. package/dist/styles/components/navigation/tab-bar-item/tab-bar-item.css +389 -0
  714. package/dist/styles/components/navigation/tab-navigator/tab-navigator.css +460 -0
  715. package/dist/styles/components/surfaces/backdrop-image/backdrop-image.css +241 -0
  716. package/dist/styles/components/surfaces/content-item/content-item.css +168 -0
  717. package/dist/styles/components/surfaces/disclosure/disclosure.css +136 -0
  718. package/dist/styles/components/surfaces/sunken-panel/sunken-panel.css +34 -0
  719. package/dist/styles/components/surfaces/surface-scaffold/surface-scaffold.css +744 -0
  720. package/dist/styles/components/typography/text/text.css +232 -0
  721. package/dist/styles/content-item.css +168 -0
  722. package/dist/styles/content-swap.css +154 -0
  723. package/dist/styles/corner-status.css +60 -0
  724. package/dist/styles/disclosure-arrow.css +20 -0
  725. package/dist/styles/disclosure.css +136 -0
  726. package/dist/styles/document.css +98 -0
  727. package/dist/styles/edge-activity-indicator.css +127 -0
  728. package/dist/styles/file-picker.css +81 -0
  729. package/dist/styles/floating-toolbar.css +87 -6
  730. package/dist/styles/foundation.css +490 -50
  731. package/dist/styles/framed-list.css +53 -0
  732. package/dist/styles/grid.css +88 -0
  733. package/dist/styles/layout.css +3 -41
  734. package/dist/styles/list-action-row.css +324 -18
  735. package/dist/styles/list-detail-dialog.css +11 -0
  736. package/dist/styles/list-header.css +135 -59
  737. package/dist/styles/list-inset-control.css +30 -0
  738. package/dist/styles/list-inset-text.css +29 -0
  739. package/dist/styles/list-item.css +371 -33
  740. package/dist/styles/list.css +293 -0
  741. package/dist/styles/loading-spinner.css +4 -0
  742. package/dist/styles/lucide-icon.css +9 -0
  743. package/dist/styles/message-composer.css +84 -0
  744. package/dist/styles/nav-stack.css +555 -47
  745. package/dist/styles/overlay-sheet.css +211 -0
  746. package/dist/styles/overlay-toast.css +149 -0
  747. package/dist/styles/overlay-tooltip.css +55 -0
  748. package/dist/styles/pane.css +780 -0
  749. package/dist/styles/popup-menu.css +498 -0
  750. package/dist/styles/progress-bar.css +168 -0
  751. package/dist/styles/progress-ring.css +91 -0
  752. package/dist/styles/radio-group.css +158 -0
  753. package/dist/styles/resizable-region.css +439 -4
  754. package/dist/styles/row.css +125 -0
  755. package/dist/styles/search-field.css +441 -0
  756. package/dist/styles/segmented-control.css +36 -9
  757. package/dist/styles/select.css +516 -74
  758. package/dist/styles/skeleton.css +64 -3
  759. package/dist/styles/slider.css +241 -0
  760. package/dist/styles/spacer.css +11 -0
  761. package/dist/styles/split-button.css +141 -0
  762. package/dist/styles/split-view.css +139 -3
  763. package/dist/styles/state-banner.css +164 -25
  764. package/dist/styles/styles.css +38 -3
  765. package/dist/styles/summary-row.css +161 -0
  766. package/dist/styles/sunken-panel.css +34 -0
  767. package/dist/styles/surface-scaffold.css +744 -0
  768. package/dist/styles/switch.css +132 -0
  769. package/dist/styles/tab-bar-item.css +389 -0
  770. package/dist/styles/tab-bar.css +167 -9
  771. package/dist/styles/tab-navigator.css +460 -0
  772. package/dist/styles/tag-field.css +8 -0
  773. package/dist/styles/text-field.css +193 -0
  774. package/dist/styles/text.css +232 -0
  775. package/dist/styles/toolbar-control-group.css +1000 -37
  776. package/dist/styles/toolbar-text.css +223 -7
  777. package/dist/styles/toolbar.css +433 -11
  778. package/dist/styles/value-table.css +115 -7
  779. package/dist/styles/webawesome.css +474 -18
  780. package/dist/styles/workbench-dialog.css +10 -0
  781. package/dist/styles/workbench.css +1011 -7
  782. package/dist/summary-row.d.ts +56 -0
  783. package/dist/summary-row.js +4 -0
  784. package/dist/summary-row.js.map +1 -0
  785. package/dist/sunken-panel.d.ts +38 -0
  786. package/dist/sunken-panel.js +4 -0
  787. package/dist/sunken-panel.js.map +1 -0
  788. package/dist/surface-scaffold-register.d.ts +12 -0
  789. package/dist/surface-scaffold-register.js +10 -0
  790. package/dist/surface-scaffold-register.js.map +1 -0
  791. package/dist/surface-scaffold.d.ts +280 -0
  792. package/dist/surface-scaffold.js +8 -0
  793. package/dist/surface-scaffold.js.map +1 -0
  794. package/dist/switch.d.ts +38 -0
  795. package/dist/switch.js +4 -0
  796. package/dist/switch.js.map +1 -0
  797. package/dist/tab-bar-item.d.ts +65 -0
  798. package/dist/tab-bar-item.js +6 -0
  799. package/dist/tab-bar-item.js.map +1 -0
  800. package/dist/tab-bar.d.ts +33 -7
  801. package/dist/tab-bar.js +1 -1
  802. package/dist/tab-navigator.d.ts +154 -0
  803. package/dist/tab-navigator.js +131 -0
  804. package/dist/tab-navigator.js.map +1 -0
  805. package/dist/tag-field.d.ts +52 -0
  806. package/dist/tag-field.js +6 -0
  807. package/dist/tag-field.js.map +1 -0
  808. package/dist/text-field.d.ts +91 -0
  809. package/dist/text-field.js +6 -0
  810. package/dist/text-field.js.map +1 -0
  811. package/dist/text.d.ts +103 -0
  812. package/dist/text.js +3 -0
  813. package/dist/text.js.map +1 -0
  814. package/dist/toolbar-control-group.d.ts +112 -8
  815. package/dist/toolbar-control-group.js +3 -1
  816. package/dist/toolbar-text.d.ts +63 -9
  817. package/dist/toolbar-text.js +2 -1
  818. package/dist/toolbar.d.ts +77 -7
  819. package/dist/toolbar.js +1 -1
  820. package/dist/types-DmHWkSd6.d.ts +207 -0
  821. package/dist/value-table.d.ts +30 -4
  822. package/dist/value-table.js +2 -1
  823. package/dist/webawesome.d.ts +11 -1
  824. package/dist/wire-catalog.d.ts +117 -5
  825. package/dist/wire-catalog.js +314 -14
  826. package/dist/wire-catalog.js.map +1 -1
  827. package/dist/wire-checkboxes.d.ts +10 -0
  828. package/dist/wire-checkboxes.js +3 -0
  829. package/dist/{wire-token-search-fields.js.map → wire-checkboxes.js.map} +1 -1
  830. package/dist/wire-choice-chips.d.ts +17 -0
  831. package/dist/wire-choice-chips.js +4 -0
  832. package/dist/wire-choice-chips.js.map +1 -0
  833. package/dist/wire-color-fields.d.ts +33 -0
  834. package/dist/wire-color-fields.js +82 -0
  835. package/dist/wire-color-fields.js.map +1 -0
  836. package/dist/wire-color-pickers.d.ts +35 -0
  837. package/dist/wire-color-pickers.js +9 -0
  838. package/dist/wire-color-pickers.js.map +1 -0
  839. package/dist/wire-comboboxes.d.ts +26 -0
  840. package/dist/wire-comboboxes.js +4 -0
  841. package/dist/wire-comboboxes.js.map +1 -0
  842. package/dist/wire-content-items.d.ts +15 -0
  843. package/dist/wire-content-items.js +208 -0
  844. package/dist/wire-content-items.js.map +1 -0
  845. package/dist/wire-corner-status.d.ts +11 -0
  846. package/dist/wire-corner-status.js +3 -0
  847. package/dist/wire-corner-status.js.map +1 -0
  848. package/dist/wire-file-pickers.d.ts +27 -0
  849. package/dist/wire-file-pickers.js +3 -0
  850. package/dist/wire-file-pickers.js.map +1 -0
  851. package/dist/wire-list-focus-scroll.d.ts +16 -0
  852. package/dist/wire-list-focus-scroll.js +3 -0
  853. package/dist/wire-list-focus-scroll.js.map +1 -0
  854. package/dist/wire-list-reorder.d.ts +41 -0
  855. package/dist/wire-list-reorder.js +3 -0
  856. package/dist/wire-list-reorder.js.map +1 -0
  857. package/dist/wire-message-composers.d.ts +17 -0
  858. package/dist/wire-message-composers.js +3 -0
  859. package/dist/wire-message-composers.js.map +1 -0
  860. package/dist/wire-nav-stack.d.ts +4 -1
  861. package/dist/wire-nav-stack.js +352 -15
  862. package/dist/wire-nav-stack.js.map +1 -1
  863. package/dist/wire-overlay-sheets.d.ts +20 -0
  864. package/dist/wire-overlay-sheets.js +4 -0
  865. package/dist/wire-overlay-sheets.js.map +1 -0
  866. package/dist/wire-pane-chrome.d.ts +21 -0
  867. package/dist/wire-pane-chrome.js +67 -0
  868. package/dist/wire-pane-chrome.js.map +1 -0
  869. package/dist/wire-resizable-regions.d.ts +2 -1
  870. package/dist/wire-resizable-regions.js +2 -1
  871. package/dist/wire-scroll-dividers.d.ts +87 -0
  872. package/dist/wire-scroll-dividers.js +3 -0
  873. package/dist/wire-scroll-dividers.js.map +1 -0
  874. package/dist/{wire-token-search-fields.d.ts → wire-search-fields.d.ts} +34 -25
  875. package/dist/wire-search-fields.js +6 -0
  876. package/dist/wire-search-fields.js.map +1 -0
  877. package/dist/wire-sidebar.d.ts +24 -4
  878. package/dist/wire-sidebar.js +159 -45
  879. package/dist/wire-sidebar.js.map +1 -1
  880. package/dist/wire-sliders.d.ts +12 -0
  881. package/dist/wire-sliders.js +31 -0
  882. package/dist/wire-sliders.js.map +1 -0
  883. package/dist/wire-tab-bars.d.ts +6 -2
  884. package/dist/wire-tab-bars.js +1 -1
  885. package/dist/wire-tab-navigator.d.ts +13 -0
  886. package/dist/wire-tab-navigator.js +153 -0
  887. package/dist/wire-tab-navigator.js.map +1 -0
  888. package/dist/wire-tag-fields.d.ts +41 -0
  889. package/dist/wire-tag-fields.js +258 -0
  890. package/dist/wire-tag-fields.js.map +1 -0
  891. package/dist/wire-text-fields.d.ts +12 -0
  892. package/dist/wire-text-fields.js +3 -0
  893. package/dist/wire-text-fields.js.map +1 -0
  894. package/dist/wire-toolbar-visibility.d.ts +13 -0
  895. package/dist/wire-toolbar-visibility.js +3 -0
  896. package/dist/wire-toolbar-visibility.js.map +1 -0
  897. package/dist/wire-workbench.d.ts +116 -0
  898. package/dist/wire-workbench.js +6 -0
  899. package/dist/wire-workbench.js.map +1 -0
  900. package/dist/workbench-dialog.d.ts +106 -0
  901. package/dist/workbench-dialog.js +127 -0
  902. package/dist/workbench-dialog.js.map +1 -0
  903. package/dist/workbench.d.ts +258 -10
  904. package/dist/workbench.js +21 -15
  905. package/dist/workbench.js.map +1 -1
  906. package/docs/accessibility.md +829 -41
  907. package/docs/anchored-surface.md +107 -0
  908. package/docs/app-layouts.md +200 -10
  909. package/docs/apple-hig.md +2 -0
  910. package/docs/backdrop-image.md +128 -0
  911. package/docs/catalog.md +599 -63
  912. package/docs/collapsible-panel.md +308 -25
  913. package/docs/color-field.md +65 -0
  914. package/docs/color-picker.md +102 -0
  915. package/docs/color-swatches.md +46 -0
  916. package/docs/component-contract.md +865 -57
  917. package/docs/component-integration.md +75 -0
  918. package/docs/component-selection.md +1124 -108
  919. package/docs/design/templates/button/emphasis-dark.svg +1 -0
  920. package/docs/design/templates/button/emphasis.svg +1 -0
  921. package/docs/design/templates/button/full-width-dark.svg +1 -0
  922. package/docs/design/templates/button/full-width.svg +1 -0
  923. package/docs/design/templates/button/icons-dark.svg +1 -0
  924. package/docs/design/templates/button/icons.svg +1 -0
  925. package/docs/design/templates/button/pill-dark.svg +1 -0
  926. package/docs/design/templates/button/pill.svg +1 -0
  927. package/docs/design/templates/button/states-dark.svg +1 -0
  928. package/docs/design/templates/button/states.svg +1 -0
  929. package/docs/design/templates/button/toggles-dark.svg +1 -0
  930. package/docs/design/templates/button/toggles.svg +1 -0
  931. package/docs/design/templates/button/tones-dark.svg +1 -0
  932. package/docs/design/templates/button/tones.svg +1 -0
  933. package/docs/design/templates/button-dark.svg +1 -0
  934. package/docs/design/templates/button.svg +1 -0
  935. package/docs/design/templates/checkbox/compact-dark.svg +1 -0
  936. package/docs/design/templates/checkbox/compact.svg +1 -0
  937. package/docs/design/templates/checkbox/error-dark.svg +1 -0
  938. package/docs/design/templates/checkbox/error.svg +1 -0
  939. package/docs/design/templates/checkbox/mixed-dark.svg +1 -0
  940. package/docs/design/templates/checkbox/mixed.svg +1 -0
  941. package/docs/design/templates/checkbox/states-dark.svg +1 -0
  942. package/docs/design/templates/checkbox/states.svg +1 -0
  943. package/docs/design/templates/checkbox-dark.svg +1 -0
  944. package/docs/design/templates/checkbox-group/horizontal-dark.svg +1 -0
  945. package/docs/design/templates/checkbox-group/horizontal.svg +1 -0
  946. package/docs/design/templates/checkbox-group/vertical-dark.svg +1 -0
  947. package/docs/design/templates/checkbox-group/vertical.svg +1 -0
  948. package/docs/design/templates/checkbox-group-dark.svg +1 -0
  949. package/docs/design/templates/checkbox-group.svg +1 -0
  950. package/docs/design/templates/checkbox.svg +1 -0
  951. package/docs/design/templates/chip/action-filters-dark.svg +1 -0
  952. package/docs/design/templates/chip/action-filters.svg +1 -0
  953. package/docs/design/templates/chip/tags-dark.svg +1 -0
  954. package/docs/design/templates/chip/tags.svg +1 -0
  955. package/docs/design/templates/chip-dark.svg +1 -0
  956. package/docs/design/templates/chip.svg +1 -0
  957. package/docs/design/templates/choice-chips/color-palette-dark.svg +1 -0
  958. package/docs/design/templates/choice-chips/color-palette.svg +1 -0
  959. package/docs/design/templates/choice-chips/compact-icons-dark.svg +1 -0
  960. package/docs/design/templates/choice-chips/compact-icons.svg +1 -0
  961. package/docs/design/templates/choice-chips/multiple-dark.svg +1 -0
  962. package/docs/design/templates/choice-chips/multiple.svg +1 -0
  963. package/docs/design/templates/choice-chips-dark.svg +1 -0
  964. package/docs/design/templates/choice-chips.svg +1 -0
  965. package/docs/design/templates/color-field/compact-dark.svg +1 -0
  966. package/docs/design/templates/color-field/compact.svg +1 -0
  967. package/docs/design/templates/color-field/error-dark.svg +1 -0
  968. package/docs/design/templates/color-field/error.svg +1 -0
  969. package/docs/design/templates/color-field/hint-dark.svg +1 -0
  970. package/docs/design/templates/color-field/hint.svg +1 -0
  971. package/docs/design/templates/color-field-dark.svg +1 -0
  972. package/docs/design/templates/color-field.svg +1 -0
  973. package/docs/design/templates/color-picker/gray-dark.svg +1 -0
  974. package/docs/design/templates/color-picker/gray.svg +1 -0
  975. package/docs/design/templates/color-picker/hsb-dark.svg +1 -0
  976. package/docs/design/templates/color-picker/hsb.svg +1 -0
  977. package/docs/design/templates/color-picker/rgb-dark.svg +1 -0
  978. package/docs/design/templates/color-picker/rgb.svg +1 -0
  979. package/docs/design/templates/color-picker-dark.svg +1 -0
  980. package/docs/design/templates/color-picker.svg +1 -0
  981. package/docs/design/templates/color-swatches/palette-dark.svg +1 -0
  982. package/docs/design/templates/color-swatches/palette.svg +1 -0
  983. package/docs/design/templates/color-swatches-dark.svg +1 -0
  984. package/docs/design/templates/color-swatches.svg +1 -0
  985. package/docs/design/templates/disclosure/embedded-dark.svg +1 -0
  986. package/docs/design/templates/disclosure/embedded.svg +1 -0
  987. package/docs/design/templates/disclosure/framed-sunken-dark.svg +1 -0
  988. package/docs/design/templates/disclosure/framed-sunken.svg +1 -0
  989. package/docs/design/templates/disclosure/plain-dark.svg +1 -0
  990. package/docs/design/templates/disclosure/plain.svg +1 -0
  991. package/docs/design/templates/disclosure-dark.svg +1 -0
  992. package/docs/design/templates/disclosure.svg +1 -0
  993. package/docs/design/templates/empty-state/filtered-dark.svg +1 -1
  994. package/docs/design/templates/empty-state/filtered.svg +1 -1
  995. package/docs/design/templates/empty-state/with-action-dark.svg +1 -1
  996. package/docs/design/templates/empty-state/with-action.svg +1 -1
  997. package/docs/design/templates/empty-state-dark.svg +1 -7
  998. package/docs/design/templates/empty-state.svg +1 -7
  999. package/docs/design/templates/list/compact-dark.svg +1 -0
  1000. package/docs/design/templates/list/compact.svg +1 -0
  1001. package/docs/design/templates/list/stack-dark.svg +1 -0
  1002. package/docs/design/templates/list/stack.svg +1 -0
  1003. package/docs/design/templates/list-action-row/default-dark.svg +1 -1
  1004. package/docs/design/templates/list-action-row/default.svg +1 -1
  1005. package/docs/design/templates/list-action-row/icon-tile-dark.svg +1 -0
  1006. package/docs/design/templates/list-action-row/icon-tile.svg +1 -0
  1007. package/docs/design/templates/list-action-row/selected-dark.svg +1 -1
  1008. package/docs/design/templates/list-action-row/selected.svg +1 -1
  1009. package/docs/design/templates/list-action-row/trailing-menu-dark.svg +1 -0
  1010. package/docs/design/templates/list-action-row/trailing-menu.svg +1 -0
  1011. package/docs/design/templates/list-action-row-dark.svg +1 -7
  1012. package/docs/design/templates/list-action-row.svg +1 -7
  1013. package/docs/design/templates/list-dark.svg +1 -0
  1014. package/docs/design/templates/list-header/action-dark.svg +1 -1
  1015. package/docs/design/templates/list-header/action.svg +1 -1
  1016. package/docs/design/templates/list-header/count-dark.svg +1 -1
  1017. package/docs/design/templates/list-header/count.svg +1 -1
  1018. package/docs/design/templates/list-header/inline-action-dark.svg +1 -0
  1019. package/docs/design/templates/list-header/inline-action.svg +1 -0
  1020. package/docs/design/templates/list-header/size-l-dark.svg +1 -0
  1021. package/docs/design/templates/list-header/size-l.svg +1 -0
  1022. package/docs/design/templates/list-header/size-m-dark.svg +1 -0
  1023. package/docs/design/templates/list-header/size-m.svg +1 -0
  1024. package/docs/design/templates/list-header/size-xl-dark.svg +1 -0
  1025. package/docs/design/templates/list-header/size-xl.svg +1 -0
  1026. package/docs/design/templates/list-header/size-xs-dark.svg +1 -0
  1027. package/docs/design/templates/list-header/size-xs.svg +1 -0
  1028. package/docs/design/templates/list-header/toggle-collapsed-dark.svg +1 -1
  1029. package/docs/design/templates/list-header/toggle-collapsed.svg +1 -1
  1030. package/docs/design/templates/list-header/toggle-expanded-dark.svg +1 -1
  1031. package/docs/design/templates/list-header/toggle-expanded.svg +1 -1
  1032. package/docs/design/templates/list-header-dark.svg +1 -11
  1033. package/docs/design/templates/list-header.svg +1 -11
  1034. package/docs/design/templates/list-item/default-dark.svg +1 -1
  1035. package/docs/design/templates/list-item/default.svg +1 -1
  1036. package/docs/design/templates/list-item/icon-tile-dark.svg +1 -0
  1037. package/docs/design/templates/list-item/icon-tile.svg +1 -0
  1038. package/docs/design/templates/list-item/multiline-dark.svg +1 -1
  1039. package/docs/design/templates/list-item/multiline.svg +1 -1
  1040. package/docs/design/templates/list-item/selected-dark.svg +1 -1
  1041. package/docs/design/templates/list-item/selected.svg +1 -1
  1042. package/docs/design/templates/list-item/trailing-dark.svg +1 -1
  1043. package/docs/design/templates/list-item/trailing.svg +1 -1
  1044. package/docs/design/templates/list-item-dark.svg +1 -11
  1045. package/docs/design/templates/list-item.svg +1 -11
  1046. package/docs/design/templates/list.svg +1 -0
  1047. package/docs/design/templates/message-composer/chat-dark.svg +1 -0
  1048. package/docs/design/templates/message-composer/chat.svg +1 -0
  1049. package/docs/design/templates/message-composer/prompt-dark.svg +1 -0
  1050. package/docs/design/templates/message-composer/prompt.svg +1 -0
  1051. package/docs/design/templates/message-composer-dark.svg +1 -0
  1052. package/docs/design/templates/message-composer.svg +1 -0
  1053. package/docs/design/templates/progress-bar/determinate-dark.svg +1 -0
  1054. package/docs/design/templates/progress-bar/determinate.svg +1 -0
  1055. package/docs/design/templates/progress-bar/tones-dark.svg +1 -0
  1056. package/docs/design/templates/progress-bar/tones.svg +1 -0
  1057. package/docs/design/templates/progress-bar-dark.svg +1 -0
  1058. package/docs/design/templates/progress-bar.svg +1 -0
  1059. package/docs/design/templates/progress-ring/sizes-dark.svg +1 -0
  1060. package/docs/design/templates/progress-ring/sizes.svg +1 -0
  1061. package/docs/design/templates/progress-ring/tones-dark.svg +1 -0
  1062. package/docs/design/templates/progress-ring/tones.svg +1 -0
  1063. package/docs/design/templates/progress-ring-dark.svg +1 -0
  1064. package/docs/design/templates/progress-ring.svg +1 -0
  1065. package/docs/design/templates/radio-group/horizontal-dark.svg +1 -0
  1066. package/docs/design/templates/radio-group/horizontal.svg +1 -0
  1067. package/docs/design/templates/radio-group/vertical-dark.svg +1 -0
  1068. package/docs/design/templates/radio-group/vertical.svg +1 -0
  1069. package/docs/design/templates/radio-group-dark.svg +1 -0
  1070. package/docs/design/templates/radio-group.svg +1 -0
  1071. package/docs/design/templates/search-field/empty-dark.svg +1 -0
  1072. package/docs/design/templates/search-field/empty.svg +1 -0
  1073. package/docs/design/templates/search-field/tokens-dark.svg +1 -0
  1074. package/docs/design/templates/search-field/tokens.svg +1 -0
  1075. package/docs/design/templates/search-field-dark.svg +1 -0
  1076. package/docs/design/templates/search-field.svg +1 -0
  1077. package/docs/design/templates/segmented-control/equal-dark.svg +1 -1
  1078. package/docs/design/templates/segmented-control/equal.svg +1 -1
  1079. package/docs/design/templates/segmented-control/pill-small-dark.svg +1 -1
  1080. package/docs/design/templates/segmented-control/pill-small.svg +1 -1
  1081. package/docs/design/templates/segmented-control-dark.svg +1 -7
  1082. package/docs/design/templates/segmented-control.svg +1 -7
  1083. package/docs/design/templates/select/compact-dark.svg +1 -0
  1084. package/docs/design/templates/select/compact.svg +1 -0
  1085. package/docs/design/templates/select/form-dark.svg +1 -0
  1086. package/docs/design/templates/select/form.svg +1 -0
  1087. package/docs/design/templates/select/icons-dark.svg +1 -0
  1088. package/docs/design/templates/select/icons.svg +1 -0
  1089. package/docs/design/templates/select-dark.svg +1 -0
  1090. package/docs/design/templates/select.svg +1 -0
  1091. package/docs/design/templates/skeleton-dark.svg +1 -9
  1092. package/docs/design/templates/skeleton.svg +1 -9
  1093. package/docs/design/templates/slider/compact-dark.svg +1 -0
  1094. package/docs/design/templates/slider/compact.svg +1 -0
  1095. package/docs/design/templates/slider/readout-dark.svg +1 -0
  1096. package/docs/design/templates/slider/readout.svg +1 -0
  1097. package/docs/design/templates/slider/ticks-dark.svg +1 -0
  1098. package/docs/design/templates/slider/ticks.svg +1 -0
  1099. package/docs/design/templates/slider-dark.svg +1 -0
  1100. package/docs/design/templates/slider.svg +1 -0
  1101. package/docs/design/templates/split-button/full-width-dark.svg +1 -0
  1102. package/docs/design/templates/split-button/full-width.svg +1 -0
  1103. package/docs/design/templates/split-button/pill-dark.svg +1 -0
  1104. package/docs/design/templates/split-button/pill.svg +1 -0
  1105. package/docs/design/templates/split-button/states-dark.svg +1 -0
  1106. package/docs/design/templates/split-button/states.svg +1 -0
  1107. package/docs/design/templates/split-button/tones-dark.svg +1 -0
  1108. package/docs/design/templates/split-button/tones.svg +1 -0
  1109. package/docs/design/templates/split-button-dark.svg +1 -0
  1110. package/docs/design/templates/split-button.svg +1 -0
  1111. package/docs/design/templates/state-banner/danger-dark.svg +1 -1
  1112. package/docs/design/templates/state-banner/danger.svg +1 -1
  1113. package/docs/design/templates/state-banner/info-badge-dark.svg +1 -0
  1114. package/docs/design/templates/state-banner/info-badge.svg +1 -0
  1115. package/docs/design/templates/state-banner/info-dark.svg +1 -1
  1116. package/docs/design/templates/state-banner/info.svg +1 -1
  1117. package/docs/design/templates/state-banner/strip-dark.svg +1 -0
  1118. package/docs/design/templates/state-banner/strip.svg +1 -0
  1119. package/docs/design/templates/state-banner/success-dark.svg +1 -1
  1120. package/docs/design/templates/state-banner/success.svg +1 -1
  1121. package/docs/design/templates/state-banner/warning-dark.svg +1 -1
  1122. package/docs/design/templates/state-banner/warning.svg +1 -1
  1123. package/docs/design/templates/state-banner-dark.svg +1 -11
  1124. package/docs/design/templates/state-banner.svg +1 -11
  1125. package/docs/design/templates/switch/compact-dark.svg +1 -0
  1126. package/docs/design/templates/switch/compact.svg +1 -0
  1127. package/docs/design/templates/switch/states-dark.svg +1 -0
  1128. package/docs/design/templates/switch/states.svg +1 -0
  1129. package/docs/design/templates/switch-dark.svg +1 -0
  1130. package/docs/design/templates/switch.svg +1 -0
  1131. package/docs/design/templates/tab-bar/workspace-tabs-dark.svg +1 -1
  1132. package/docs/design/templates/tab-bar/workspace-tabs.svg +1 -1
  1133. package/docs/design/templates/tab-bar-dark.svg +1 -5
  1134. package/docs/design/templates/tab-bar.svg +1 -5
  1135. package/docs/design/templates/tag-field/error-dark.svg +1 -0
  1136. package/docs/design/templates/tag-field/error.svg +1 -0
  1137. package/docs/design/templates/tag-field/tags-dark.svg +1 -0
  1138. package/docs/design/templates/tag-field/tags.svg +1 -0
  1139. package/docs/design/templates/tag-field-dark.svg +1 -0
  1140. package/docs/design/templates/tag-field.svg +1 -0
  1141. package/docs/design/templates/text-field/compact-dark.svg +1 -0
  1142. package/docs/design/templates/text-field/compact.svg +1 -0
  1143. package/docs/design/templates/text-field/error-dark.svg +1 -0
  1144. package/docs/design/templates/text-field/error.svg +1 -0
  1145. package/docs/design/templates/text-field/labeled-dark.svg +1 -0
  1146. package/docs/design/templates/text-field/labeled.svg +1 -0
  1147. package/docs/design/templates/text-field/multiline-dark.svg +1 -0
  1148. package/docs/design/templates/text-field/multiline.svg +1 -0
  1149. package/docs/design/templates/text-field/number-dark.svg +1 -0
  1150. package/docs/design/templates/text-field/number.svg +1 -0
  1151. package/docs/design/templates/text-field/search-dark.svg +1 -0
  1152. package/docs/design/templates/text-field/search.svg +1 -0
  1153. package/docs/design/templates/text-field-dark.svg +1 -0
  1154. package/docs/design/templates/text-field.svg +1 -0
  1155. package/docs/design/templates/toolbar/title-and-actions-dark.svg +1 -1
  1156. package/docs/design/templates/toolbar/title-and-actions.svg +1 -1
  1157. package/docs/design/templates/toolbar/width-visibility-320-dark.svg +1 -0
  1158. package/docs/design/templates/toolbar/width-visibility-320.svg +1 -0
  1159. package/docs/design/templates/toolbar/width-visibility-600-dark.svg +1 -0
  1160. package/docs/design/templates/toolbar/width-visibility-600.svg +1 -0
  1161. package/docs/design/templates/toolbar-control-group/borderless-single-dark.svg +1 -1
  1162. package/docs/design/templates/toolbar-control-group/borderless-single.svg +1 -1
  1163. package/docs/design/templates/toolbar-control-group/glass-dark.svg +1 -0
  1164. package/docs/design/templates/toolbar-control-group/glass.svg +1 -0
  1165. package/docs/design/templates/toolbar-control-group/icon-buttons-dark.svg +1 -1
  1166. package/docs/design/templates/toolbar-control-group/icon-buttons.svg +1 -1
  1167. package/docs/design/templates/toolbar-control-group/icon-tile-brand-dark.svg +1 -0
  1168. package/docs/design/templates/toolbar-control-group/icon-tile-brand.svg +1 -0
  1169. package/docs/design/templates/toolbar-control-group/icon-tile-danger-dark.svg +1 -0
  1170. package/docs/design/templates/toolbar-control-group/icon-tile-danger.svg +1 -0
  1171. package/docs/design/templates/toolbar-control-group/icon-tile-neutral-dark.svg +1 -0
  1172. package/docs/design/templates/toolbar-control-group/icon-tile-neutral.svg +1 -0
  1173. package/docs/design/templates/toolbar-control-group/icon-tile-success-dark.svg +1 -0
  1174. package/docs/design/templates/toolbar-control-group/icon-tile-success.svg +1 -0
  1175. package/docs/design/templates/toolbar-control-group/icon-tile-warning-dark.svg +1 -0
  1176. package/docs/design/templates/toolbar-control-group/icon-tile-warning.svg +1 -0
  1177. package/docs/design/templates/toolbar-control-group/push-buttons-dark.svg +1 -1
  1178. package/docs/design/templates/toolbar-control-group/push-buttons.svg +1 -1
  1179. package/docs/design/templates/toolbar-control-group/with-text-dark.svg +1 -1
  1180. package/docs/design/templates/toolbar-control-group/with-text.svg +1 -1
  1181. package/docs/design/templates/toolbar-control-group-dark.svg +1 -11
  1182. package/docs/design/templates/toolbar-control-group.svg +1 -11
  1183. package/docs/design/templates/toolbar-dark.svg +1 -5
  1184. package/docs/design/templates/toolbar-text/dark-tone-dark.svg +1 -0
  1185. package/docs/design/templates/toolbar-text/dark-tone.svg +1 -0
  1186. package/docs/design/templates/toolbar-text/default-dark.svg +1 -1
  1187. package/docs/design/templates/toolbar-text/default.svg +1 -1
  1188. package/docs/design/templates/toolbar-text/large-dark.svg +1 -1
  1189. package/docs/design/templates/toolbar-text/large.svg +1 -1
  1190. package/docs/design/templates/toolbar-text/small-dark.svg +1 -1
  1191. package/docs/design/templates/toolbar-text/small.svg +1 -1
  1192. package/docs/design/templates/toolbar-text-dark.svg +1 -9
  1193. package/docs/design/templates/toolbar-text.svg +1 -9
  1194. package/docs/design/templates/toolbar.svg +1 -5
  1195. package/docs/design/templates/value-table/details-dark.svg +1 -1
  1196. package/docs/design/templates/value-table/details.svg +1 -1
  1197. package/docs/design/templates/value-table-dark.svg +1 -5
  1198. package/docs/design/templates/value-table.svg +1 -5
  1199. package/docs/design/templates.md +87 -33
  1200. package/docs/design-philosophy.md +65 -20
  1201. package/docs/device-class.md +10 -9
  1202. package/docs/disclosure.md +97 -0
  1203. package/docs/document-baseline.md +93 -0
  1204. package/docs/examples/application-ui-profile.json +60 -0
  1205. package/docs/examples/command-palette-adapter.tsx +69 -17
  1206. package/docs/examples/component-catalog-extension.json +52 -0
  1207. package/docs/examples/component-composition-extension.json +80 -0
  1208. package/docs/layout.md +946 -53
  1209. package/docs/list-detail-dialog.md +100 -0
  1210. package/docs/manual-test-plan.md +29 -0
  1211. package/docs/message-composer.md +156 -0
  1212. package/docs/nav-stack.md +327 -14
  1213. package/docs/overlay-toast.md +62 -0
  1214. package/docs/overlay-tooltip.md +53 -0
  1215. package/docs/progress.md +62 -0
  1216. package/docs/recipes.md +147 -73
  1217. package/docs/slider.md +64 -0
  1218. package/docs/split-view.md +96 -7
  1219. package/docs/sunken-panel.md +106 -0
  1220. package/docs/surface-scaffold.md +487 -0
  1221. package/docs/tab-navigator.md +291 -0
  1222. package/docs/tag-field.md +66 -0
  1223. package/docs/type-contracts.md +137 -0
  1224. package/docs/ui-analyzer.md +406 -0
  1225. package/docs/ui-doctor.md +298 -0
  1226. package/docs/ui-evaluator.md +139 -0
  1227. package/docs/ux-demo.md +58 -17
  1228. package/docs/webawesome-migration.md +82 -0
  1229. package/docs/webawesome-theme.md +306 -47
  1230. package/docs/workbench-dialog.md +88 -0
  1231. package/docs/workbench.md +637 -12
  1232. package/docs/writing.md +154 -0
  1233. package/doctor/cli.mjs +120 -0
  1234. package/doctor/component-style-checks.mjs +457 -0
  1235. package/doctor/config.schema.json +94 -0
  1236. package/doctor/copy-capitalization-checks.mjs +603 -0
  1237. package/doctor/eslint-diagnostics.d.mts +24 -0
  1238. package/doctor/eslint-diagnostics.mjs +24 -0
  1239. package/doctor/index.d.mts +122 -0
  1240. package/doctor/index.mjs +1424 -0
  1241. package/doctor/report.schema.json +118 -0
  1242. package/evaluator/cli.mjs +89 -0
  1243. package/evaluator/index.d.mts +90 -0
  1244. package/evaluator/index.mjs +1203 -0
  1245. package/evaluator/report.schema.json +152 -0
  1246. package/llms.txt +940 -54
  1247. package/package.json +488 -43
  1248. package/scripts/component-catalog-extension-validation.mjs +28 -0
  1249. package/traversal-exclusions.mjs +86 -0
  1250. package/ux-demo/recipes/app-shell.tsx +204 -16
  1251. package/ux-demo/recipes/collapsible-sidebar.tsx +206 -45
  1252. package/ux-demo/recipes/compact-toolbar.tsx +135 -14
  1253. package/ux-demo/recipes/composer-form.tsx +135 -24
  1254. package/ux-demo/recipes/list-detail-dialog.tsx +155 -21
  1255. package/ux-demo/recipes/list-workspace-states.tsx +183 -11
  1256. package/ux-demo/recipes/loaders.ts +11 -3
  1257. package/ux-demo/recipes/loading-inspector.tsx +162 -39
  1258. package/ux-demo/recipes/media-detail.tsx +272 -0
  1259. package/ux-demo/recipes/mount-recipe.ts +28 -11
  1260. package/ux-demo/recipes/navigation-sidebar.tsx +137 -11
  1261. package/ux-demo/recipes/navigation-stack.tsx +79 -24
  1262. package/ux-demo/recipes/types.ts +18 -2
  1263. package/ux-demo/recipes/workspace-header.tsx +86 -5
  1264. package/vite-ux-review.d.mts +83 -0
  1265. package/vite-ux-review.mjs +120 -0
  1266. package/dist/app-tab.d.ts +0 -30
  1267. package/dist/app-tab.js +0 -5
  1268. package/dist/app-tab.js.map +0 -1
  1269. package/dist/browser/app-tab.js +0 -4
  1270. package/dist/browser/panel-header.js +0 -7
  1271. package/dist/browser/token-search-field.js +0 -4
  1272. package/dist/chunk-2Z5TWHKQ.js +0 -34
  1273. package/dist/chunk-2Z5TWHKQ.js.map +0 -1
  1274. package/dist/chunk-37T3VNIZ.js +0 -19
  1275. package/dist/chunk-37T3VNIZ.js.map +0 -1
  1276. package/dist/chunk-55DATV3A.js +0 -10
  1277. package/dist/chunk-55DATV3A.js.map +0 -1
  1278. package/dist/chunk-56RJXPHG.js.map +0 -1
  1279. package/dist/chunk-5ATCDSQS.js +0 -42
  1280. package/dist/chunk-5ATCDSQS.js.map +0 -1
  1281. package/dist/chunk-5E2HVJ33.js +0 -10
  1282. package/dist/chunk-5E2HVJ33.js.map +0 -1
  1283. package/dist/chunk-7BR3DO2A.js +0 -31
  1284. package/dist/chunk-7BR3DO2A.js.map +0 -1
  1285. package/dist/chunk-7JB7VPRI.js +0 -34
  1286. package/dist/chunk-7JB7VPRI.js.map +0 -1
  1287. package/dist/chunk-7LDCTU7D.js +0 -134
  1288. package/dist/chunk-7LDCTU7D.js.map +0 -1
  1289. package/dist/chunk-AQNKJRFH.js +0 -79
  1290. package/dist/chunk-AQNKJRFH.js.map +0 -1
  1291. package/dist/chunk-AVZHJN6C.js +0 -14
  1292. package/dist/chunk-AVZHJN6C.js.map +0 -1
  1293. package/dist/chunk-B24C4A6T.js +0 -22
  1294. package/dist/chunk-B24C4A6T.js.map +0 -1
  1295. package/dist/chunk-BLK3UEEI.js +0 -23
  1296. package/dist/chunk-BLK3UEEI.js.map +0 -1
  1297. package/dist/chunk-CH4SQ6H5.js +0 -39
  1298. package/dist/chunk-CH4SQ6H5.js.map +0 -1
  1299. package/dist/chunk-DAFFDO33.js +0 -14
  1300. package/dist/chunk-DAFFDO33.js.map +0 -1
  1301. package/dist/chunk-I7INRJO4.js +0 -17
  1302. package/dist/chunk-I7INRJO4.js.map +0 -1
  1303. package/dist/chunk-L4OKFDJY.js +0 -24
  1304. package/dist/chunk-L4OKFDJY.js.map +0 -1
  1305. package/dist/chunk-LCOBDOCC.js +0 -265
  1306. package/dist/chunk-LCOBDOCC.js.map +0 -1
  1307. package/dist/chunk-M5JRI6MN.js +0 -27
  1308. package/dist/chunk-M5JRI6MN.js.map +0 -1
  1309. package/dist/chunk-RNPGFQ33.js +0 -10
  1310. package/dist/chunk-RNPGFQ33.js.map +0 -1
  1311. package/dist/chunk-RUNWEPR4.js +0 -10
  1312. package/dist/chunk-RUNWEPR4.js.map +0 -1
  1313. package/dist/chunk-W2FK7ZNY.js +0 -26
  1314. package/dist/chunk-W2FK7ZNY.js.map +0 -1
  1315. package/dist/chunk-WVPYVDXY.js +0 -15
  1316. package/dist/chunk-WVPYVDXY.js.map +0 -1
  1317. package/dist/chunk-XE5ZLPCC.js +0 -20
  1318. package/dist/chunk-XE5ZLPCC.js.map +0 -1
  1319. package/dist/chunk-XXMOARTH.js +0 -229
  1320. package/dist/chunk-XXMOARTH.js.map +0 -1
  1321. package/dist/chunk-YGN7OMLT.js.map +0 -1
  1322. package/dist/panel-header.d.ts +0 -36
  1323. package/dist/panel-header.js +0 -7
  1324. package/dist/panel-header.js.map +0 -1
  1325. package/dist/styles/app-tab.css +0 -152
  1326. package/dist/styles/panel-header.css +0 -64
  1327. package/dist/styles/tab-scaffold.css +0 -84
  1328. package/dist/styles/token-search-field.css +0 -289
  1329. package/dist/tab-scaffold.d.ts +0 -30
  1330. package/dist/tab-scaffold.js +0 -16
  1331. package/dist/tab-scaffold.js.map +0 -1
  1332. package/dist/token-search-field.d.ts +0 -43
  1333. package/dist/token-search-field.js +0 -4
  1334. package/dist/token-search-field.js.map +0 -1
  1335. package/dist/wire-tab-scaffold.d.ts +0 -11
  1336. package/dist/wire-tab-scaffold.js +0 -16
  1337. package/dist/wire-tab-scaffold.js.map +0 -1
  1338. package/dist/wire-token-search-fields.js +0 -5
  1339. package/docs/design/templates/panel-header/icon-actions-dark.svg +0 -1
  1340. package/docs/design/templates/panel-header/icon-actions.svg +0 -1
  1341. package/docs/design/templates/panel-header/icon-summary-actions-dark.svg +0 -1
  1342. package/docs/design/templates/panel-header/icon-summary-actions.svg +0 -1
  1343. package/docs/design/templates/panel-header/no-icon-dark.svg +0 -1
  1344. package/docs/design/templates/panel-header/no-icon.svg +0 -1
  1345. package/docs/design/templates/panel-header/page-heading-dark.svg +0 -1
  1346. package/docs/design/templates/panel-header/page-heading.svg +0 -1
  1347. package/docs/design/templates/panel-header/title-only-dark.svg +0 -1
  1348. package/docs/design/templates/panel-header/title-only.svg +0 -1
  1349. package/docs/design/templates/panel-header-dark.svg +0 -13
  1350. package/docs/design/templates/panel-header.svg +0 -13
  1351. package/docs/design/templates/token-search-field/empty-dark.svg +0 -1
  1352. package/docs/design/templates/token-search-field/empty.svg +0 -1
  1353. package/docs/design/templates/token-search-field/tokens-dark.svg +0 -1
  1354. package/docs/design/templates/token-search-field/tokens.svg +0 -1
  1355. package/docs/design/templates/token-search-field-dark.svg +0 -7
  1356. package/docs/design/templates/token-search-field.svg +0 -7
  1357. package/docs/tab-scaffold.md +0 -41
  1358. package/ux-demo/recipes/recipes.css +0 -448
@@ -5,9 +5,9 @@ Use the shipped [`component-catalog.json`](../ai/component-catalog.json) when a
5
5
  tool needs exhaustive structured facts; this page remains the concise human
6
6
  decision procedure.
7
7
 
8
- 1. Search the [Kerf UX catalog](./ux-demo.md) and the supported Web Awesome set.
8
+ 1. Search the [Kerf UX catalog](./ux-demo.md). Prefer a Kerf UI component, then a native HTML element, using each naturally for what it is good at. When neither fits and the need recurs, file a component gap. Web Awesome is an optional integration: an application that has adopted it (see [Web Awesome integration](#web-awesome-integration)) may also use its remaining supported elements, but never one a Kerf component replaces.
9
9
  2. Reuse a primitive when its purpose, anatomy, state, and interaction match.
10
- 3. Compose primitives for recurring layout. Prefer public props and tokens; when a composition needs a selector, target only classes listed in the catalog's `publicClasses` contract.
10
+ 3. Compose primitives for recurring layout through public props and tokens. Do not select one component from another component's stylesheet.
11
11
  4. Add a thin application adapter for product copy, domain mapping, actions, routing, persistence, permissions, and transport.
12
12
  5. Use custom markup only when the semantic contract differs. If the pattern recurs across products, open an upstream component or recipe request.
13
13
 
@@ -15,38 +15,219 @@ The application adapter is usually a plain function that maps domain state to
15
15
  component props plus stable `data-action` values. It is not a fork of package
16
16
  markup or CSS.
17
17
 
18
- **Don't fight the components.** The package is built to look right unstyled, so
19
- custom CSS is the exception. Before adding `padding`, `margin`, `width`, `height`,
20
- `border`, `background`, a wrapper card, or a decoration, check whether the
21
- component, the pane, or the content-item already owns it — it almost always does,
22
- and adding more usually double-insets or fights it. Trust component defaults and
23
- fix the surrounding layout instead of overriding a control. See
18
+ ## Decision pass before JSX or CSS
19
+
20
+ Make these choices in order for each region, including a region copied from a
21
+ mockup or another application:
22
+
23
+ 1. **Name the job.** What does the person read, choose, edit, or navigate? What
24
+ state and keyboard behavior must survive? Search the Kerf catalog, then the
25
+ consuming application's catalog. Choose by that contract, not by a similar
26
+ silhouette. For example, use `ContentItem` for an owned content surface,
27
+ `List` for vertical rhythm, `Grid` for equal responsive tracks,
28
+ `Toolbar`/`ToolbarText` for a heading with actions, and `PopupMenu` for a
29
+ command menu. `SearchField` is for text plus filter chips; an ordinary
30
+ search input does not gain tokens just to use that component.
31
+ 2. **Reuse, compose, then extend.** If a component already owns the job,
32
+ configure it. If several primitives form the job, compose them and keep
33
+ product data/actions in a thin adapter. Create an application component when
34
+ it owns a repeatable domain contract or genuinely new structure. If the
35
+ missing contract would benefit other applications, file a Kerf component or
36
+ recipe gap. Do not clone a component's markup to make a local variant.
37
+ 3. **Give every element and class a reason.** An element should supply semantic
38
+ meaning, an interaction target, an accessibility relationship, or layout
39
+ that no selected component already owns. Put accepted content directly in
40
+ the component's props/slots; delete wrapper `div`/`span` elements and
41
+ fragments used only for spacing, styling, or satisfying a child type. Add a
42
+ CSS class only for an application-owned selector, not to restyle a Kerf
43
+ root; use stable `data-action` hooks for behavior. Native links, tables,
44
+ and form controls still belong where their native semantics are the right
45
+ contract.
46
+ 4. **Assign geometry once.** Decide which component owns the surface, inset,
47
+ scrollport, and each gap before adding styles. Align neighboring text edges
48
+ and control edges; group related items tightly and separate distinct
49
+ sections with a larger step from the shared scale. Leave useful empty space
50
+ around a short form or sparse state instead of filling it with decorative
51
+ cards, labels, or dividers. Use a public edge-to-edge or inset option where
52
+ available; a negative margin or compensating wrapper is a sign to revisit
53
+ ownership. Check narrow and intermediate widths before choosing fixed
54
+ columns or dimensions.
55
+ 5. **Compare the finished composition.** Inspect it beside adjacent screens
56
+ and the catalog specimen, then in a real browser at wide and narrow widths.
57
+ Check reading order, content edges, wrapping, clipping, whitespace, scroll
58
+ ownership, focus, and active/empty/loading states. Revise the component
59
+ choice or composition when the result needs repeated CSS corrections.
60
+
61
+ The package's defaults are the starting design, not an empty canvas. A custom
62
+ component or rule should explain which missing behavior or structure it owns.
63
+
64
+ Write the copy by the package rule as you choose components: a component's
65
+ naming props (button and menu-item labels, segment and `Select` choices,
66
+ `ToolbarText` titles, `ListHeader` labels, field labels) take title style, and
67
+ its describing props (`description`, `detail`, hints, placeholders, tooltips,
68
+ option text, status) take sentence style. See
69
+ [Writing interface copy](./writing.md#capitalization).
70
+
71
+ **Don't fight the components.** The package is built to look right without an
72
+ application customization layer. Before adding `padding`, `margin`, `width`,
73
+ `height`, `border`, `background`, a wrapper card, or a decoration, check whether
74
+ the component, the pane, or the content-item already owns it — it almost always
75
+ does. Express presentation through props and tokens. Encapsulate genuinely new
76
+ structure in a self-styled application component, and never reach into a nested
77
+ Kerf or Web Awesome component from that stylesheet. See
24
78
  [`design-philosophy.md`](./design-philosophy.md) "Reach for the primitive, not for
25
79
  CSS".
26
80
 
81
+ ### Shared semantic tones
82
+
83
+ `SemanticTone` is the shared color-role type for `Badge`, `Chip`, `StateBanner`,
84
+ and semantic `ContentItem` appearances: `neutral`, `info`, `pop`, `success`,
85
+ `warning`, and `danger`. Import it as a type from `@kerfjs/ui`,
86
+ `@kerfjs/ui/badge`, `@kerfjs/ui/state-banner`, or `@kerfjs/ui/content-item`.
87
+ Use `info` for the role backed by the existing `--kui-color-brand-*` tokens.
88
+ Migrate Badge/Chip `tone="brand"` to `tone="info"`; `BadgeTone` and
89
+ `StateBannerTone` remain deprecated aliases of `SemanticTone`.
90
+
91
+ ## Foundation tokens
92
+
93
+ Import the opt-in `@kerfjs/ui/document.css` baseline when the application wants
94
+ Kerf UI to own global box sizing, body typography/colors, plain-link color, and
95
+ the definite full-height chain. It also lets native table cells and form controls
96
+ inherit the surrounding font metrics without removing table-header emphasis.
97
+ Put `.kui-app-root` on the one direct mount
98
+ container only for a full-height shell; ordinary flowing pages can omit it. See
99
+ [Document baseline](document-baseline.md).
100
+
101
+ Import `@kerfjs/ui/foundation.css` when application-owned composition CSS needs
102
+ the same semantic typography, spacing, device breakpoints, geometry, radii,
103
+ colors, focus ring, or shadows as Kerf components. Its complete supported
104
+ `--kui-*` surface is cataloged by the `foundation` entry; tools may treat that
105
+ entry as the public allowlist rather than inferring stability from CSS text.
106
+ Override these tokens globally for an application theme or on the narrowest
107
+ useful subtree. Prefer a component prop or component-specific token when the
108
+ change belongs to one component or instance, and preserve the documented
109
+ foreground/background contrast relationships and visible focus ring.
110
+
111
+ ### Brand color
112
+
113
+ Set the opt-in `--kui-color-brand` once on `:root` to give the application its
114
+ own brand. Any color works: Kerf derives the whole brand ramp from it — the
115
+ loud fill (and the quiet and normal fills and borders mixed from it), its
116
+ on-loud text, brand text and links, brand text on brand fills, and the focus
117
+ ring — clamping lightness in each color scheme so every pair keeps WCAG AA for
118
+ any hue. Unset, every brand token keeps its tuned default exactly. With the
119
+ Web Awesome integration the same derivation drives `--wa-color-brand-*` and
120
+ `--wa-color-focus`.
121
+
122
+ ```css
123
+ :root {
124
+ --kui-color-brand: #1a7f37;
125
+ }
126
+ ```
127
+
128
+ Do not change the brand by overriding `--kui-color-brand-fill-loud` alone:
129
+ brand text (`--kui-color-brand-on-quiet`, `--kui-color-brand-on-fill`) and the
130
+ focus ring are separate tuned values and would stay the default blue. Choose a
131
+ brand hue apart from the status tones it shares surfaces with: `info` follows
132
+ the brand, so a green brand makes an info banner read like `success`. For one
133
+ subtree with a different identity, use a scoped `tint` accent instead.
134
+
135
+ ### Typed runtime dimensions
136
+
137
+ Use `Row`, `Grid`, or `List` spacing shorthands for repeated sibling spacing: `gap="xs"`,
138
+ `gap="m"`, and the other `UiSpaceName` values resolve to their matching
139
+ `--kui-space-*` token. Use `Spacer` for one deliberate empty width or height, or
140
+ pass `flex` to consume the remaining space along a flex parent's main axis.
141
+ Pass `gap={{ column: 'none', row: 'm' }}` when the axes need different values;
142
+ each axis accepts the same token or complete typed length as the scalar form.
143
+ The canonical rhythm is `none`, `2xs`, `xs`, `m`, and `l`; use `s` and `xl`
144
+ only as deliberate exceptions.
145
+
146
+ When a value cannot be expressed by one spacing step, import the CSS-free
147
+ `@kerfjs/ui/css-values` subpath. `px`, `rem`, `em`, and `pct` create typed
148
+ `CssLength` values; `space` and `lengthVar` reference spacing or
149
+ application-owned length tokens. `plus` creates a non-standalone
150
+ `CssLengthExpression`, so wrap it with `calc` before passing it to a gap prop:
151
+
152
+ ```tsx
153
+ import { calc, pct, plus, rem, space } from "@kerfjs/ui/css-values";
154
+ import { Grid } from "@kerfjs/ui/grid";
155
+ import { List } from "@kerfjs/ui/list";
156
+ import { Row } from "@kerfjs/ui/row";
157
+
158
+ <List gap="xs">...</List>;
159
+ <Grid columns={3} gap="m">...</Grid>;
160
+ <Grid columns={3} gap={{ column: 'none', row: 'm' }}>...</Grid>;
161
+ <Row hAlign="full" vAlign="middle" gap="m">...</Row>;
162
+ <List gap={space("m")}>...</List>;
163
+ <List gap={calc(plus(rem(0.25), pct(10)))}>...</List>;
164
+ ```
165
+
166
+ `CssValue` is the common branded base, not an arbitrary-string constructor.
167
+ For a responsive equal-width form, pass `Grid minColumnWidth={px(376)}` instead
168
+ of `columns`; the Grid's container width decides when the tracks collapse.
169
+ Raw strings such as `"0.25rem"` do not satisfy `Row.gap`, `Grid.gap`, or `List.gap`; this
170
+ contract lands before the 5.0 stable release so misspelled tokens and incomplete
171
+ expressions fail during typechecking rather than in the browser.
172
+
173
+ Other CSS-valued props use distinct contracts: `Spacer.width` and
174
+ `Spacer.height` take `UiSpaceName | CssLength`; `flex()` creates `CssFlex` for
175
+ `Row.flex`, `Grid.flex`, and `List.flex`; `Skeleton` dimensions take typed lengths (plus finite intrinsic
176
+ keywords for width/height); and `SelectChoice.color` takes a
177
+ `CssForegroundColor` from `uiColor()` with a foreground token (`*-on-*`, a text
178
+ role, or a `*-text` alias), from `foregroundColorVar()`, or from `foregroundColor()` via the `foregroundColor` helper for an application-chosen CSS color. `LucideIcon.color` accepts the same foreground type and otherwise inherits surrounding text color. The bare `success`,
179
+ `warning`, `danger`, `pop`, and `accent` tokens are quiet fills, not
180
+ foregrounds, and are rejected there; `colorVar()` returns a plain `CssColor`.
181
+ `LucideIcon` is block-level by default; set `inline` to let it flow inside
182
+ `Text` or other prose without changing its size or accessibility semantics.
183
+ Do not substitute one brand for another. Row components
184
+ have no declaration-string `style` prop; use `className`, documented public
185
+ tokens, and semantic component props. Catalog media queries remain strings and
186
+ semantic pixel measurements remain numbers because those are different APIs.
187
+ The corresponding public builders are `flex`, `uiColor`, `colorVar`, and
188
+ `foregroundColorVar`.
189
+
27
190
  ## Production recipes
28
191
 
29
192
  Use the [complete recipe guide](./recipes.md) when several primitives form one
30
193
  application boundary:
31
194
 
32
- | Task | Stable catalog route |
33
- | --- | --- |
34
- | Desktop application shell | [Catalog](../ux-demo/) · `?component=recipe-app-shell` |
35
- | Navigation sidebar | [Catalog](../ux-demo/) · `?component=recipe-navigation-sidebar` |
36
- | Workspace header | [Catalog](../ux-demo/) · `?component=recipe-workspace-header` |
37
- | List-detail dialog | [Catalog](../ux-demo/) · `?component=recipe-list-detail-dialog` |
38
- | Composer form | [Catalog](../ux-demo/) · `?component=recipe-composer-form` |
39
- | List workspace states | [Catalog](../ux-demo/) · `?component=recipe-list-workspace-states` |
40
- | Compact toolbar choices and actions | [Catalog](../ux-demo/) · `?component=recipe-compact-toolbar` |
41
- | Navigation stack | [Catalog](../ux-demo/) · `?component=recipe-navigation-stack` |
42
- | Loading inspector | [Catalog](../ux-demo/) · `?component=recipe-loading-inspector` |
43
- | Collapsible sidebar | [Catalog](../ux-demo/) · `?component=recipe-collapsible-sidebar` |
195
+ | Task | Stable catalog route |
196
+ | ----------------------------------- | ------------------------------------------------------------------ |
197
+ | Desktop application shell | [Catalog](../ux-demo/) · `?component=recipe-app-shell` |
198
+ | Navigation sidebar | [Catalog](../ux-demo/) · `?component=recipe-navigation-sidebar` |
199
+ | Workspace header | [Catalog](../ux-demo/) · `?component=recipe-workspace-header` |
200
+ | List-detail dialog | [Catalog](../ux-demo/) · `?component=recipe-list-detail-dialog` |
201
+ | Composer form | [Catalog](../ux-demo/) · `?component=recipe-composer-form` |
202
+ | List workspace states | [Catalog](../ux-demo/) · `?component=recipe-list-workspace-states` |
203
+ | Compact toolbar choices and actions | [Catalog](../ux-demo/) · `?component=recipe-compact-toolbar` |
204
+ | Navigation stack | [Catalog](../ux-demo/) · `?component=recipe-navigation-stack` |
205
+ | Loading inspector | [Catalog](../ux-demo/) · `?component=recipe-loading-inspector` |
206
+ | Collapsible sidebar | [Catalog](../ux-demo/) · `?component=recipe-collapsible-sidebar` |
207
+ | Media detail page | [Catalog](../ux-demo/) · `?component=recipe-media-detail` |
44
208
 
45
209
  Recipes use public production exports and show ownership boundaries; they are
46
210
  copyable reference compositions, not new monolithic components.
47
211
 
212
+ When presenting a component or recipe in a Catalog, use the authoritative
213
+ [Catalog demo authoring contract](./catalog.md#catalog-demo-authoring-contract)
214
+ rather than deriving preview structure from these
215
+ selection entries.
216
+
48
217
  ## Missing recurring concepts
49
218
 
219
+ For arbitrary interactive help or popup content beside a control, use
220
+ [`openAnchoredSurface`](anchored-surface.md) with an accessible label; use
221
+ `openAnchoredSurfaceAt` for pointer coordinates. It owns the Kerf UI surface,
222
+ placement (an 8px viewport gutter, and a height fitted to the room beside the
223
+ anchor with scrolling content), focus, dismissal, and modal-dialog hosting while
224
+ the app owns its content and action policy. Never add media queries or
225
+ `max-height` overrides to make a surface fit a phone. For a popup anchored to
226
+ dark media chrome (a `ToolbarControlGroup tone="dark"` over a preview), pass
227
+ `tone: 'dark'` rather than building an app-owned dark panel: the surface takes
228
+ the group's inverse tone and its content inherits the matching colors. Use
229
+ `PopupMenu` for a typed command list.
230
+
50
231
  Kerf UI does not export a command-palette component. Do not invent a package
51
232
  command-palette import.
52
233
  The typed [application adapter example](./examples/command-palette-adapter.tsx)
@@ -58,98 +239,689 @@ an upstream component or recipe request.
58
239
 
59
240
  ## Problem-to-component matrix
60
241
 
61
- | Interface need | Use when | Do not use when; nearest alternative | Required wiring | Application owns | Import | Recipe |
62
- | --- | --- | --- | --- | --- | --- | --- |
63
- | Icon — `LucideIcon` | A decorative or explicitly labeled Lucide-compatible icon belongs in app UI. | Do not use an icon as the only name of an unfamiliar action; add visible or accessible text. Prefer it over Web Awesome `wa-icon`. | None. | Icon choice and meaningful label. | `@kerfjs/ui/lucide-icon` | [Accessibility](./accessibility.md#shared-rules) |
64
- | Disclosure indicator — `DisclosureArrow` | A control needs one animated 18px root-scaled visual for open and closed state, including configurable directions or a replacement icon. | Do not use it as the interactive control or accessible name; place it inside the button or control that exposes expanded state. | Pass the controlled `open` state, render it inside the owning control, author replacement icon content facing right before transforms, and override `--kui-disclosure-arrow-size` only when another visual size is required. Direction changes use the shortest rotation path, with counterclockwise chosen for a 180-degree closed-to-open tie. | Open state, interaction, accessible name, size override, replacement glyph, direction choices, and shortest-path rotation. | `@kerfjs/ui/disclosure-arrow` | [Component ownership](./component-contract.md#ownership-boundaries) |
65
- | Application toolbar — `Toolbar` | Leading identity, optional centered content, and trailing controls form one horizontal app bar. | Do not use it for a page, panel, or dialog heading; use `PanelHeader`. | Compose `ToolbarText` and `ToolbarControlGroup` where their contracts fit. | Actions, command availability, responsive relocation, and state. | `@kerfjs/ui/toolbar` | [Toolbar composition](../README.md#component-subpaths) |
66
- | Toolbar control cluster — `ToolbarControlGroup` | Related toolbar controls need contained, borderless, pressed, or single-control treatment. | Do not use it merely to align unrelated buttons; use toolbar slots or ordinary layout. Web Awesome `wa-button-group` is only for an exceptional grouped-action contract. | Delegate child actions; use `SegmentedControl` for an exclusive choice. | Actions, pressed/expanded state, and policy. | `@kerfjs/ui/toolbar-control-group` | [Component ownership](./component-contract.md#ownership-boundaries) |
67
- | Floating controls over content — `FloatingToolbar` | A small cluster of controls (e.g. a drawer restore) must float over scrolling content — distinct and forced-dark — inside a positioned container. | Do not use it for a primary page or panel toolbar (use `Toolbar`), or for anything that must sit above dialogs/overlays — it is not top-layer. | Compose `ToolbarControlGroup`s and delegate their actions; the app owns visibility and position. | Controls, visibility, and position. | `@kerfjs/ui/floating-toolbar` | [Component subpaths](../README.md#component-subpaths) |
68
- | Toolbar identity text — `ToolbarText` | A toolbar needs extra-large (page/panel title), large, default, or compact textual identity. | Plain text is not a heading by default; when a title needs heading semantics pass `headingLevel` (or prefer `PanelHeader`, which forwards it). | Optional `headingLevel` for `role="heading"` + `aria-level`. | Text, heading level, and responsive priority. | `@kerfjs/ui/toolbar-text` | [Toolbar composition](../README.md#component-subpaths) |
69
- | Navigation row — `ListItem` | A pane or navigation area needs a selectable, disabled, dormant-trailing, or multiline action row. | Do not put a control in `trailing`; use `ListActionRow` when the trailing region must be independently interactive. Use an `<a>` for navigation that must retain link behavior, a native `<button>` for an ordinary action, or implement the complete ARIA menu widget. | Delegate its `data-action`; compose inside a `.kui-content` section. Put domain event/drop metadata in `rootAttributes` rather than adding wrapper markup. | Routing, selection, permissions, copy, action handling, and domain `data-*` values. | `@kerfjs/ui/list-item` | [Pane geometry](../README.md#pane-and-content-geometry) |
70
- | Navigation row with trailing action — `ListActionRow` | A full-width row needs a selectable primary action and an independently focusable trailing action. | Use `ListItem` when trailing content is dormant metadata. Do not put controls inside the row's `label`, `icon`, or `trailingActionIcon` SafeHtml slots. Do not use `AppTab` outside tablist semantics or `ToolbarControlGroup` outside a toolbar. | Delegate both action strings; update controlled selection and any popover/context-menu state in the app. | Routing, selection, both action policies, domain metadata, and popover/context-menu behavior. | `@kerfjs/ui/list-action-row` | [Accessibility](./accessibility.md#listactionrow) |
71
- | Navigation section heading — `ListHeader` | A menu section needs a full-width label, semantic count, non-count badge, logical-end action, or real disclosure state. | Do not concatenate counts into `label` or put numeric content in `badge`; use `count` with the localized full phrase in `countLabel`. Do not add a disclosure arrow to navigation that reveals nothing. Do not shrink its 44px action target to the 18px visual. Do not use it as a page, panel, or dialog title; use `PanelHeader`. | Delegate its optional action; the app controls expanded state and revealed content. Toggle mode supplies `DisclosureArrow` unless `actionIcon` replaces it. Use `triggerAttributes` only for domain `data-*` or a native popover relationship. | Section organization, valid count and localized count label, disclosure state and content, non-count badge content, popover target behavior, and policy. | `@kerfjs/ui/list-header` | [Pane geometry](../README.md#pane-and-content-geometry) |
72
- | Application layout composition | A sidebar, main area, inspector, or dialog needs shared toolbar/content/footer and child geometry. | Do not pad the pane shell, wrap child-owned geometry in competing insets, invent unrelated centered measures, or leave an icon-only rail for a hidden pane. | Use `.kui-pane` and one `.kui-pane__content`; add `.kui-content` and `.kui-content-item` as needed. A visible pane owns collapse in its toolbar; move a hidden inline-start pane's restore control to the main toolbar leading edge and an inline-end pane's restore control to its trailing edge. | Layout hierarchy, reading width, scroll ownership, responsive relocation, and pane visibility state. | `@kerfjs/ui/layout.css` | [Pane anatomy](./layout.md#anatomy) |
73
- | Menu composition | Navigation sections need full-size rows and the same content-item geometry as every other pane. | Do not add sidebar-specific wrapper padding, shrink targets to icon size, nest an interactive trailing control in `ListItem`, or use a chevron on a row that does not disclose content. Use ordinary links for a different navigation contract. | Compose `ListHeader`, `ListItem`, and `ListActionRow` in `.kui-content`; use `ListHeader` toggle mode with real controlled content, and use `.kui-content-item` for other surfaces plus a pane footer for toolbar actions. | Information architecture, disclosure content and state, responsive drawer/shell behavior, and token overrides. | `@kerfjs/ui/layout.css` | [Pane geometry](../README.md#pane-and-content-geometry) |
74
- | Resizable application pane — `ResizableRegion`, `clampRegionSize`, `resizeRegionFromPointer` | A controlled split pane needs the Kerf separator, collapse state, pointer plus keyboard resizing, or a product-specific decorative grip. | Do not use it for a static two-column layout; use CSS grid. Prefer it over Web Awesome `wa-split-panel` unless that component's distinct API is required. Keep `handleIcon` noninteractive. | Call `wireResizableRegions` from `@kerfjs/ui/wire-resizable-regions` once and retain its disposer. | Size signal, min/max policy, collapse policy, persistence, and optional decorative handle icon. | `@kerfjs/ui/resizable-region` | [ResizableRegion contract](./accessibility.md#resizableregion) |
75
- | One application tab — `AppTab` | A controlled app tab needs selection, close, drag, leading/trailing anatomy, safe domain metadata, or a product-specific close glyph. | Do not render it alone or use it for a small settings choice; compose in `TabBar`, or use `SegmentedControl`. Keep `closeIcon` noninteractive. | Compose in `TabBar`; let `wireTabBars` manage interaction. Put only domain `data-*` values in `rootAttributes`. | Tab identity, order, selection, close policy, content, and domain metadata values. | `@kerfjs/ui/app-tab` | [Tabs contract](./accessibility.md#tabs) |
76
- | Application tab strip — `TabBar`, `wireTabBars`, `reorderTabs` | Tabs switch page regions and may overflow, close, or reorder. | Do not use it for a compact local view toggle; use `SegmentedControl`. Do not use it for a long choice list; use `Select`. Prefer it over Web Awesome `wa-tab-group`, `wa-tab`, and `wa-tab-panel` for Kerf app tabs. | Call `wireTabBars` once, retain the disposer, and apply `onReorder` synchronously; `reorderTabs` is the default array helper. | Ordered tabs, selection, panels, routing, closing, and persistence. | `@kerfjs/ui/tab-bar` plus `@kerfjs/ui/wire-tab-bars` | [Tabs contract](./accessibility.md#tabs) |
77
- | Panel, dialog, or page heading — `PanelHeader` | A panel, dialog, or page needs a heading with an extra-large title, an optional icon and subtitle, and trailing actions. | Do not use it as persistent app chrome; use `Toolbar`. It supplies header structure, not modal behavior; use an application overlay or Web Awesome `wa-dialog` for that behavior. | Connect the title id and any provided summary id to the dialog or panel host, pass the trailing controls (typically a `ToolbarControlGroup`), and delegate their actions. **For a page or view title set `headingLevel` (usually `1`)** so the title is a real heading landmark (`role="heading"` + `aria-level`) for screen-reader heading navigation; omit it for a dialog title, which is referenced via `aria-labelledby` to `titleId` and needs no heading. | Open state, focus lifecycle, dismissal, the trailing controls, labels, copy, and the heading level for page use. | `@kerfjs/ui/panel-header` | [Header ownership](./component-contract.md#extracted-versus-application-specific) |
78
- | Key/value facts — `ValueTable`, `ValueTableRow` | Read-only labels and values form a semantic definition list, optionally with a leading icon. | Do not use it for editable form fields or a row/column data grid; use native form or table semantics. | Compose typed `ValueTableRow` entries; pass `icon` when a 24px leading icon adds useful context. | Values, formatting, icon meaning, and empty/loading policy. | `@kerfjs/ui/value-table` | [Component ownership](./component-contract.md#ownership-boundaries) |
79
- | Indeterminate activity — `LoadingSpinner` | A Kerf surface needs compact, labeled or decorative indeterminate progress. | Do not use it for known progress; use Web Awesome `wa-progress-bar` or `wa-progress-ring`. Direct Web Awesome UI may use `wa-spinner`; do not mix spinner systems within one surface. | None; pass a label when the spinner conveys status. | Loading lifecycle and adjacent status copy. | `@kerfjs/ui/loading-spinner` | [Accessibility](./accessibility.md#shared-rules) |
80
- | Loading placeholder — `Skeleton` + a component's `placeholder` prop | A value or a whole component is still loading and should hold its space as a subtle, unanimated block, keeping the layout stable — an inspector or detail view rendering its real chrome with per-record values absent. | Do not use it for known progress (use `LoadingSpinner`), do not animate it, and do not hand-rebuild a component's empty state — set `placeholder` on the component instead. Prefer it over `wa-skeleton`, which the pure-Kerf primitives avoid to stay Web-Awesome-free. | Set `placeholder` on a value-bearing component (`Select`, `ListHeader`, `ListItem`, `ValueTableRow`, `PanelHeader`, `SegmentedControl`, `StateBanner`, `AppTab`, `ToolbarText`, `ListActionRow`) to render skeletons in its value slots with interactivity disabled; use the standalone `Skeleton` for a custom slot. | Loading lifecycle, which slots are unknown, and announcing the loading region. | `@kerfjs/ui/skeleton` | [Accessibility](./accessibility.md#shared-rules) |
81
- | Value selection — `Select` | A controlled form value comes from a moderate or long choice list, possibly grouped or icon-bearing. | Do not use it for commands; use a real action menu. Do not use it for a small visible choice set; use `SegmentedControl`. Prefer it over direct `wa-select`, `wa-option`, or value-like `wa-dropdown`/`wa-dropdown-item` composition. | Import `@kerfjs/ui/select/register` once; listen for standard input/change events. | Controlled value, validation, choices, and domain mapping. | `@kerfjs/ui/select` | [Web Awesome integration](../README.md#web-awesome-theme) |
82
- | Small exclusive choice — `SegmentedControl` | A few visible choices switch a compact view or setting, with toolbar, rounded, or pill presentation. | Do not use it for tabpanel semantics; use `TabBar`. Do not use it for many choices; use `Select`. Prefer it over `wa-button-group` when the controls select one value. | Delegate its action, read `data-segment-value`, update `value`, and rerender. | Controlled value, labels, action, and persistence. | `@kerfjs/ui/segmented-control` | [SegmentedControl contract](./accessibility.md#segmentedcontrol) |
83
- | Structured search editor — `TokenSearchField`, `readTokenSearchField`, `placeTokenSearchCaret`, `wireTokenSearchFields` | Free text and ordered, editable, removable filter tokens share one searchbox; enable `collapsible` when an empty, unfocused field should reduce to one iconic action, standalone or in a toolbar group. | Do not use it for ordinary text entry; use a native input or Web Awesome `wa-input`. Do not use it when filters belong in separate form controls. | Read DOM-owned text on input, empty `textContent` on clear, and use `placeTokenSearchCaret` after explicit controlled focus changes. Call `wireTokenSearchFields` from `@kerfjs/ui/wire-token-search-fields` once so Enter submits without adding a line break and keyboard chip deletion restores focus plus the text-relative caret after controlled replacement. In `collapsible` mode it also manages the transient expand/collapse/focus by default (activate to reveal + focus, Escape or empty blur to collapse); bind the field's `expanded` to the signal on the returned handle (`handle.expanded(id)`) or adopt your own via `collapsible.signals`, and opt out per behavior only when the app must own it. | Parsing, suggestions, tokens, query execution, results, announcements, and — only if overriding the default — the collapsible `expanded` signal. | `@kerfjs/ui/token-search-field` | [TokenSearchField contract](./accessibility.md#tokensearchfield) |
84
- | Persistent inline status — `StateBanner` | A neutral, info, success, warning, or danger message belongs next to the affected work. | Do not use it for a no-content screen; use `EmptyState`. Do not use it for transient confirmation; use a toast. Web Awesome `wa-callout` is the ecosystem alternative for Web Awesome-owned content. | Delegate an optional action; choose alert urgency only for attention-requiring failure. | State mapping, message lifetime, retry/action behavior, and copy. | `@kerfjs/ui/state-banner` | [Feedback accessibility](./accessibility.md#shared-rules) |
85
- | Empty or busy content area — `EmptyState` | A content region has no items, cannot proceed, or is loading and needs explanation plus an optional action. | Do not use it for an inline status update; use `StateBanner`. Do not use it for transient success; use `wa-toast`/`wa-toast-item` or the application's toast system. | Delegate its optional action; it composes `LoadingSpinner` when busy. | Empty/busy policy, recovery action, illustration, and copy. | `@kerfjs/ui/empty-state` | [Feedback ownership](./component-contract.md#extracted-versus-application-specific) |
242
+ For a read-only or click-to-edit field preview, use `FieldLabel` from
243
+ `@kerfjs/ui/text` above the preview instead of a `ListHeader`. It matches the
244
+ themed Web Awesome form-control label. Put it in `ListInsetControl sides="trl"`
245
+ beside a `ContentItem` value, and connect its id to the preview group's
246
+ `aria-labelledby`; see [Field labels](./layout.md#text).
247
+
248
+ | Interface need | Use when | Do not use when; nearest alternative | Required wiring | Application owns | Import | Recipe |
249
+ | ----------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
250
+ | Icon — `LucideIcon` | A decorative or explicitly labeled Lucide-compatible icon belongs in app UI. | Do not use an icon as the only name of an unfamiliar action; add visible or accessible text. Prefer it over Web Awesome `wa-icon`. | None. | Icon choice and meaningful label. | `@kerfjs/ui/lucide-icon` | [Accessibility](./accessibility.md#shared-rules) |
251
+ | Compact metadata — `Badge` | A short status, count, category, or metadata label needs self-owned visual treatment configured by semantic props. | Do not use it as a button, link, or removable chip. Do not restyle consuming-component descendants to create a badge. | Choose `tone`, `appearance`, `shape`, and `size`; supply `label` for abbreviated content or `ariaHidden` when a surrounding component already owns the same accessible text. For new content without a count use the text-free `size="dot"`, which requires `label` or `ariaHidden`. Set `maxWidth` to truncate long app-supplied text with an ellipsis and a hover `title`. | Metadata text, semantic tone mapping, and abbreviated-content labeling. | `@kerfjs/ui/badge` | [Component ownership](./component-contract.md#ownership-boundaries) |
252
+ | Disclosure indicator — `DisclosureArrow` | A control needs one animated 18px root-scaled visual for open and closed state, including configurable directions or a replacement icon. | Do not use it as the interactive control or accessible name; place it inside the button or control that exposes expanded state. | Pass the controlled `open` state, render it inside the owning control, author replacement icon content facing right before transforms, and override `--kui-disclosure-arrow-size` only when another visual size is required. Direction changes use the shortest rotation path, with counterclockwise chosen for a 180-degree closed-to-open tie. | Open state, interaction, accessible name, size override, replacement glyph, direction choices, and shortest-path rotation. | `@kerfjs/ui/disclosure-arrow` | [Component ownership](./component-contract.md#ownership-boundaries) |
253
+ | Application toolbar or heading — `Toolbar` | Leading identity, optional centered content, and trailing controls form one horizontal app bar or a page/panel/dialog heading. | Do not add bespoke heading geometry or a private wrapper; use the same zone contract everywhere. | Put identity/title text directly in a zone as `ToolbarText`; group controls and icon tiles in `ToolbarControlGroup`. | Actions, command availability, responsive relocation, state, and supporting copy below a heading. | `@kerfjs/ui/toolbar` | [Toolbar composition](../README.md#component-subpaths) |
254
+ | Toolbar control cluster — `ToolbarControlGroup`, `ToolbarActionLink` | Related toolbar buttons, semantic links, compact/tight controls, avatar actions, or a dropdown trigger/menu surface need one configured chrome contract. | Do not use it merely to align unrelated controls. Do not restyle anchors or dropdown parts in application CSS; use `ToolbarActionLink`, `overflow`, and `menuInset`. Web Awesome `wa-button-group` is only for an exceptional grouped-action contract. | Delegate child actions; use `ToolbarActionLink` for native navigation, `overflow="scroll"` for bounded action rows, and `menuInset` for dropdown surface padding. Use `avatarImage` instead of inserting an `img`; use `SegmentedControl` for an exclusive choice. | Actions, destinations, pressed/expanded state, content, and policy. | `@kerfjs/ui/toolbar-control-group` | [Component ownership](./component-contract.md#ownership-boundaries) |
255
+ | Floating controls over content — `FloatingToolbar` | A small cluster of controls (e.g. a drawer restore) must float over scrolling content — distinct and forced-dark — inside a positioned container. | Do not use it for a primary page or panel toolbar (use `Toolbar`), or for anything that must sit above dialogs/overlays — it is not top-layer. | Compose `ToolbarControlGroup`s and delegate their actions; the app owns visibility and position. | Controls, visibility, and position. | `@kerfjs/ui/floating-toolbar` | [Component subpaths](../README.md#component-subpaths) |
256
+ | Toolbar identity text — `ToolbarText` | A toolbar needs extra-large (page/panel title), large, default, or compact textual identity. | Plain text is not a heading by default; when a title needs heading semantics pass `headingLevel`. Sizes below `xlarge` are intentionally quiet identity text in default tone — do not use them as a normal-color subsection title; use `Text` with an `h2`–`h6` variant, or `ListHeader` for a list section. | Optional `headingLevel` for `role="heading"` + `aria-level`. Defaults to one line, ellipsized when it does not fit; `wrap` flows onto multiple lines, `ellipsis` toggles the trailing …, and `maxLines` caps a wrap. | Text, heading level, overflow behavior, and responsive priority. | `@kerfjs/ui/toolbar-text` | [Toolbar composition](../README.md#component-subpaths) |
257
+ | Semantic block or inline text — `Text` | Ordinary application copy needs native `h1`–`h6` or `p` semantics plus standard geometry, or inline secondary copy needs a native `span` without box geometry. | Do not choose heading levels for appearance alone or recreate muted, error, small, or code utility classes. Use `ToolbarText` for toolbar identity/title content and `ListInsetText` when list-aligned prose needs full margin/border/padding geometry. | Omit `variant` for the default `p`, choose `h1`–`h6` from the document outline, or choose `span` inside a row, label, or table cell. Independently compose `tone="quiet | danger"`, `size="compact"`, and `font="monospace"`; ordinary native global, `data-_`, and `aria-_` attributes pass through. | Copy, localization, semantic variant, presentation roles, and document heading hierarchy. | `@kerfjs/ui/text` | [Text](./layout.md#text) |
258
+ | Vertical stack — `List` | Rows, sections, or arbitrary components need a consistent vertical stretch layout, optional standard/custom gap, flex growth, one vertical scroll owner, or edge dividers. | It is layout-only and does not provide `ul`/`ol` semantics. Do not nest scroll owners or use it when a horizontal layout is required. | Choose `gap`, `flex`, `scrollable`, and canonical `dividerSides` (`t`, `r`, `b`, `l` combinations in that order); bound the block size when scrolling. | Child semantics/content, containing height, and which optional layout behaviors apply. | `@kerfjs/ui/list` | [Pane geometry](../README.md#pane-and-content-geometry) |
259
+ | Equal-width columns — `Grid` | Equal-width sibling columns need a fixed count or should collapse as their container narrows, while preserving equal tracks despite intrinsic child widths. | Do not use it for intrinsic, asymmetric, spanning, or masonry tracks; use application-owned CSS grid. Do not use it for a user-operable separator; use `ResizableRegion`. | Choose fixed `columns` or typed `minColumnWidth`, plus typed `gap`, optional `flex`, and physical-side `textInsets` / `controlInsets` when the track group needs a standard text or control inset; text wins on overlap. | Child semantics/content, outer width, fixed count or minimum width, and typed gap/flex/inset choices. | `@kerfjs/ui/grid` | [Grid](./layout.md#grid) |
260
+ | Board of columns — `ColumnTrack` | A board shows parallel columns (kanban lanes) that must keep a readable width and scroll sideways, or page one at a time on a phone. | Do not use it for a wrapping responsive grid; use `Grid`. Do not use it for two resizable panes; use `SplitView`. Do not re-track a `Grid` from app CSS. | Pass columns as children (each owns its inset and vertical scroll); set `minColumnWidth` (default 250px) or `layout="paged"` with an optional `peek` for phones. Name it with `rootAttributes`. | Columns, their content, the layout choice per device, and drag and drop. | `@kerfjs/ui/column-track` | [Feedback accessibility](./accessibility.md#shared-rules) |
261
+ | Two contents swapped in place — `ContentSwap` | A region swaps between two contents in place, such as a dialog's two steps or a footer's changing actions, and the change should read as motion. | Do not use it for full views with toolbars; use `NavStack`. Do not hand-roll stacked cells, inert handling, or push keyframes. | Set `active` to `a` or `b`, `transition` (`push`, `crossfade`, `none`) and the push `direction`; pass `label` to name it and `slot`/`fill` for a dialog label or footer. | The active side, the direction, both contents, and the region name. | `@kerfjs/ui/content-swap` | [Feedback accessibility](./accessibility.md#shared-rules) |
262
+ | Navigation row — `ListItem` | A pane or navigation area needs a selectable, disabled, dormant-trailing, or multiline action row. | Do not put a control in `trailing`; use `ListActionRow` when the trailing region must be independently interactive. Use an `<a>` for navigation that must retain link behavior, a native `<button>` for an ordinary action, or implement the complete ARIA menu widget. | Delegate its `data-action`; compose inside a `.kui-content` section. Put domain event/drop metadata in `rootAttributes` rather than adding wrapper markup. The rounded root clips overflowing descendants; set `multiline` when the primary label should wrap. | Routing, selection, permissions, copy, action handling, and domain `data-*` values. | `@kerfjs/ui/list-item` | [Pane geometry](../README.md#pane-and-content-geometry) |
263
+ | Navigation row with trailing action — `ListActionRow` | A full-width row needs a selectable primary action and an independently focusable trailing action. | Use `ListItem` when trailing content is dormant metadata. Do not put controls inside the row's `label`, `icon`, or `trailingActionIcon` SafeHtml slots. Do not use `TabBarItem` outside tablist semantics or `ToolbarControlGroup` outside a toolbar. | Delegate both action strings; update controlled selection and any popover/context-menu state in the app. | Routing, selection, both action policies, domain metadata, and popover/context-menu behavior. | `@kerfjs/ui/list-action-row` | [Accessibility](./accessibility.md#listactionrow) |
264
+ | Navigation section heading — `ListHeader` | A menu section needs a full-width label, semantic count, non-count badge, logical-end action, or real disclosure state. | Do not concatenate counts into `label` or put numeric content in `badge`; use `count` with the localized full phrase in `countLabel`. Do not add a disclosure arrow to navigation that reveals nothing. Keep its 44px hit target; do not resize its 36px square. Do not use it as a page, panel, or dialog title; use a heading `Toolbar`. | Delegate its optional action; the app controls expanded state and revealed content. Toggle mode supplies `DisclosureArrow` unless `actionIcon` replaces it. Use `triggerAttributes` only for domain `data-*` or a native popover relationship. | Section organization, valid count and localized count label, disclosure state and content, non-count badge content, popover target behavior, and policy. | `@kerfjs/ui/list-header` | [Pane geometry](../README.md#pane-and-content-geometry) |
265
+ | Inset self-bordered control — `ListInsetControl` | A control that owns its own border and padding but no outer margin (a search input, a `SegmentedControl`) must line up inside a `.kui-content` list with the standard 8px inline margins and stretch to fill the row. | Do not wrap a `.kui-content-item` or a `ListItem`/`ListHeader` that already owns its inline margin — that double-insets it. Do not add ad-hoc `margin`/`padding` around a bare control to align it; use this instead. | Place the self-bordered control(s) as children; they stretch to fill. It applies only the inline margin, flex stretch, and 8px gap — the child owns its own border and padding. | The control(s), their state, and action wiring. | `@kerfjs/ui/list-inset-control` | [Pane geometry](../README.md#component-subpaths) |
266
+ | Inset bare text — `ListInsetText` | A plain string or inline content with no margin, border, or padding of its own must sit in a `.kui-content` list with its text edge aligned to the bordered items around it. | Do not use it to wrap a component that already owns content-item geometry (`ListItem`, `StateBanner`, a `.kui-content-item`) — that double-insets it. Do not hand-roll the 8px margin / 1px border / 8px padding. | Pass the text or inline `SafeHtml` as children; it supplies the 8px inline margin, 1px transparent border, and 8px padding so the text edge lands at the standard 17px inset. Pass `sides="rl"` to keep that horizontal inset but drop the vertical margin, border, and padding for tight text layout. | The text, copy, and localization. | `@kerfjs/ui/list-inset-text` | [Pane geometry](../README.md#component-subpaths) |
267
+ | Self-contained content child — `ContentItem` | An ordinary surface-like child of a `Pane` or `.kui-content` stack needs the shared 8px margin / 1px border / 8px padding geometry; pass `frame="framed"` only when it marks a real distinction, `appearance="surface"` or a semantic appearance for coordinated surface colors, and `shape="pill"` for the 22px radius. | Do not wrap a component that already owns content-item geometry (`ListItem`, `ListHeader`, `StateBanner`, `Toolbar`, `ValueTable`) or pad around it — that double-insets. Do not frame an item only to make it look contained. Use `SunkenPanel` for a lowered inset stack and `ListInsetText` for bare text that only needs to align. | Pass the item content as children; choose `appearance` (`transparent` default, `surface`, or a semantic status), `frame`, and `shape` instead of writing CSS. Put safe `data-*` metadata in `rootAttributes`; `ariaLabel` names a distinct region and `focusTarget` makes it a programmatic focus target. | The content, surface or status appearance, and whether it marks a distinction worth a visible frame. | `@kerfjs/ui/content-item` | [Content items](./layout.md#content-items) |
268
+ | Application column — `Pane` | A sidebar, main area, inspector, or dialog needs shared vertical header/content/footer organization, one scroll owner, and optional edge separators. | Do not pad the pane shell, wrap child-owned geometry in competing insets, invent unrelated centered measures, or leave an icon-only rail for a hidden pane. | Import `Pane`, use `children` for its homogeneous primary content and the named `SafeHtml` prop slots `header`/`footer` for optional fixed chrome, then opt into only the needed logical-edge separators; add `ContentItem` children as needed. On compact devices set `compactChrome` (`scroll` or `overlay`) through the container's `pane` configuration, and call `wirePaneChrome(root, { header, footer })` from `@kerfjs/ui/wire-pane-chrome` so open overlay chrome closes on Escape or an outside press. A visible pane owns collapse in its toolbar; move a hidden inline-start pane's restore control to the main toolbar leading edge and an inline-end pane's restore control to its trailing edge. | Layout hierarchy, reading width, responsive relocation, pane visibility state, slot semantics, labels, and separator placement. | `@kerfjs/ui/pane` | [Pane anatomy](./layout.md#anatomy) |
269
+ | Scroll dividers — `wireScrollDividers` | Pinned chrome (a `Pane` header or footer, a `NavStack` top chrome or bottom toolbar, a `TabNavigator` bar, the sides of a `TabBar` strip, or app-owned chrome around a scroller) needs a divider only while content is scrolled away beneath it. | Do not keep a static toolbar divider to fake it or write a border onto another component; each component draws its own line from the wiring's state. | Call `wireScrollDividers` once at the app root and retain the disposer; it covers every `Pane`, `NavStack`, `TabNavigator`, and `TabBar` below it. Name app-owned arrangements in `targets` by id; a `Toolbar` or `List` named as chrome draws its facing side. Configure a pane with `chromeDividers` (`scroll` default, `always`, `none`). | Which panes follow the scroll, app-owned targets, and the disposer. | `@kerfjs/ui/wire-scroll-dividers` | [Scroll dividers](./layout.md#scroll-dividers) |
270
+ | Keyboard focus scroll in scrollable Lists — `wireListFocusScroll` | Rows of a `scrollable` List are reached by keyboard (Tab, or the app's own arrow-key focus moves) and must come fully into view, focus ring included, in Firefox and Safari too: their `focus()` leaves a partly hidden row clipped. | Do not call `scrollIntoView` from app focus handlers or style the List; do not wire it for pointer-only lists. | Call `wireListFocusScroll(root)` once at the app root and retain the disposer. On keyboard (`:focus-visible`) focus inside a `scrollable` List it scrolls the focused element into view only when its ring crosses the clip; pointer focus is left alone. | The disposer. | `@kerfjs/ui/wire-list-focus-scroll` | [Framed result pickers](./layout.md#framed-result-pickers) |
271
+ | One-pane navigation — `NavStack` | A compact flow pushes into details while keeping earlier views mounted, or a single-pane screen needs the same stable layout contract. | Do not use it when list and detail should remain visible together; use `SplitView`. Do not use it alone for co-equal top-level destinations; use one stack per `TabNavigator` tab. | Keep the ordered view array controlled, put view-specific bottom chrome on each view (or use the component fallback), import its CSS explicitly, and call `wireNavStack` for back delegation, content-slide/chrome-cross-fade transitions, and focus move/restore. Mark a preferred initial target with `data-nav-focus` when DOM order is insufficient. | View keys/content/titles, push and pop actions, preferred initial focus targets, and per-view or persistent bottom toolbar content. | `@kerfjs/ui/nav-stack` | [App-layout decision matrix](./app-layouts.md#decision-matrix) |
272
+ | Responsive list-detail — `SplitView` | A primary list and related detail belong together on roomy devices but become a one-pane drill-down on compact devices. | Do not use it for a single linear flow or a multi-panel editor shell. | Provide controlled selection/detail state and device class; opt into resize wiring only when the separator is user adjustable. | Selection, detail content, compact back action, device policy, and optional persisted width. | `@kerfjs/ui/split-view` | [App-layout decision matrix](./app-layouts.md#decision-matrix) |
273
+ | Compact top-level destinations — `TabNavigator` | A handset or portrait-tablet app has two to five co-equal destinations whose scenes and nested navigation must remain mounted across switches. | Do not use it for document tabs, reorderable work items, or a desktop navigation rail. | Keep the active id controlled, import its CSS explicitly, and call `wireTabNavigator`; commonly place one `NavStack` in each tab scene. | Destination definitions, active id, routing, persistence, and roomy-device replacement. | `@kerfjs/ui/tab-navigator` | [App-layout decision matrix](./app-layouts.md#decision-matrix) |
274
+ | Desktop multi-panel workspace — `Workbench` | A desktop-class tool needs a central work area plus independently collapsible navigator, inspector, or console regions. | Do not shrink the full shell onto compact devices or use it for one standalone panel. | Render only the required rails/drawer, keep collapse state controlled, and replace peripheral regions with stacks or overlays below desktop sizes. Opt a panel into drag/keyboard resizing with `resizable` and call `wireWorkbench` with its size signal. | Panel presence/content, collapsed states, sizes, persistence, responsive replacement, and controls. | `@kerfjs/ui/workbench` | [Workbench](./workbench.md) |
275
+ | Standalone rail or drawer — `CollapsiblePanel` | One left/right rail or bottom drawer needs controlled collapse without adopting the complete `Workbench` shell. | Do not use it for several coordinated workspace panels or retain an empty icon-only rail while collapsed. | Pair it with `CollapsiblePanelToggle`; call `wireSidebar` for focus transfer, Escape/backdrop dismissal, compact overlay trapping, and persistence integration. | Panel content/size, collapsed state, toggle placement, persistence, and compact policy. | `@kerfjs/ui/collapsible-panel` | [App-layout decision matrix](./app-layouts.md#decision-matrix) |
276
+ | Lowered content surface — `SunkenPanel` | A main work area or nested content group needs one visually lowered surface with a compact inset and vertical stack. | Do not use it merely to add padding, as a replacement for `Pane` anatomy, or around children that already own the same outer surface. | Compose the application-owned content as children, choose the default `rounded` shape or `square` for a flush edge-to-edge area, and pass `ariaLabel` only when the surface is a distinct named region. Every sunken surface carries a fine grain texture, generated once per page by the first one that renders; call `ensureSunkenTexture` only when the page paints Web Awesome `appearance="sunken"` without any Kerf sunken component, and set `--kui-sunken-texture: none` at `:root` for a flat surface. | Region semantics, accessible name, shape, scroll ownership, child ordering, and content. | `@kerfjs/ui/sunken-panel` | [SunkenPanel](./sunken-panel.md) |
277
+ | Scrolling view's hero image — `BackdropImage` | A scrolling `Pane` or `NavStack` view opens with a mood or identity image (an artist, album, or place page) that should lag the scroll, dissolve into a color, and read as one surface with the content below. | Do not use it for inline content images, thumbnails, or avatars. Do not hand-roll scroll listeners, `background-attachment: fixed`, or mask gradients. Do not use it outside a vertical scroller; parallax needs one. | Place it first in the scrolling content. Pass `src`, `alt` (`""` for decoration), optional `srcset`/`sizes`, `fit`/`position` or a tiled `repeat`, a typed `height`, `parallax` (`none`, `subtle`, or a 0 to 1 factor), `blur` (`radius`, `blurredSrc`, `dim`) for a progressive blur, a typed `fadeTo` color that also paints below, a `scrim` for overlay text, `overlay` content over its block end, and `children` below. Kerf owns the scroll-driven, compositor-only parallax and its static fallbacks. | The image and alt text, the fade color, overlay content and its contrast, and the content below. | `@kerfjs/ui/backdrop-image` | [BackdropImage](./backdrop-image.md) |
278
+ | Menu composition | Navigation sections need full-size rows and the same content-item geometry as every other pane. | Do not add sidebar-specific wrapper padding, shrink targets to icon size, nest an interactive trailing control in `ListItem`, or use a chevron on a row that does not disclose content. Use ordinary links for a different navigation contract. | Compose `ListHeader`, `ListItem`, and `ListActionRow` in `.kui-content`; use `ListHeader` toggle mode with real controlled content, and use `ContentItem` for other surfaces plus a pane footer for toolbar actions. | Information architecture, disclosure content and state, responsive drawer/shell behavior, and token overrides. | `@kerfjs/ui/layout.css` | [Pane geometry](../README.md#pane-and-content-geometry) |
279
+ | Resizable application pane — `ResizableRegion`, `clampRegionSize`, `resizeRegionFromPointer` | A controlled split pane needs the Kerf separator, collapse state, pointer plus keyboard resizing, or a product-specific decorative grip. | Do not use it for static equal columns; use `Grid`. Use application CSS grid for static asymmetric or intrinsic tracks. Prefer it over Web Awesome `wa-split-panel` unless that component's distinct API is required. Keep `handleIcon` noninteractive. | Call `wireResizableRegions` from `@kerfjs/ui/wire-resizable-regions` once and retain its disposer. | Size signal, min/max policy, collapse policy, persistence, and optional decorative handle icon. | `@kerfjs/ui/resizable-region` | [ResizableRegion contract](./accessibility.md#resizableregion) |
280
+ | One application tab — `TabBarItem` | A controlled app tab needs selection, close, drag, leading/trailing anatomy, compact/segmented/icon-only presentation, label truncation, safe domain metadata, or a product-specific close glyph. | Do not render it alone or use it for a small settings choice; compose in `TabBar`, or use `SegmentedControl`. Keep `closeIcon` noninteractive. | Compose in `TabBar`; let `wireTabBars` manage interaction. Put only domain `data-*` values in `rootAttributes`; use typed appearance props instead of descendant CSS. | Tab identity, order, selection, close policy, content, domain metadata values, and outer placement. | `@kerfjs/ui/tab-bar-item` | [Tabs contract](./accessibility.md#tabs) |
281
+ | Application tab strip — `TabBar`, `wireTabBars`, `reorderTabs` | Tabs switch page regions and may overflow, close, reorder, fill a segmented inspector strip, sit beside a trailing action, or keep that adjacent action distinct from a far-edge end action. | Do not use it for a compact local view toggle; use `SegmentedControl`. Do not use it for a long choice list; use `Select`. Prefer it over Web Awesome `wa-tab-group`, `wa-tab`, and `wa-tab-panel` for Kerf app tabs. | Call `wireTabBars` once, retain the disposer, and apply `onReorder` synchronously; `reorderTabs` is the default array helper. Combine `trailingPlacement="adjacent"` with `end` for split actions; TabBar owns the shrinking/scrolling tab geometry and keeps both actions visible. Choose typed presentation/allocation props while the parent owns outer placement. | Ordered tabs, selection, panels, routing, closing, persistence, action content, and outer placement. | `@kerfjs/ui/tab-bar` plus `@kerfjs/ui/wire-tab-bars` | [Tabs contract](./accessibility.md#tabs) |
282
+ | Panel, dialog, or page heading — `Toolbar` + `ToolbarText` | A panel, dialog, or page needs an extra-large title, optional icon, grouped trailing actions, and optional supporting copy. | Do not add a private heading wrapper or bespoke layout. The toolbar supplies structure, not modal behavior; use `DialogSurface` or a `kerfjs/overlay` dialog for that behavior. In a narrow peripheral rail or drawer, where xlarge would truncate at the panel's minimum size, use the default `ToolbarText` size as pane identity. | Connect title/supporting-copy ids to the host, group controls, and delegate actions. **For a page or view title set `headingLevel` (usually `1`)** on `ToolbarText`; omit it for a dialog title referenced by `aria-labelledby`. | Open state, focus lifecycle, dismissal, controls, ids, copy, and heading level. | `@kerfjs/ui/toolbar` + `@kerfjs/ui/toolbar-text` | [Toolbar headings](./accessibility.md#toolbar-headings) |
283
+ | Modal dialog, dialog or popup geometry — `DialogSurface`, `openDialog`, `closeDialog`, `PopoverDialogSurface`, `PopupSurface` | A task must block the page in a modal dialog with standard sizes/presentations/body/footer insets, typed modal viewport bounds, a definite height, or a body one child fills; a dialog must stay non-modal and light-dismiss; or a raw dropdown menu needs list-compatible inset ownership. | Do not use these surfaces as generic layout. Do not toggle a `DialogSurface`'s `open` attribute (that opens it non-modally), avoid consumer `::part()` or descendant overrides, and do not stack a dialog body inset around list-owned child geometry. | Render `DialogSurface` with a `label` (or `labelledBy` plus a `heading`), the body as children, and its buttons as `footer`; open it with `openDialog()` and close it with `closeDialog()`, its close button, or a `data-dialog-close` element, and cancel `kui-request-close` to keep it open. Compose a dialog body as a `List` by default, use `bodyInset="none"` when its children own list geometry, and wrap bare prose in `ListInsetText`. Set `height` with `bodyLayout="fill"` when one `SplitView` or `Pane` should fill the body. For a non-modal, light-dismiss dialog render `PopoverDialogSurface` (native `popover="auto"`, opened by a `popoverTarget` control or `showPopover()`), never a hand-built popover with app chrome CSS; `presentation="embedded"` shows it in flow. Wrap a raw `wa-dropdown` in `PopupSurface` for its menu inset. | Open state, whether a close may proceed, dismissal policy, names, content, and outer placement. | `@kerfjs/ui/surface-scaffold` | [Surface scaffolds](./surface-scaffold.md) |
284
+ | Modal list-detail — `ListDetailDialog` | A modal task picks one record from a list and shows its detail beside it, with the dialog's title, actions, and close control belonging to the detail. | Do not use it for a single-pane dialog; use `DialogSurface`. Do not wrap a `SplitView` in a `DialogSurface` by hand for this layout: the surface header spans both columns and stops the divider below it. | Pass `list` (`title`, `toolbar`, `content`, `footer`, `width`) and `detail` (`title`, `description`, `actions`, `content`, `footer`); open it with `openDialog()`; pass `compact` from `deviceClass()` and `detailActive` for the compact drill-down, and pop on `nav-back`. | Open state, selection, the pushed detail, device policy, content, and record actions. | `@kerfjs/ui/list-detail-dialog` | [ListDetailDialog](./list-detail-dialog.md) |
285
+ | Modal workbench — `WorkbenchDialog` | A modal editing task needs a work area with side panels (layers, an inspector) whose rails overlay the work area on compact devices. |
286
+ | Show and hide content — `Disclosure` | Optional or advanced content should stay one press away under a summary (advanced settings, a build log), or several sections should open one at a time. | Do not use it to switch peer views (use `SegmentedControl` or `TabBar`) or for a collapsible rail (use `CollapsiblePanel`). Do not hand-build a details element with its own marker CSS. | Render `Disclosure` with a `title`, an optional `detail`, and content that draws no inset of its own; give Disclosures the same `name` for an accordion; pick `appearance` `plain`, `framed`, or `sunken`, or `embedded` inside a `ContentItem` that already owns the inset (no margin, border, or padding of its own, a compact summary row, and `flush` `Text` content). The open state is native: close it from code with `element.open = false`, and listen for the captured `toggle` event through `toggleAction`. | Title, content, initial open state, group name, and toggle handling. | `@kerfjs/ui/disclosure` | [Disclosure](./disclosure.md) |
287
+ | Core overlay bottom sheet — `@kerfjs/ui/overlay-sheet.css`, `wireOverlaySheets` | A `kerfjs/overlay` `overlay()`, `confirm()`, `prompt()`, `form()`, or `choice()` opened with `presentation: 'bottom-sheet'` should look like a `DialogSurface` sheet, and optionally be resizable by the person. | Do not hand-style `.kerf-overlay` or build a grabber; prefer a `DialogSurface` `presentation="bottom-sheet"` when the dialog is a Kerf `DialogSurface` rather than a core overlay. | Import `@kerfjs/ui/overlay-sheet.css` once. Pass `exitClass: 'kui-overlay-sheet-exit'` for the slide out. For a resizable sheet, add the `kui-overlay-sheet-resizable` class (`className: 'kerf-overlay kui-overlay-sheet-resizable'`) and call `wireOverlaySheets()` once per container sheets open in (`document.body` by default). | Opening, results, content, and which sheets are resizable. | `@kerfjs/ui/overlay-sheet.css`, `@kerfjs/ui/wire-overlay-sheets` | [Core overlay bottom sheets](./surface-scaffold.md#core-dialogs-as-bottom-sheets) |
288
+ | Key/value facts — `ValueTable`, `ValueTableRow` | Read-only labels and values form a semantic definition list, optionally with a leading icon. | Do not use it for editable form fields or a row/column data grid; use native form or table semantics. | Compose typed `ValueTableRow` entries; pass `icon` when a 24px leading icon adds useful context. Set `labelWidth` for a minimum label column, `presentation="stacked"` to put each value under its label, or `stackBelow` (`compact` 512px, `narrow` 576px) to stack only while the table is that narrow; never override `--kui-value-table-row-columns` for these. | Values, formatting, icon meaning, and empty/loading policy. | `@kerfjs/ui/value-table` | [Component ownership](./component-contract.md#ownership-boundaries) |
289
+ | Framed rows of arbitrary content — `FramedList`, `FramedListRow` | Settings rows, account or source cards, or a shortcut list group several rows of copy and controls in one rounded frame with dividers between them. | Do not use it for read-only label/value facts; use `ValueTable`. Do not use it for selectable navigation rows or a bounded result picker; use `List` with `ListItem` (a picker adds `frame`, `scrollable`, and `maxHeight`). Do not pad or border rows from application CSS. | Compose any row content (a `Row` of copy, a keycap, icon-only `Button`s) in each `FramedListRow`; mark the row being edited `highlighted`. Name the list with `label` when no heading does. | Row content, controls, which row is highlighted, and the list's name. | `@kerfjs/ui/framed-list` | [Feedback accessibility](./accessibility.md#shared-rules) |
290
+ | Selectable item summaries — `SummaryRow` | A list or board shows many items as dense, selectable summaries: an identifier and title, a timestamp, and a metadata line (tickets, tasks). | Do not use it for navigation rows; use `ListItem`. Do not use it for free-form selectable tiles; use `ContentItem`. Do not hand-roll row chrome. | Pass `title`, optional `leading`, `trailingMeta`, and `metadata`; choose `presentation` (`row` or `card`), `rail`, `selected`, `dimmed`, `listEdge`, and `titleLines`. Put rows in a labeled `role="listbox"` and own selection and arrow-key focus in the app. | The listbox, selection, keyboard movement, content, rail tone, and dimming. | `@kerfjs/ui/summary-row` | [Feedback accessibility](./accessibility.md#shared-rules) |
291
+ | Color from a fixed palette — `ColorSwatches` | A setting takes one color from a small curated palette (a label, calendar, or command color), or no color. | Do not use it when any color is allowed, or for choices that are not colors (use `ChoiceChips` or `RadioGroup`). | Render `ColorSwatches` with `name`, a `label`, `swatches` (`{ value, label, color }`, `'transparent'` for no color), and `value`; read the choice on `change` through `action`. | The palette and color names, and the chosen value. | `@kerfjs/ui/color-swatches` | [ColorSwatches](./color-swatches.md) |
292
+ | Any color — `ColorPicker`, `wireColorPickers` | Any color is allowed and the person may need precision (a fill, stroke, or brand color), optionally with presets or saved samples. | Do not use it for a small curated palette (use `ColorSwatches`). | Render `ColorPicker` with `id`, `label`, `value`, and `mode`; call `wireColorPickers(root, { onChange })` once and re-render with the reported `value` and `mode`; add `presets`, `samples`, and `addSampleAction` as needed. | The value and model, presets and samples. | `@kerfjs/ui/color-picker`, `@kerfjs/ui/wire-color-pickers` | [ColorPicker](./color-picker.md) |
293
+ | A color in a form — `ColorField`, `wireColorFields` | A form or inspector row sets one color (a fill, border, or theme color) and opens a picker only while it is being changed. |
294
+ | List of short values — `TagField`, `wireTagFields` | A form collects several short values of one kind (labels, recipients, keywords), each submitted as its own value. | Do not use it for search filters (use `SearchField`) or to pick from a short known set (use `ChoiceChips`). | Render `TagField` with `id`, `label`, `tags`, and `name`; call `wireTagFields(root, { onChange })` once and re-render with the reported list; add `max` and a `normalize` for validation, and show `onReject`'s reason as `error`. | The tag list, validation, and error text. | `@kerfjs/ui/tag-field`, `@kerfjs/ui/wire-tag-fields` | [TagField](./tag-field.md) |
295
+ | Value on a range — `Slider`, `wireSliders` | A setting is a value in a known range where position matters more than the exact number (volume, zoom, opacity), optionally with named stops. | Do not use it when the exact number matters (use a numeric `TextField`), for on or off (use `Switch`), or for a few named options (use `SegmentedControl`). | Render `Slider` with `id`, `min`/`max`/`step`, `value`, and a `label`; add `showValue` and `unit` for a readout and `ticks` for stops; listen for `input`/`change` through `action`, and call `wireSliders(root)` once so the fill and readout follow a drag. | The value, range, labels, and re-rendering with the value. | `@kerfjs/ui/slider`, `@kerfjs/ui/wire-sliders` | [Slider](./slider.md) |
296
+ | Measurable progress — `ProgressBar`, `ProgressRing` | A task reports how far it has gone (an upload, a migration, a quota), or work of unknown size is under way. | Do not use them for a brief busy glyph inside a control (use `LoadingSpinner`) or for a scale reading that is not progress (use a native `<meter>`). | `ProgressBar` with `value`/`max`, a `label` (or `ariaLabel`), and `showValue` or `valueText`; omit `value` for the indeterminate sweep. `ProgressRing` (`small`, `medium`, `large`) where a bar does not fit, named by `label`. Pick a `tone` for a status. | Value, max, labels, tone, and size. | `@kerfjs/ui/progress-bar`, `@kerfjs/ui/progress-ring` | [Progress](./progress.md) |
297
+ | Indeterminate activity — `LoadingSpinner` | A Kerf surface needs compact, labeled or decorative indeterminate progress. | Do not use it for known progress; use a native `<progress>` element, or `wa-progress-bar` / `wa-progress-ring` in an application using the Web Awesome integration. Do not mix spinner systems within one surface. | Pass a label when the spinner conveys status; use size for a named icon step or positive pixel size. | Loading lifecycle and adjacent status copy. | `@kerfjs/ui/loading-spinner` | [Accessibility](./accessibility.md#shared-rules) |
298
+ | Loading placeholder — `Skeleton` + a component's `placeholder` prop | A value or a whole component is still loading and should hold its space as a subtle, unanimated block, keeping the layout stable — an inspector or detail view rendering its real chrome with per-record values absent. | Do not use it for known progress (use `LoadingSpinner`), do not animate it, and do not hand-rebuild a component's empty state — set `placeholder` on the component instead. Prefer it over `wa-skeleton`. | Set `placeholder` on a value-bearing component (`Select`, `ListHeader`, `ListItem`, `ValueTableRow`, `SegmentedControl`, `StateBanner`, `TabBarItem`, `ToolbarText`, `ListActionRow`) to render skeletons in its value slots with interactivity disabled; use the standalone `Skeleton` for a custom slot. | Loading lifecycle, which slots are unknown, and announcing the loading region. | `@kerfjs/ui/skeleton` | [Accessibility](./accessibility.md#shared-rules) |
299
+ | Command menu — `PopupMenu` | A short list of commands sits behind one trigger, such as a toolbar sort or More menu, optionally grouped under headings and dividers with item icons. | Do not use it to choose a persistent value; use `Select`. Do not hand-write `wa-dropdown`/`wa-dropdown-item` markup for an action menu. | Import `@kerfjs/ui/popup-menu/register` once. Place it in a `single` `ToolbarControlGroup` with `nestedDropdown` and a `menuInset`, or wrap it in `PopupSurface` outside a toolbar. Handle item `action`s by delegation. | Commands, enabled state, and reactions to opening or closing. | `@kerfjs/ui/popup-menu` | [Toolbar composition](#toolbar-composition) |
300
+ | Standalone action — `Button` | A dialog footer, a form, or content needs an action button with visible text: `tone="brand"` for the main action, `tone="danger"` for a destructive one, and `emphasis="secondary"` or `"plain"` for the quieter actions beside it. A link that looks like a button takes `href`. | Do not use it inside a `ToolbarControlGroup`; give the group plain `<button>`s. For an icon-only action give it an `icon` and `ariaLabel` and no label, and for an on/off toggle set `pressed`; a menu trigger is a `PopupMenu`. | Pass the label as children and delegate its `action`; a form button sets `type="submit"` or `"reset"` (the default `button` never submits) with `name`, `value`, and `form`. `loading` shows a spinner and `aria-busy`; the app decides what a press does meanwhile. `size="compact"` is 33px. In a `Toolbar` trailing zone or a `TabBar` action zone it keeps the control band. Set `focusRingInset` when an ancestor clips overflow: the focus ring moves inside the box, with a surface-colored line inside it so it stays visible on a loud fill. `fill` spans a full-width primary action across its parent's inline width, label centered, as on `SplitButton`. | The label, delegated action, and form ownership. | `@kerfjs/ui/button` | [Feedback accessibility](./accessibility.md#shared-rules) |
301
+ | Icon-only action — `Button` with `icon` and `ariaLabel` | One action is clear from its icon alone and stands by itself or beside a form field, such as Browse next to a path input: give `Button` an `icon` and an `ariaLabel` and no label. |
302
+ | Standalone toggle — `Button` with `pressed` | An on/off control (show a panel or a conversation), icon-only or labeled, sits in content or a pane footer outside any Toolbar: `pressed` reports `aria-pressed` and draws the pressed look on top of the tone and emphasis; `shape="pill"` rounds it. |
303
+ | Primary action with options — `SplitButton` | A prominent primary action has a closely related set of options chosen from an attached trigger, such as Drive with a provider menu; `shape="pill"` rounds both outer ends, as on `Button`. | Do not use it for a plain action; use `Button`. Do not use it for a toolbar command menu; use `PopupMenu`. Do not assemble one from `wa-button-group`, whose hosts do not forward names or `aria-expanded`. | Pass the primary `label` and `action`, the options trigger's `optionsLabel`, `optionsAction`, and `optionsExpanded`; pick a loud `tone`, `fill` for full width, `busy` while work runs, and `disabled`/`optionsDisabled`. Set `focusRingInset` when an ancestor clips overflow, so each half's ring is drawn inside its box. | Both actions, the options menu and its open state, the running state and tone switch, and copy. | `@kerfjs/ui/split-button` | [Feedback accessibility](./accessibility.md#shared-rules) |
304
+ | Choosing or dropping files — `FilePickerTrigger`, `FileDropZone`, `wireFilePickers` | People attach or import files by browsing or by dropping them onto a target. | Do not style a native file input or its label from app CSS. Do not make the drop zone the only way in; it also opens the chooser. | Use `FilePickerTrigger` for a compact Add control and `FileDropZone` for a dashed target; set `accept`, `multiple`, `name`, and `pickerId`. Call `wireFilePickers(root, { onFiles })` once: it reports browsed and dropped files (drops filtered by `accept`, the same check `fileMatchesAccept` exposes) and marks the zone while dragging. | What happens to the files, the chosen-file list, copy, and accepted types. | `@kerfjs/ui/file-picker`, `@kerfjs/ui/wire-file-pickers` | [Feedback accessibility](./accessibility.md#shared-rules) |
305
+ | Value selection — `Select` | A controlled form, toolbar, or compact navigation value comes from a moderate or long choice list, possibly grouped, icon-bearing, icon-only when closed, or truncating. Set `multiple` with an array `value` when the person may choose any number of them; add `selectedPresentation="icon-only"` and a fixed `triggerIcon` for a toolbar filter menu. | Do not use it for commands; use `PopupMenu`. Do not use it for a small visible choice set; use `SegmentedControl`. Prefer it over direct `wa-select`, `wa-option`, or value-like `wa-dropdown`/`wa-dropdown-item` composition. | Import `@kerfjs/ui/select/register` once for registration and current-request animation ownership; listen for standard input/change events. Do not add consumer popup timing or positioning repairs. Use typed presentation props rather than consumer `::part()` overrides; let the parent own placement. | Controlled value, validation, choices, domain mapping, and outer placement. | `@kerfjs/ui/select` | [Web Awesome integration](../README.md#web-awesome-theme) |
306
+ | Free text — `TextField`, `wireTextFields` | A form or dialog collects a line of free text (a name, an address, a title) or a longer note: `label` names it (or `ariaLabel` when nearby content already does), `hint` explains it, and `error` reports a validation problem. `multiline` with `rows` (and `maxRows` to grow) takes a longer note; `maxLength` with `showCount` shows the remaining budget; `icon` and `clearable` suit a filter field. | Do not use it when only existing values are allowed; use `Select`. Do not use it to pick among suggestions or create tags; use `Combobox`. Do not use it for search text with removable filter tokens (`SearchField`) or a message with a send action (`MessageComposer`). Prefer it over `wa-input` and `wa-textarea`. | Call `wireTextFields(root)` once when a field is `clearable` or `showCount`. Read the value from the native `input` or `change` event. | Value, validation and error copy, hint copy, and what a cleared field means. | `@kerfjs/ui/text-field` | [TextField contract](./accessibility.md#textfield) |
307
+ | On/off option — `Checkbox`, `wireCheckboxes`, `Switch` | A form or settings list has an independent yes/no option: `Checkbox` when a form submits it (with `indeterminate` for a parent of partly checked children), `Switch` when the setting applies the moment it changes. | Do not use a `Switch` for an option a form submits later, or a `Checkbox` for an immediate setting. Do not use either for one choice among several (`RadioGroup`); a labeled set of related checkboxes is a `CheckboxGroup`. Prefer them over `wa-checkbox` and `wa-switch`. | Call `wireCheckboxes(root)` once when a `Checkbox` is `indeterminate`. Read `checked` from the native `change` event. Stack several standalone Checkboxes in a `List gap="xs"`: 8px apart, the same 28px pitch as `RadioGroup` choices; a labeled set of options is a `CheckboxGroup`. | Checked and mixed state, validation copy, and what a change does. | `@kerfjs/ui/checkbox`, `@kerfjs/ui/switch` | [Checkbox, RadioGroup, and Switch contract](./accessibility.md#checkbox-radiogroup-and-switch) |
308
+ | One of a few labeled options — `RadioGroup` | A form asks for one of two to about six options that people should compare at a glance, each with a readable label and an optional hint. | Do not use it for a long list (`Select`), a view switch (`SegmentedControl`), or pill or color choices (`ChoiceChips`). Prefer it over `wa-radio-group`. | Read the value from the native `change` event and render `value`. | Value, choices and their copy, and validation. | `@kerfjs/ui/radio-group` | [Checkbox, RadioGroup, and Switch contract](./accessibility.md#checkbox-radiogroup-and-switch) |
309
+ | Several of a few labeled options — `CheckboxGroup` | A form asks for any number of two to about eight related options under one label, each with a readable label and an optional hint, and every checked value submits under one name. | Do not use it for one choice among several (`RadioGroup`), one independent option or a mixed parent (`Checkbox`), an immediate setting (`Switch`), or wrapping pill choices (`ChoiceChips` `multiple`). Prefer it over `wa-checkbox-group`. | Pass the checked values as `value` and read each change from the native `change` event. Its choices stack like `RadioGroup` choices: 8px apart, the same 28px pitch. Validate a minimum or maximum in the app and pass `error`. | Checked values, choices and their copy, and validation. | `@kerfjs/ui/checkbox-group` | [Checkbox, RadioGroup, and Switch contract](./accessibility.md#checkbox-radiogroup-and-switch) |
310
+ | Pick or create a value by typing — `Combobox`, `wireComboboxes` | People type to find an existing value among many or create a new one (tags, labels, recipients). | Do not use it when only existing values are allowed; use `Select`. Do not use it for search text with removable filter tokens; use `SearchField`. Do not style a native input with a datalist. | Pass `id`, `label`, and `suggestions` (strings or `{ value, label }`), plus `placeholder`, `hint`, and `createLabel` (or `false` for suggestions only). Call `wireComboboxes(root, { onCommit })` once; it filters, moves the active option with the arrows, and reports `{ id, value, created, input }` on Enter, a comma, or a click. | Suggestions, committed values, normalization, and clearing the field. | `@kerfjs/ui/combobox`, `@kerfjs/ui/wire-comboboxes` | [Feedback accessibility](./accessibility.md#shared-rules) |
311
+ | Small exclusive choice — `SegmentedControl` | A few visible choices switch a compact view or setting, with toolbar, rounded, or pill presentation. | Do not use it for tabpanel semantics; use `TabBar`. Do not use it for many choices; use `ChoiceChips` when they stay visible and wrap, or `Select` for a long list. Prefer it over `wa-button-group` when the controls select one value. | Delegate its action, read `data-segment-value`, update `value`, and rerender. | Controlled value, labels, action, and persistence. | `@kerfjs/ui/segmented-control` | [SegmentedControl contract](./accessibility.md#segmentedcontrol) |
312
+ | Wrapping visible choice — `ChoiceChips` | Several visible options, too many for one segmented track, must wrap onto more rows — a labeled color palette with swatches, a tag color, a category. Set `multiple` with an array `value` when any number may be on, such as label filters or annotation intents. | Do not use it for a few compact choices on one track; use `SegmentedControl`. Do not use it for a long list or tight space; use `Select`. Do not use it for removable tags (`Chip`). Prefer it over `wa-radio-group` with `appearance="button"` radios, which wrap as a ragged joined group. | Pass a form `name`, a `label` or `labelledBy`, and the controlled `value`; delegate the `action` on `change`, read the radio `value` (or, with `multiple`, the checked boxes under `name`), and rerender. Place it in a dark appearance scope for inverse chrome rather than restyling it. Lead choices with a `swatch` (`CssColor` or `'transparent'`) or an `icon`. | Controlled value, choices, swatch colors, change handling, and form submission. | `@kerfjs/ui/choice-chips` | [ChoiceChips contract](./accessibility.md#choicechips) |
313
+ | Chat or prompt composer — `MessageComposer`, `wireMessageComposers` | A chat message, assistant prompt, or reply is written in a raised frame and sent with a trailing action, often in a `DialogSurface` floating footer over a transcript. | Do not use it for an ordinary form field submitted with the rest of a form; use a `multiline` `TextField`. Do not wrap it in another framed `ContentItem` or card; it owns its frame, padding, and shadow. Prefer it over a textarea and a button in app-styled chrome. | Pass a `name`, a title-style `label`, an `id` when it has a `hint`, and the trailing `actions` (a brand Send `Button`). Bound the growing field with `minRows` and `maxRows`. Read and clear the textarea from the send action. For Enter-to-send, set `submitOnEnter` and call `wireMessageComposers(root)` once; Enter clicks the first trailing action, Shift+Enter is a newline, and IME commits never send. | Value, sending, shortcuts beyond the opt-in Enter-to-send, and the disabled or busy state of its actions. | `@kerfjs/ui/message-composer`, `@kerfjs/ui/wire-message-composers` | [MessageComposer](./message-composer.md) |
314
+ | Structured search editor — `SearchField`, `readSearchField`, `placeSearchFieldCaret`, `wireSearchFields` | Free text and ordered, editable, removable filter tokens share one searchbox; enable `collapsible` when an empty, unfocused field should reduce to one iconic action, standalone or in a toolbar group. | Do not use it for ordinary text entry; use `TextField`. Do not use it when filters belong in separate form controls. | Read DOM-owned text on input, empty `textContent` on clear, and use `placeSearchFieldCaret` after explicit controlled focus changes. Call `wireSearchFields` from `@kerfjs/ui/wire-search-fields` once so Enter submits without adding a line break and keyboard chip deletion restores focus plus the text-relative caret after controlled replacement. In `collapsible` mode it also manages the transient expand/collapse/focus by default (activate to reveal + focus, Escape or empty blur to collapse); bind the field's `expanded` to the signal on the returned handle (`handle.expanded(id)`) or adopt your own via `collapsible.signals`, and opt out per behavior only when the app must own it. | Parsing, suggestions, tokens, query execution, results, announcements, and — only if overriding the default — the collapsible `expanded` signal. | `@kerfjs/ui/search-field` | [SearchField contract](./accessibility.md#searchfield) |
315
+ | Persistent inline status — `StateBanner` | A neutral, info, pop, success, warning, or danger message belongs next to the affected work; pop highlights featured or novel content without implying status. | Do not use pop as a success, warning, or danger substitute. Do not use StateBanner for a no-content screen; use `EmptyState`. Do not use it for transient confirmation; use a toast. In an application using the Web Awesome integration, `wa-callout` is the alternative for Web Awesome-owned content. | Delegate an optional action; choose alert urgency only for attention-requiring failure. Use the optional tone-tinted `badge` for a terse count or status beside the title, not as the only expression of meaning. | State mapping, message lifetime, retry/action behavior, badge content, and copy. | `@kerfjs/ui/state-banner` | [Feedback accessibility](./accessibility.md#shared-rules) |
316
+ | App-level progress in a corner — `CornerStatus`, `wireCornerStatus` | Ongoing app-wide work, such as "Loading…" or "Updating Tickets… 3 of 12", needs a non-dismissible status that has no better home beside the affected work. | Do not use it for transient, dismissible confirmation; use a toast. Do not use it for status that belongs beside the affected work; place a `StateBanner` there. Do not position a `StateBanner` with fixed-position application CSS. | Compose one or more `StateBanner`s with `urgency="status"`; they stack. Call `wireCornerStatus` once so each overlay host opens in the top layer as renders insert it. It never takes focus and has no close button, light dismiss, or Escape. | Status lifetime (render while the work runs, remove when it ends), banner copy and progress, and corner placement. | `@kerfjs/ui/corner-status`, `@kerfjs/ui/wire-corner-status` | [Feedback accessibility](./accessibility.md#shared-rules) |
317
+ | Ambient edge activity — `EdgeActivityIndicator` | App-wide background activity (server work, sync) should be visible along the top edge without a modal, a banner, or a layout shift. | Do not use it for progress the user waits on or must read; use `CornerStatus`. Do not use it for known progress; use a progress bar. Do not make it the only record of important state. | Drive `busy`; pass an optional `message` for a polite status pill and a `tone`. It sits below the top safe area (or flush with `inset="none"`), takes no pointer, and only fades under reduced motion. | The busy state, message, and tone. | `@kerfjs/ui/edge-activity-indicator` | [Feedback accessibility](./accessibility.md#shared-rules) |
318
+ | Empty or busy content area — `EmptyState` | A content region has no items, cannot proceed, or is loading and needs explanation plus an optional action. | Do not use it for an inline status update; use `StateBanner`. Do not use it for transient success; use `toast()` from `kerfjs/overlay` or the application's toast system. | Delegate its optional action; it composes `LoadingSpinner` when busy. | Empty/busy policy, recovery action, illustration, and copy. | `@kerfjs/ui/empty-state` | [Feedback ownership](./component-contract.md#extracted-versus-application-specific) |
86
319
 
87
320
  ## Ambiguous choices
88
321
 
89
- - `Toolbar` is persistent app chrome; `PanelHeader` heads a panel, dialog, or page.
90
- - `TabBar` changes tabpanels and supports overflow/reorder; `SegmentedControl` chooses among a few compact views; `Select` handles a longer value list.
91
- - `StateBanner` persists beside affected work; `EmptyState` replaces absent content; `wa-callout` is contextual ecosystem content; `wa-toast` and `wa-toast-item` are transient and must not carry the only copy of important state.
92
- - `ResizableRegion` is an interactive controlled pane. CSS grid is the right answer when columns do not need a user-operable separator.
93
- - `TokenSearchField` is a structured editor. A native input or `wa-input` is the right answer for ordinary text.
322
+ For a lowered background behind an entire scrolling work area, choose
323
+ `Pane appearance="sunken"` or the appearance option on the layout that owns
324
+ the scroll viewport. Use `SunkenPanel` for a padded content group that does
325
+ not introduce scrolling. See [Lowered work surfaces](./layout.md#lowered-work-surfaces).
326
+
327
+ Set `ResizableRegion`'s `--kui-resizable-region-background` for an inline
328
+ surface. A `PopupMenu` opens in the browser top layer, so the region keeps
329
+ clipping its own content while the menu shows in full; an open raw Web Awesome
330
+ dropdown inside it automatically releases clipping and raises the region on
331
+ its public popup layer instead. Set
332
+ `contentOverflow="visible"` for other anchored content that must escape the
333
+ region. A collapsed region can place `restoreControl` in a top or bottom corner with
334
+ `restorePosition`, set its typed `restoreInset`, or use
335
+ `restorePlacement="inline"` for a control in normal flow.
336
+
337
+ Use `FloatingToolbar placement="inline"` when a restore owner supplies the
338
+ position. Floating placement supports per-edge `--kui-floating-toolbar-inset-*`
339
+ tokens; `safeAreaInsets` adds the layout-routed or device safe-area inset to
340
+ the positioned edges.
341
+
342
+ For a larger option row, use `ListItem density="spacious"`; `compact` and
343
+ `standard` remain available. `multiline` wraps its label and aligns its icon
344
+ to the first line; `multilineIconAlign="center"` centers the icon against the
345
+ whole label. `divider` owns a before or after separator. Set
346
+ `state="drag-target"` for the component's drop outline and background (a row
347
+ that accepts dropped content). For a list the person reorders, set
348
+ `draggable` on each `ListItem`, `ListItemLink`, or `ListActionRow` (each with
349
+ an `itemId`) and call `wireListReorder` from `@kerfjs/ui/wire-list-reorder`
350
+ once, retaining its disposer: it dims the dragged rows, draws the 2px brand
351
+ insertion line on the hovered row's `before` or `after` edge, moves rows with
352
+ Alt+Shift+ArrowUp/ArrowDown, and reports
353
+ `{ listId, sourceIds, target: { id, position }, source }`. Dragging a selected
354
+ or pressed row moves every selected row of its `List` (set `data-list-id` on
355
+ the `List` to tell several lists apart). Apply the change synchronously with
356
+ `reorderListItems`; order stays application state. Without the wiring, the
357
+ `dragging` and `dropPosition` props render the same states from app-owned
358
+ drag state. Public
359
+ `--kui-list-item-*` tokens control its row, icon, label, and trailing geometry
360
+ and color. `ListHeader` exposes `--kui-list-header-min-height`, title padding,
361
+ title minimum height, and border-width tokens for section density.
362
+ Set `--kui-list-group-divider-color` on a containing `List` to give
363
+ `ListHeader`, `ListItem`, and `ListActionRow` the same before/after divider
364
+ color; each row otherwise uses the quiet neutral border tone.
365
+ Set `--kui-list-row-padding-inline` on a containing `List` to give `ListItem`
366
+ and `ListActionRow` rows one leading inline inset: both start their leading
367
+ icons on the same edge at any value, and the token defaults to
368
+ `--kui-layout-item-padding`. `--kui-list-item-padding-inline` still overrides
369
+ it for `ListItem` rows alone, so use the shared token whenever the two row kinds
370
+ share a list.
371
+ Both row kinds also draw their untiled leading icon at one shared size,
372
+ `--kui-list-row-icon-size` (default 18px), so a list that mixes them starts
373
+ their labels on one edge too. Set it on the containing `List` to resize both
374
+ row kinds together; `--kui-list-item-icon-size` still overrides it for
375
+ `ListItem` rows alone. An `iconTile` keeps its 32px tile and 18px glyph at any
376
+ value.
377
+ For a filled command list, set `--kui-list-item-background` and
378
+ `--kui-list-item-border` on the list or row. Scope `--kui-list-item-color`,
379
+ `--kui-list-item-hover-background`, `--kui-list-item-selected-color`, and
380
+ `--kui-list-item-selected-background` at the same boundary for text and state
381
+ fills. The matching `--kui-list-item-hover-border` and
382
+ `--kui-list-item-selected-border` tokens set state outlines without replacing
383
+ ListItem CSS or neutralizing global semantic border colors.
384
+
385
+ Use `ListItemLink` from `@kerfjs/ui/list-item` for a navigation row with a
386
+ real `href`. It shares `ListItem` content slots, density, selection, and row
387
+ geometry while rendering a native anchor. `external` opens a new tab with
388
+ `noopener noreferrer` and announces that behavior in the default accessible
389
+ name. Disabled and loading links omit `href` and leave the tab order. Use
390
+ `ListItem` for an application action dispatched through `action`.
391
+
392
+ Use `Toolbar responsive="trailing-priority"` for a collapsible search in the
393
+ trailing zone that should take a full second row when expanded. `responsiveAt`
394
+ chooses the compact or narrow container breakpoint. The leading identity stays
395
+ in the first row. Set `centerAlign="balanced"` when the center zone must sit on
396
+ the toolbar's midpoint despite unequal or empty side content; it gives the
397
+ leading and trailing zones equal tracks. A lone `ToolbarText` in a balanced
398
+ center is a navigation-bar title: the side zones keep their content width and
399
+ the title truncates first, centered while the sides leave room (NavStack uses
400
+ this once it shows a back control). `--kui-toolbar-leading-min-width`,
401
+ `--kui-toolbar-trailing-gap`, `--kui-toolbar-trailing-justify`, and the
402
+ `--kui-toolbar-*-padding-inline` zone tokens adjust local geometry without
403
+ selecting toolbar anatomy from application CSS.
404
+ For a shorter header embedded in a panel or card, pass `Toolbar
405
+ density="compact"`: a 40px toolbar with a 34px control band and 3px block
406
+ insets (inline insets and the zone gap stay 8px). Give its groups
407
+ `size="compact"` so they fit the band. Composite toolbars take the same
408
+ `density` through their `ToolbarConfig` (Workbench panel, main, and bottom
409
+ toolbars, CollapsiblePanel, NavStack, and SplitView) and size the groups they
410
+ compose — panel toggles, relocated toggles, the back button — to match. Pass
411
+ `density` to `CollapsiblePanelRelocated` when its destination toolbar is
412
+ compact.
413
+
414
+ Set `--kui-toolbar-inset: 0px` on an embedded Toolbar that should have no outer
415
+ padding while keeping its `--kui-toolbar-gap` between control zones. The token
416
+ also reduces its minimum height by the removed inset; safe-area compensation
417
+ still adds to the chosen inset on claimed edges.
418
+
419
+ For compact dialog copy, use `Text flush lineHeight="tight"`; block Text still
420
+ resets native margins. Center short status copy with `Text align="center"`
421
+ (`end` aligns a trailing value) instead of setting `text-align` on `.kui-text`. `ValueTable density="compact"` reduces row padding and
422
+ gap. Its `--kui-value-table-row-columns`, `--kui-value-table-row-padding-block`,
423
+ and `--kui-value-table-row-gap` tokens support a specific metadata layout.
424
+ Use `ToolbarText size="xsmall"` for a dense rail heading. Use
425
+ `size="xlarge-fixed"` for a toolbar heading at the fixed 20px step; `xlarge`
426
+ retains the responsive page-title clamp. Pass `headingLevel` when the text is
427
+ a section landmark. A `SearchField` editor can shrink to zero minimum width inside a narrow
428
+ group; set `--kui-search-field-editor-min-width` only when a wider editor is
429
+ required.
430
+
431
+ - `Toolbar` serves persistent app chrome and headings; the zone contents and accessible naming distinguish the purpose.
432
+ - `TabBar` changes tabpanels and supports overflow/reorder; `SegmentedControl` chooses among a few compact views; `ChoiceChips` keeps a larger exclusive set (or, with `multiple`, an any-number set) visible as wrapping pills; `Select` handles a longer value list.
433
+
434
+ Use `TabBarItem presentation="icon-only"` with its `name` kept as the accessible
435
+ tab name. For segmented tabs that should show names in a wide reader and icons
436
+ in a narrower container, set `TabBar iconOnlyAt="wide"` (832px), `"narrow"`
437
+ (704px), or `"compact"` (448px), and give each segmented `TabBarItem` a leading
438
+ icon. The tablist's own width controls the switch; the visually hidden name
439
+ remains its accessible name. Use `labelMaxWidth` for an ellipsized visible name. Set `attention`
440
+ to color a tab's name with `--kui-tab-bar-item-attention-color`. Set `dropTarget`
441
+ while an app drag is over a tab's content; the tab keeps its selection semantics
442
+ and uses the `--kui-tab-bar-item-drop-target-*` tokens for its highlight. Set
443
+ `nameOverflow="visible"` when an inline loading treatment needs the full name
444
+ instead of the default ellipsis. A `TabBar` owns its
445
+ scrolling strip; its public `--kui-tab-bar-strip-*` tokens configure strip
446
+ height, spacing, border, radius, background, and scroll inset without styling
447
+ its internal classes. `--kui-tab-bar-trailing-flex` controls the trailing zone.
448
+ For a distinct application action, use `end` to pin it at the far edge; use
449
+ `trailingPlacement="adjacent"` to keep a tab-local `trailing` action beside the
450
+ strip. Each zone accepts one `ToolbarControlGroup` or one standalone
451
+ `Button` for a primary action with its own chrome. Avoid wrappers and
452
+ application flex overrides.
453
+ Set `pinned` on the first `TabBarItem` when that tab must remain visible as peers
454
+ scroll. It stays inside the tablist and keyboard order. Set the `TabBar`
455
+ `snapTabs` prop when scrolling peers should settle at whole-tab starts
456
+ beside that pinned tab. `wireTabBars` measures the pinned inset and provides
457
+ enough end scroll room for the last peer to align there; a partial peer can
458
+ still appear at the trailing edge as an overflow cue. This mode also aligns a
459
+ newly selected tab at the pinned edge in LTR and RTL. Set the prop on the bar,
460
+ without styling its strip or tab internals. With `snapTabs`, keep the trailing
461
+ zone non-shrinking (the default `--kui-tab-bar-trailing-flex`): the reserved
462
+ end room counts toward the strip's share when both zones shrink.
463
+ Set the public
464
+ `--kui-tab-bar-item-pinned-background` token if the surrounding surface differs from
465
+ the default; the pinned tab must cover peers as they scroll beneath it. Its
466
+ background also covers the strip's inline padding and border so scrolled labels
467
+ cannot paint beside the pinned edge, including in right-to-left strips. The
468
+ backing follows the tab's pill radius, keeping a selected pinned tab's corners
469
+ and shadow whole beside the overflow divider. Call
470
+ `wireTabBars` for keyboard selection and reorder behavior and its WebKit RTL
471
+ scroll correction.
472
+
473
+ - `StateBanner` persists beside affected work; `EmptyState` replaces absent content; a `kerfjs/overlay` `toast()` is transient and must not carry the only copy of important state. With the Web Awesome integration, `wa-callout` is contextual ecosystem content and `wa-toast` is the transient equivalent.
474
+
475
+ For a banner with multi-line supporting copy, use `copyLayout="stacked"` to put
476
+ the detail below the title and badge. The default `actionPlacement="trailing"`
477
+ keeps the action beside the copy while the copy has room and moves it to its
478
+ own end-aligned trailing row when the banner is narrow (a phone, a sidebar),
479
+ so a group of buttons never squeezes or covers the title; no breakpoint or
480
+ `actionPlacement` switch is needed for narrow layouts. Use
481
+ `actionPlacement="below"` when the action should always take a separate
482
+ trailing row. The default copy layout keeps the detail inline;
483
+ `--kui-state-banner-copy-gap` and `--kui-state-banner-copy-row-gap` adjust the
484
+ stacked copy's spacing at an instance boundary.
485
+
486
+ For a full-width status band at a layout edge — above a workspace, below an
487
+ app bar — use `presentation="strip"` instead of restyling the card: it is flush
488
+ (no inline margin), square, puts its copy on the shared content-text column,
489
+ and draws only tone-colored `dividerSides` edges (bottom by default; `''` for
490
+ none). Keep the default `card` presentation for a banner beside the affected
491
+ work inside a pane.
492
+
493
+ For ongoing app-level progress that has no home beside the affected work, host
494
+ the banner in `CornerStatus` rather than positioning it with fixed CSS: a
495
+ manual popover in the top layer, at a safe-area-aware viewport corner, with no
496
+ close button, light dismiss, or Escape. Call `wireCornerStatus` once; it opens
497
+ each host as renders insert it, and the application removes the host when the
498
+ work ends.
499
+
500
+ A modal dialog opened while the status shows stacks above it, as it does over a
501
+ toast. Raising the status back above the modal would only paint it there: a
502
+ modal makes everything outside its own subtree inert, so the status could not
503
+ be reached or announced either way. When the dialog's task depends on that
504
+ progress, show it inside the dialog.
505
+
506
+ For a compact `Select`, set `triggerWidth` to `"fit-content"`, `"max-content"`,
507
+ or `"fill"`, and bound it with `maxTriggerWidth` / `minTriggerWidth` (under any
508
+ presentation; the value or `renderSelected` content ellipsizes before the caret).
509
+ For a round icon-only toolbar trigger, set `selectedPresentation="icon-only"`
510
+ and `caret={false}`. The control keeps its accessible name, current choice help
511
+ tag, and keyboard-operated listbox; the selected icon stays centered even when
512
+ `renderSelected` supplies it. The default keeps the visible caret.
513
+ Custom `renderSelected` text inherits the control color by default; the
514
+ `--kui-select-selected-color`, `--kui-select-selected-font-size`, and
515
+ `--kui-select-selected-font-weight` tokens configure its typography. Plain
516
+ selected text stays on one ellipsized line when the trigger narrows.
517
+
518
+ For an unavailable entry, set `SelectChoice.disabled` and optionally
519
+ `disabledReason`; the option stays visible but cannot be chosen. A multiple
520
+ `Select` can opt in to `selectAllLabel` and `clearLabel` footer buttons.
521
+ Select all includes only enabled choices, Clear removes the selection, and
522
+ both report changes through the normal `input` and `change` events. The app
523
+ still owns the controlled `value` and localized action labels.
524
+
525
+ - `ResizableRegion` is an interactive controlled pane. `Grid` is the right answer for static equal-width columns; application CSS grid remains the answer for asymmetric or intrinsic tracks.
526
+ - A `ResizableRegion`'s content spans the whole region, like its separator. Give
527
+ it one child — normally a `Pane` — and that child fills the region, so the
528
+ pane reaches the region's far edge and owns scrolling for long content.
529
+ Several children stack at their natural height. Do not size the child with
530
+ application `height` rules. While expanded, slide-motion content follows the
531
+ region's actual track, so a region its parent clamps (a `max-width`, a narrow
532
+ container) never shows content past its separator; the fixed expanded size
533
+ applies only while the collapsed content slides out.
534
+ - A `ResizableRegion` overlay automatically clamps both its track and fixed-size
535
+ animated content to the responsive overlay maximum. Set the policy and maximum
536
+ on the component instead of adding application descendant width/height fixes.
537
+ It paints `--kui-color-surface` itself (an inline region stays transparent),
538
+ so do not add a background to make an overlay opaque.
539
+ - Give `Workbench` panels a `toolbar` (title, `leading` / `center` / `trailing`
540
+ groups, and a standard `toggle`) and the work area a `mainToolbar` /
541
+ `mainBottomToolbar`: the Workbench moves a closed panel's groups marked
542
+ `relocateOnCollapse`
543
+ and toggle into the work area's toolbar, so never hand-place or duplicate
544
+ panel toggles. See [Workbench panel toolbars](workbench.md#panel-toolbars).
545
+ - Configure application panels through the shared `separator`, `collapseMotion`,
546
+ `contentOverflow`, `presentation`, `restoreControl`, and `restorePosition`
547
+ props on `ResizableRegion`, `Workbench` panels, and `CollapsiblePanel`. These
548
+ cover separator suppression, one-reflow collapse with composited motion,
549
+ bottom-drawer popups, compact overlays or replacements, and safe-area restore
550
+ placement without descendant `.kui-*` overrides. A `Workbench` rail's
551
+ or bottom drawer's `responsiveOverlayAt` (like `ResizableRegion`'s
552
+ `responsiveFillAt`) switches it to an overlay below a container breakpoint
553
+ without a device-class check.
554
+ `wireSidebar` also accepts a
555
+ hidden compact replacement and keeps compact overlays exclusive by default.
556
+ - `SearchField` is a structured editor. A `TextField` is the right answer for ordinary text.
557
+
558
+ For common structured search, use `createSearchFieldModel` from `@kerfjs/ui/search-field-model`, pass the model to `SearchField`, and register it under the field id in `wireSearchFields(root, { models })`. Rules parse `name:value` expressions and provide suggestions; the model owns chips, selection, removal, clear, and an optional evaluation result. The field subscribes only to `model.structure`, so typing plain text does not re-run the host render; read `model.state.peek()` in the host's render and bind `model.result` as a signal hole instead of reading `model.state.value`. Omit `model` and `models` for full manual control.
559
+
560
+ In a form, use `SearchField presentation="form-field"` with its `label`,
561
+ optional `hint`, and `required` state. It renders a full-width control beside
562
+ `TextField` without a Toolbar or extra inline inset. The app validates required
563
+ search content before saving.
564
+ The form-field corners follow the same `--kui-layout-rounded-radius` as a
565
+ neighboring `TextField`.
566
+ The four public color tokens (`--kui-search-field-background`,
567
+ `--kui-search-field-border`, `--kui-search-field-token-background`, and
568
+ `--kui-search-field-token-foreground`) inherit from an app ancestor or the
569
+ field's root. `className` marks that root, including the outer wrapper in
570
+ `form-field` presentation, so one app class can configure either form.
571
+ `SearchFieldRule.suggest(input, state)` receives the unfinished value and current committed tokens, so a rule can omit values already selected. Existing one-argument suggestion callbacks continue to work.
572
+ For a sibling date picker or other app helper, call `model.commit(value)` while a `name:` prefix is active. It parses and commits that value for the active rule even when it is absent from suggestions, replacing the unfinished prefix text. Invalid values and calls without an active prefix leave the query unchanged; `choose(value)` remains restricted to suggested tokens.
573
+ To apply a saved search or restore a query programmatically, call `model.replace({ query, tokens })`. It publishes parsed state and rebuilds the DOM-owned editor text even when no chip changed. For a field without a model, change the field's `revision` prop when setting `query` yourself.
574
+ When one root contains both kinds of field, a registered model enables chip keyboard behavior only for its own field. Other fields keep native editing unless the root opts into `keyboard` with an application removal callback.
575
+ For an icon action at the end of the field, pass `trailingAction` with `icon`,
576
+ accessible `label`, and delegated `action` (plus optional `id`). The component
577
+ renders a compact button beside the clear button, with the same size, hover,
578
+ focus ring, and cursor, in every presentation. For a help toggle that opens a
579
+ surface, set `expanded` (and `haspopup`, plus `controls` while it is open); for
580
+ an on/off toggle, set `pressed`. The open or pressed state keeps the hover fill.
581
+ Put domain `data-*` metadata in `attributes`. Never style your own button into
582
+ the `trailing` slot; reserve `trailing` for passive content such as a shortcut
583
+ hint.
584
+ Set `fill` on a collapsible `SearchField` in a stretched Toolbar center to
585
+ use the available width when expanded; the field and its search group retain
586
+ their compact widths when collapsed.
587
+ When the expanded toolbar field has focus, its inset surface uses
588
+ `--kui-search-field-background` or the default surface color if that token is
589
+ unset.
590
+
591
+ `ToolbarControlGroup.tileTone` selects `neutral`, `brand`, `success`, `warning`, or `danger` quiet fill, matching quiet border, and on-quiet foreground for a non-interactive icon tile. Compose a contained `single` group whose only child is a direct decorative LucideIcon (`aria-hidden="true"`). Omission preserves the normal group palette. The prop does not recolor interactive, mixed, multi-control, or borderless groups; keep real actions in controls with their existing focus/hover/pressed treatments.
592
+
593
+ `ToolbarControlGroup` `material="glass"` paints a group that floats over imagery or a clear (transparent) toolbar on the translucent chrome material (`--kui-chrome-material` with the blur/saturate `--kui-chrome-material-filter`), with a specular edge in place of the gray border and a soft shadow. Its controls take `--kui-color-text`, so they stay at AA over any content; a raised or outline selection paints an opaque surface pill. The fill turns opaque under reduced transparency, increased contrast, static effects (`update: slow` or `:root[data-kui-effects="static"]`), or without backdrop-filter support, and paints Canvas/CanvasText in forced colors. A `tone="dark"` glass group keeps its loud fill and gains the blur and edge; a borderless group has no surface and ignores the material. Keep the solid default on an opaque toolbar, and never add your own `backdrop-filter` or translucent background to a group.
594
+
595
+ `ListItem`, `ListItemLink`, and `ListActionRow` take `iconTile` to present their leading `icon` in a filled 32px rounded tile holding an 18px glyph, for settings or command rows that identify each entry by color. Pass a tone (`neutral`, `brand`, `success`, `warning`, or `danger`) for the same quiet fill, matching quiet border, and on-quiet foreground as `ToolbarControlGroup.tileTone`, or `{ color, foreground? }` for an application color: `color` is a `CssColor` (`uiColor()`, `colorVar()`, or `fillColor('#e5484d')`) and `foreground` a `CssForegroundColor`; without one, the glyph is black or white, whichever contrasts with the fill. The tile sits 6px clear of a standard 44px row (a compact row is at least 42px tall), moves the label to the tile's edge, and keeps its colors when the row is hovered or selected. Never wrap the icon in your own tile or resize the row's icon slot.
94
596
 
95
597
  ## Toolbar composition
96
598
 
97
- A `Toolbar` has three zones — `leading`, `center`, and `trailing`. In almost
98
- every case the only things that go **directly** in a zone are `ToolbarText`
99
- (identity/title text) and `ToolbarControlGroup` (any control or cluster of
100
- controls). Do not drop bare buttons, inputs, links, or arbitrary markup straight
101
- into a zone; wrap controls in a `ToolbarControlGroup` so they get the shared
102
- toolbar geometry, hover/pressed treatment, and grouping. `SegmentedControl`,
103
- `Select`, a collapsible `TokenSearchField`, and Web Awesome controls all live
104
- **inside** a `ToolbarControlGroup`, not loose in the zone. `PanelHeader` is the
105
- one wrapper that composes these for you as a panel/dialog/page heading.
599
+ Use `ToolbarText tone="dark"` on a loud-filled toolbar surface (one painted
600
+ with `--kui-color-neutral-fill-loud`, the inverse of the page) to match dark
601
+ control groups; like them it inverts with the color scheme. Text over a dark
602
+ photo or scrim needs a foreground that is light in both schemes instead: a
603
+ `BackdropImage` `scrim` gives its overlay the dark scheme, so keep the
604
+ default tone there. It applies to read-only headings and actionable
605
+ titles at every size; default tone retains existing identity and heading colors.
606
+
607
+ A `FloatingToolbar` accepts `ToolbarControlGroup` directly as its children in
608
+ both floating and inline placement. Name the toolbar with `label`; group its
609
+ controls as you would in a `Toolbar` zone.
610
+
611
+ A `Toolbar` has three zones — `leading`, `center`, and `trailing`. Each accepts
612
+ `KerfUiContent` directly, including a status `Chip`, a native control, or
613
+ application markup. `ToolbarText` is the standard identity/title; use
614
+ `ToolbarControlGroup` when related controls should share its chrome, sizing,
615
+ hover treatment, or overflow behavior. A standalone primary `Button` keeps
616
+ its own chrome and fits naturally in the trailing zone. Bare
617
+ controls retain their own styling and accessibility responsibilities; the
618
+ toolbar only positions them within the zone. A toolbar with a single zone (only
619
+ `leading`, only `trailing`, or only `center`) gives that zone the whole content
620
+ box: an absent zone leaves no empty track or gap, so content set to fill the row
621
+ reaches the opposite inset.
622
+ For a title that opens an editor, set `action` on a direct `ToolbarText`: it
623
+ renders a native button that keeps its content width when possible and
624
+ ellipsizes before an adjacent status chip when the leading zone narrows. The
625
+ application handles the delegated action and replaces it with its own input
626
+ while editing. Use a separate heading landmark if the view needs one.
627
+ For a search or cluster that needs shared toolbar geometry, place
628
+ `SegmentedControl`, `Select`, or `SearchField` inside a
629
+ `ToolbarControlGroup`. The ToolbarText catalog's actionable-title example
630
+ places its status `Chip` directly beside the title while the search uses a
631
+ group. `TabBar` also accepts a `ToolbarControlGroup` in its `leading`,
632
+ `trailing`, or `end` zone, including an application wrapper that renders one.
633
+ For a page, panel, or
634
+ dialog heading, put an extra-large `ToolbarText` directly in the leading zone,
635
+ optionally preceded by a grouped icon, and group trailing actions. Keep supporting
636
+ copy below as app-owned content. Size the title to its track: a narrow
637
+ peripheral rail or drawer (a navigator, inspector, or console beside a work
638
+ area that carries the extra-large title, often with its own close control in
639
+ the header) labels itself with the default size, because extra-large truncates
640
+ there — "Inspector" becomes "Ins…" in a 160px rail. By default, nothing wraps
641
+ inside a `ToolbarControlGroup`: an icon sits beside its label on one row and the
642
+ group sizes to its content, so a row that does not fit relocates whole groups
643
+ through the toolbar's `responsive` policy. For independent action links that
644
+ must all remain visible, set `overflow="wrap"`: whole links move to another
645
+ row inside the group without breaking an icon from its label. Use
646
+ `overflow="scroll"` when a single-row action strip is intentional. A
647
+ toolbar draws no divider by default: pinned over or under scrolling content,
648
+ it gets one from the scroll state instead — the `Pane` it heads draws the line
649
+ only while content is scrolled beneath it, once `wireScrollDividers` is wired
650
+ (see [Scroll dividers](./layout.md#scroll-dividers)). Set `dividerSides` to the
651
+ canonical physical-edge combinations (`t`, `r`, `b`, `l`, in that order—for
652
+ example `b`, `tr`, or `trbl`) only when the toolbar owns a permanent separator
653
+ edge. Dividers earn their place: never fake one with a border or pad below one
654
+ to make it look right.
655
+
656
+ `Toolbar` renders a semantic `header` by default. Set `position="footer"`
657
+ for a toolbar at the bottom of a pane or page; Workbench's
658
+ `mainBottomToolbar` and the catalog resource bar apply this automatically.
659
+ The position changes the HTML element without changing zones or geometry.
106
660
 
107
661
  Common toolbar patterns:
108
662
 
109
- | Want | Put in the zone | Notes |
110
- | --- | --- | --- |
111
- | Identity or title text | `<ToolbarText text="…" size="large" />` (or `xlarge` for a page/panel title) | Wrap in a `single` borderless group only when it must align with adjacent control pills |
112
- | One or more icon/text buttons | `<ToolbarControlGroup>{buttons}</ToolbarControlGroup>` | Use `buttonAppearance="push"` for toggle buttons with `aria-pressed`; `single` for a lone control |
113
- | An exclusive view switch | `<ToolbarControlGroup><SegmentedControl … /></ToolbarControlGroup>` | Not `TabBar`, which switches tabpanels |
114
- | A value list | `<ToolbarControlGroup><Select … /></ToolbarControlGroup>` | Register `@kerfjs/ui/select/register` once |
115
- | A collapsible search box | `<ToolbarControlGroup single><TokenSearchField collapsible … /></ToolbarControlGroup>` | The group animates the iconic ↔ expanded states; `wireTokenSearchFields` manages expand/collapse/focus by default |
663
+ For a long-running action, set `busy` on its single-control
664
+ `ToolbarControlGroup` and supply a descriptive `busyLabel`. The group preserves
665
+ the control's dimensions, shows `LoadingSpinner` in its place, sets
666
+ `aria-busy`, and makes the control inert until the app clears `busy`. An icon
667
+ group hides only the glyph; a `content="text"` or `"mixed"` group hides the
668
+ whole control, label included, so the spinner never draws over text.
669
+
670
+ | Want | Put in the zone | Notes |
671
+ | ------------------------------ | -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
672
+ | Identity or title text | `<ToolbarText text="…" size="large" />` (or `xlarge` for a page/panel title that fits) | Wrap in a `single` borderless group only when it must align with adjacent control pills |
673
+ | One or more icon/text buttons | `<ToolbarControlGroup>{buttons}</ToolbarControlGroup>` | Use `buttonAppearance="push"` for toggle buttons with `aria-pressed`; `single` for a lone control |
674
+ | One primary application action | `trailing={<Button tone="brand">New Ticket…</Button>}` | The standalone button keeps its own chrome; use `tone="success"` for a positive pricing check or `tone="danger"` when the action is destructive |
675
+ | An exclusive view switch | `<ToolbarControlGroup><SegmentedControl … /></ToolbarControlGroup>` | Not `TabBar`, which switches tabpanels |
676
+ | A value list | `<ToolbarControlGroup><Select … /></ToolbarControlGroup>` | Register `@kerfjs/ui/select/register` once; use `focusRingOwner="group"` so focus follows the group's geometry |
677
+ | A command menu | `<ToolbarControlGroup single nestedDropdown><PopupMenu … /></ToolbarControlGroup>` | Register `@kerfjs/ui/popup-menu/register` once; set `menuInset` on the group |
678
+ | A collapsible search box | `<ToolbarControlGroup single><SearchField collapsible … /></ToolbarControlGroup>` | The group animates the iconic ↔ expanded states; `wireSearchFields` manages expand/collapse/focus by default |
679
+
680
+ ### Room for an expanded search
116
681
 
117
- A **popup menu in a toolbar** is a `single` `ToolbarControlGroup` wrapping a Web
118
- Awesome `wa-dropdown`: its `slot="trigger"` `wa-button` is the toolbar button and
119
- the `wa-dropdown-item`s are the menu. Keep the dropdown's managed light-DOM
120
- children under `data-morph-skip-children` so kerf does not reconcile Web Awesome's
121
- own DOM.
682
+ A collapsible search group grows into the room beside its sibling groups. When
683
+ that room is too small, the siblings wrap onto a new row partway through the
684
+ opening, and the toolbar grows a row taller. Kerf does not hide or move your
685
+ other controls; plan for it instead:
686
+
687
+ - Size the expanded search to what fits: `--kui-search-field-expanded-width`
688
+ for a plain search group, or `sizing="grow"` with a `growBasis` that fits
689
+ beside the siblings.
690
+ - If a useful search cannot fit beside the other controls, set those controls
691
+ aside while it is open. Mark them `visibility="yield-to-expanded-sibling"`
692
+ (they leave a 480px-or-narrower toolbar while a sibling is expanded), or, in
693
+ a `responsive="trailing-priority"` Toolbar,
694
+ `visibility="yield-to-priority-row"` (they leave exactly while the expanded
695
+ control has its own row), or gather them behind a "…" `PopupMenu` overflow
696
+ group. The application decides which controls yield.
697
+
698
+ ### Application surfaces below search
699
+
700
+ Pass `expandedOverflow="visible"` to `ToolbarControlGroup content="search"`
701
+ when an application-owned suggestion list, date picker, or help surface extends
702
+ below it. The group is the positioning containing block, retains auto height,
703
+ and permits overflow only while `expanded` is true. Omission or `"clip"` keeps
704
+ existing behavior, including Kerf's built-in suggestions. Other content modes
705
+ and collapsed searches keep their existing overflow rules.
122
706
 
123
707
  ```tsx
124
- <ToolbarControlGroup single>
125
- <wa-dropdown placement="bottom-start" data-morph-skip-children>
126
- <wa-button slot="trigger" appearance="plain" with-caret aria-label="Sort">
127
- <LucideIcon icon={ArrowDownAZ} name="arrow-down-a-z" />
128
- </wa-button>
129
- <wa-dropdown-item data-action="sort-recent">Recently updated</wa-dropdown-item>
130
- <wa-dropdown-item data-action="sort-priority">Priority</wa-dropdown-item>
131
- </wa-dropdown>
708
+ <ToolbarControlGroup content="search" expanded={open} expandedOverflow="visible">
709
+ <SearchField id="ticket-search" label="Search tickets" presentation="toolbar-group" collapsible expanded={open} />
710
+ {open ? <AppDatePicker data-search-field-keep-open /> : null}
132
711
  </ToolbarControlGroup>
133
712
  ```
134
713
 
714
+ The application owns placement (for example absolute positioning below the
715
+ group), stacking, dismissal, and hiding/removing its surface on collapse. Mark
716
+ focusable floating content `data-search-field-keep-open`, or configure
717
+ `collapsible.keepOpenOn`, to keep an empty field open when focus enters it.
718
+ This prop does not escape clipping imposed by an ancestor or create a top-layer
719
+ popover. Do not override the group's position, height, or overflow in app CSS.
720
+
721
+ ### Popup menu migration
722
+
723
+ A **popup menu in a toolbar** is a `PopupMenu` (`@kerfjs/ui/popup-menu`) in a
724
+ `single` `ToolbarControlGroup` with `nestedDropdown`; the group sizes the trigger
725
+ as a toolbar button and `menuInset` sets the menu's inset. `PopupMenu` renders
726
+ its own native trigger button and a `role="menu"` panel of typed items
727
+ (commands, headings, and dividers) that opens in the browser top layer, and
728
+ keeps the open menu's state out of the morph. Register
729
+ `@kerfjs/ui/popup-menu/register` once; it wires opening, keyboard navigation,
730
+ submenus, and dismissal for every PopupMenu in the document. Do not hand-write
731
+ `wa-dropdown` or menu markup for a menu.
732
+
733
+ ```tsx
734
+ <ToolbarControlGroup single nestedDropdown menuInset="compact">
735
+ <PopupMenu
736
+ label="Sort"
737
+ icon={<LucideIcon icon={ArrowDownAZ} name="arrow-down-a-z" />}
738
+ items={[
739
+ { label: "Recently Updated", action: "sort-recent" },
740
+ { label: "Priority", action: "sort-priority" },
741
+ ]}
742
+ />
743
+ </ToolbarControlGroup>
744
+ ```
745
+
746
+ Nested decisions use an item with `submenu`. Children keep their own actions,
747
+ `attributes` metadata, icons, `checked` state, disabled state and
748
+ `disabledReason` tooltip. Nested `heading` and `divider` entries group those
749
+ commands without entering keyboard navigation. `tone: 'danger'` draws a
750
+ destructive command. A parent can sit among ordinary commands and dividers, so the same
751
+ items shape covers single-line and batch actions; compute each batch child's
752
+ `disabled` state from the current selection.
753
+
754
+ ```tsx
755
+ <PopupMenu
756
+ label="Line actions"
757
+ items={[
758
+ { label: 'Copy Reference', action: 'copy-reference', attributes: { 'data-item-id': lineId } },
759
+ { label: 'Decide', submenu: [
760
+ { kind: 'heading', label: 'Review' },
761
+ { label: 'Approve', action: 'decide', checked: current === 'approve', attributes: { 'data-item-id': lineId, 'data-decision': 'approve' } },
762
+ { label: 'Reject', action: 'decide', tone: 'danger', disabled: needsPrice, disabledReason: needsPrice ? 'Add a price first' : undefined, attributes: { 'data-item-id': lineId, 'data-decision': 'reject' } },
763
+ { kind: 'divider' },
764
+ { label: 'Other…', action: 'choose-other' },
765
+ ] },
766
+ { kind: 'divider' },
767
+ { label: 'Remove', action: 'remove', tone: 'danger' },
768
+ ]}
769
+ />
770
+ ```
771
+
772
+ For a flat command menu with persistent sort choices, group commands under
773
+ `heading` entries and set `checked` explicitly on each choice. Checked rows
774
+ show a checkmark; the background marks the current keyboard row, as in `Select`.
775
+ Items with `checked: true` or `checked: false` reserve checkmark space, and so
776
+ does every plain command in a menu level (the top menu or one submenu) that
777
+ holds such an item, so icons and labels line up across the level; a level
778
+ without a choice keeps the compact start. Omit `checked` for a plain command,
779
+ including one beside checkbox items. The application owns each choice's state:
780
+ choosing one reports the state it asks for (`detail.checked`) in the root's
781
+ bubbling, cancelable `kui-menu-select` event, alongside `detail.item` and its
782
+ `detail.value`, and the menu shows the new checkmark once the application
783
+ renders it. Commands still dispatch their own `data-action` once on pointer and
784
+ keyboard selection; canceling `kui-menu-select` keeps the menu open.
785
+
786
+ For a row opened by right-click, render `PopupMenu` with `context`, `label`,
787
+ `anchor`, and a stable root `data-*` marker. Its trigger is an invisible anchor
788
+ removed from the accessibility tree; a separate visible button may stay
789
+ disabled. The menu owns its anchor host: it renders out of flow with no layout
790
+ footprint (no line box, no gap slot), so render it anywhere in the surface it
791
+ belongs to — never inside an app wrapper with `position: fixed`, a 1px size,
792
+ or a `z-index` (the open menu is in the browser top layer). In the app's
793
+ `contextmenu` handler, prevent the browser menu, store
794
+ `{ x: event.clientX, y: event.clientY }` in the signal the menu renders as
795
+ `anchor`, and call `openPopupMenu` with the menu. Its `placement` applies at
796
+ the point: the default `bottom-start` opens below it, and `top-start` or
797
+ `top-end` opens above it (for a menu anchored to a footer or composer), still
798
+ flipping when that side has no room. Because the point is part of the
799
+ menu's own template, it survives re-renders and a rebuilt menu, so the app
800
+ never re-applies it. `openPopupMenuAt` still opens a menu rendered without `anchor` at a given
801
+ point, at its `placement` unless the call names one for that opening
802
+ (`openPopupMenuAt(menu, x, y, { placement: 'top-start' })`). Call `closePopupMenu` for programmatic dismissal. A pointer-anchored menu
803
+ keeps the same collision placement, focus management, submenu keyboard
804
+ navigation, and outside/Escape dismissal as a trigger-anchored one.
805
+
806
+ The menu opens in the browser top layer, flips and shifts at viewport edges,
807
+ and limits its height to the available space, scrolling past it. It shifts
808
+ only along its trigger's (or point's) edge, never across it: when neither
809
+ side fits, it opens on the side with more room and scrolls, so a tall menu
810
+ never covers its trigger and a second press on the trigger closes it. The app
811
+ supplies pointer coordinates and command policy; it does not need to calculate
812
+ menu offsets. For other anchored content, use `AnchoredSurface` for help or
813
+ popup content, a native `title` for a plain-text hint, or `kerfjs/overlay`'s
814
+ `positionAnchored()` when only placement is needed. An application using the
815
+ Web Awesome integration may use `wa-tooltip` for a rich hover tooltip until
816
+ Kerf ships a styled one; `wa-popover` and `wa-popup` are `Discouraged`. These
817
+ are distinct interaction contracts: a command menu still uses `PopupMenu`.
818
+
819
+ ## Configuring recurring list rows
820
+
821
+ Configure the List family instead of selecting its descendant classes. Use
822
+ `density="compact"` for result-heavy panes, `description` for the secondary
823
+ label line, `status` for dormant state text, and `busy` for known progress that
824
+ keeps current content visible. `divider` marks group boundaries without an
825
+ app-owned separator rule. `ListHeader.indicatorTone` gives count, badge, or
826
+ status content neutral, accent, pop, or danger attention. Pop marks featured or
827
+ novel content without claiming a status transition.
828
+
829
+ When a row needs a context action, use `ListActionRow`; its two native buttons
830
+ remain siblings. `trailingActionVisibility="interaction"` keeps the action
831
+ available on hover and keyboard focus and automatically leaves it visible on
832
+ non-hover devices. These props own presentation only—the application still
833
+ owns labels, status meaning, action policy, selection, and domain metadata.
834
+ `density="compact"` makes a single-line row 36px tall (42px with `iconTile`),
835
+ the same height as a compact `ListItem`, so the two row kinds stay level in a
836
+ dense mixed list; a standard row is 44px.
837
+
838
+ When the trailing control is an overflow menu ("…" with Edit, Delete, …),
839
+ pass `trailingMenu: { label, icon, items, placement?, disabled? }` instead of
840
+ the `trailingAction*` props. The row renders a real `PopupMenu` (icon-only, no
841
+ caret, opening `bottom-end` by default) as its sibling trailing control, and
842
+ `trailingActionVisibility="interaction"` reveals it the same way, keeping it
843
+ visible while the menu is open. Register `@kerfjs/ui/popup-menu/register` once.
844
+ Items dispatch their own `data-action`s; find the row from a chosen item with
845
+ `closest('[data-component="list-action-row"]')`. To open the same menu on a
846
+ right-click, delegate `contextmenu` on the row's primary button, prevent the
847
+ browser menu, and call `openPopupMenuAt` with the row's
848
+ `[data-component="popup-menu"]` child and the pointer's `clientX` /
849
+ `clientY`: a button-triggered menu opens `bottom-start` at the pointer for that
850
+ opening and returns to its trigger once it closes. Pass a placement for that
851
+ opening as a fourth argument, `openPopupMenuAt(menu, x, y, { placement:
852
+ 'top-start' })`, to open it above the point instead (for a row near a footer
853
+ or composer); the viewport flip, shift, and height cap still apply.
854
+
855
+ ```tsx
856
+ <ListActionRow
857
+ action="select-command"
858
+ itemId={command.id}
859
+ label={command.name}
860
+ trailingActionVisibility="interaction"
861
+ trailingMenu={{
862
+ label: `Actions for ${command.name}`,
863
+ icon: moreIcon,
864
+ items: [
865
+ { label: 'Edit', action: 'edit-command' },
866
+ { kind: 'divider' },
867
+ { label: 'Delete', action: 'delete-command', tone: 'danger' },
868
+ ],
869
+ }}
870
+ />;
871
+
872
+ delegate(list, 'contextmenu', '[data-action="select-command"]', (event, primary) => {
873
+ const menu = primary.parentElement?.querySelector<PopupMenuElement>(
874
+ ':scope > [data-component="popup-menu"]',
875
+ );
876
+ if (!menu) return;
877
+ event.preventDefault();
878
+ openPopupMenuAt(menu, (event as MouseEvent).clientX, (event as MouseEvent).clientY);
879
+ });
880
+ ```
881
+
135
882
  ## Correct composition and duplicated-markup trap
136
883
 
137
884
  Correct: let the pane stay unpadded while its children own the shared 8/1/8
138
885
  geometry and 44px targets.
139
886
 
140
887
  ```tsx
141
- <aside class="kui-pane">
142
- <nav class="kui-pane__content kui-content">
888
+ <Pane element="aside" contentElement="nav" label="Workspace" contentLabel="Workspace pages">
143
889
  <section>
144
- <ListHeader label="Workspace" />
145
- <ListItem action="open" label="Inbox" icon={inboxIcon} />
146
- <ListActionRow action="open-file" label="main.ts" trailingAction="file-actions" trailingActionLabel="Actions for main.ts" trailingActionIcon={moreIcon} />
890
+ <ListHeader label="Workspace" />
891
+ <ListItem action="open" label="Inbox" icon={inboxIcon} />
892
+ <ListActionRow
893
+ action="open-file"
894
+ label="main.ts"
895
+ trailingAction="file-actions"
896
+ trailingActionLabel="Actions for main.ts"
897
+ trailingActionIcon={moreIcon}
898
+ />
147
899
  </section>
148
- <div class="kui-content-item">Workspace details</div>
149
- </nav>
150
- </aside>
900
+ <ContentItem>Workspace details</ContentItem>
901
+ </Pane>
151
902
  ```
152
903
 
904
+ When that child is a selectable card, configure `ContentItem` with
905
+ `interactive`, `action`, `itemId`, and a `selectionMode`; wire
906
+ `wireContentItems` once for Enter and Space. The component owns selection,
907
+ hover, focus, and disabled paint in its reserved 1px frame (see
908
+ [Content items](./layout.md#content-items)).
909
+ For a multi-select card containing its own controls, place
910
+ `selectionMode="multiple"` ContentItems inside a labeled
911
+ `List selectionMode="multiple"`; the app supplies each card's `selected`
912
+ state. Resolve each card activation with `applySelection` and
913
+ `selectionGesture` from `@kerfjs/ui/selection`, which implement the same
914
+ platform-normalized replace, Cmd/Ctrl-toggle, and Shift-range model as
915
+ `ChoiceChips` `multiple` (`isApplePlatform` decides between Cmd and Ctrl); `wireContentItems` forwards those modifiers from
916
+ Enter and Space, and keeps the grid one Tab stop. Put content that is not
917
+ selectable between those rows (an activity group, a "messages skipped"
918
+ divider) in a `ContentItem gridRow`, never a hand-written `role="row"`
919
+ wrapper.
920
+ For wrapped document tiles, use `Grid minColumnWidth={px(160)}` with
921
+ `selectionMode="multiple"` and `ariaLabel`. The same ContentItem row/gridcell
922
+ contract applies, while `wireContentItems` follows the rendered tile layout
923
+ with all four arrow keys.
924
+
153
925
  Incorrect: duplicating component-like rows and compensating for nested padding
154
926
  forks the package anatomy and spacing contract.
155
927
 
@@ -161,26 +933,270 @@ forks the package anatomy and spacing contract.
161
933
  </aside>
162
934
  ```
163
935
 
164
- ## Web Awesome overlap policy
165
-
166
- Web Awesome catalog coverage means supported and themed, not preferred. Import
167
- `@kerfjs/ui/webawesome` for Kerf JSX types, individual component modules for
168
- registration, and the CSS-only `@kerfjs/ui/webawesome.css` theme.
169
-
170
- | Web Awesome choice | Kerf decision |
171
- | --- | --- |
172
- | `wa-button`, `wa-dropdown`, `wa-dropdown-item` | Use buttons and command menus for actions. Use `ListItem` for a navigation row and `Select` when the user chooses a value. |
173
- | `wa-button-group` | Use only for exceptional grouped actions; use `SegmentedControl` for one-of-many selection. |
174
- | `wa-input`, `wa-tag` | Use for ordinary text and tags; use `TokenSearchField` only when text and ordered filter tokens form one editor. |
175
- | `wa-select`, `wa-option` | Use `Select`, which owns Kerf spacing, controlled rendering, icon stability, and explicit registration. |
176
- | `wa-tab-group`, `wa-tab`, `wa-tab-panel` | Use `TabBar`/`AppTab` for application tabs or `SegmentedControl` for compact local views. |
177
- | `wa-icon` | Use `LucideIcon` in application UI. |
178
- | `wa-split-panel` | Use `ResizableRegion` for Kerf application panes; retain Split Panel only when its distinct API is required. |
179
- | `wa-spinner`, `wa-progress-bar`, `wa-progress-ring`, `wa-skeleton` | Use `LoadingSpinner` for compact Kerf indeterminate activity; choose the ecosystem component when its distinct progress or placeholder semantics fit. |
180
- | `wa-callout`, `wa-toast`, `wa-toast-item` | Use `StateBanner` for persistent inline app status, `EmptyState` for absent content, and toasts only for transient feedback. |
181
- | `wa-popup`, `wa-tooltip`, `wa-popover` | Prefer the high-level interaction whose semantics fit. Use Popup only when its low-level anchored positioning removes custom placement code. |
182
- | `wa-tree`, `wa-tree-item`, `wa-animated-image`, `wa-comparison` | Use only for the specialized behavior named by the component. |
183
- | `wa-zoomable-frame` | Avoid for application UI; keep embedded-media behavior application-owned. |
936
+ ## Removable tags
937
+
938
+ Use `Chip` when a short tag has a remove action. `removeAction` becomes the
939
+ native button's `data-action`; `removeLabel` must name the specific tag for
940
+ assistive technology. Use `itemId` for the application's delegated handler.
941
+ The application updates its tag list after the action. `size="compact"` uses a
942
+ 20px chip with a 16px remove button, and `disabled` disables removal. Tone,
943
+ appearance, and shape use the same semantic choices as `Badge`; use `Badge`
944
+ when no removal is needed and the content is status or count metadata.
945
+ Pass an unsized, decorative `LucideIcon` through `icon` for a leading glyph;
946
+ Chip sizes it to its own type scale and aligns it beside the label. For a long
947
+ plain-text label, set `truncate`: the chip can shrink within a `Row`, its label
948
+ gets a one-line ellipsis, and the full string is the label's native `title`.
949
+ Keep a price or other unbreakable sibling in `Text wrap="nowrap"`. `truncate`
950
+ requires a string label so the title cannot lose text hidden inside markup.
951
+
952
+ ```tsx
953
+ <Chip
954
+ size="compact"
955
+ tone="info"
956
+ itemId={tag.id}
957
+ removeAction="remove-tag"
958
+ removeLabel={`Remove ${tag.name} tag`}
959
+ >
960
+ {tag.name}
961
+ </Chip>
962
+ ```
963
+
964
+ ## File and link chips
965
+
966
+ Give `Chip` an `href` when a short chip should open or download something,
967
+ such as the files a chat message references. The chip becomes a native `<a>`
968
+ with the same geometry, icon slot, truncation, and focus ring, plus hover
969
+ feedback. `download` is `true` or the suggested file name; `external` opens a
970
+ new tab with `rel="noopener noreferrer"` and announces it, like
971
+ `ListItemLink`. A link chip cannot also carry a remove button. Use
972
+ `ListItemLink` for a navigation row and `ToolbarActionLink` in a toolbar.
973
+
974
+ Inside a `brand-loud` or `neutral` `ContentItem` bubble, set
975
+ `tone="inherit"`: the chip follows the bubble's foreground and draws its shape
976
+ with a currentColor border (soft for `quiet`, full strength for `outline` and
977
+ `solid`) instead of a fill, so its label keeps the bubble's text contrast.
978
+ Its hover strengthens the border and underlines the label, and its focus ring
979
+ follows the foreground. Semantic tones keep their fills and add a currentColor
980
+ wash on hover. File names are data: keep their spelling.
981
+
982
+ ```tsx
983
+ <Row gap="xs" wrap>
984
+ {files.map((file) => (
985
+ <Chip
986
+ tone="inherit"
987
+ href={file.url}
988
+ download={file.name}
989
+ icon={<LucideIcon icon={FileText} name="file-text" />}
990
+ truncate
991
+ >
992
+ {file.name}
993
+ </Chip>
994
+ ))}
995
+ </Row>
996
+ ```
997
+
998
+ ## Action chips
999
+
1000
+ Give `Chip` an `action` when activating the chip should do something with its
1001
+ value once, such as inserting a filter token from a search syntax help popover
1002
+ into the query. The whole chip becomes a native
1003
+ `<button type="button" data-action data-item-id>` with the same geometry, plus
1004
+ hover, press, focus-ring, and `disabled` states; Enter and Space activate it,
1005
+ and a delegated handler reads `itemId`. Set `actionLabel` when the visible
1006
+ label alone is unclear, and keep the label inside it ("Insert filter is:mine")
1007
+ so speech input still matches. An action chip cannot also take `href` or
1008
+ `removeAction`, because nested interactive content is invalid. Use `Badge` for
1009
+ metadata nobody activates, and `ChoiceChips` when the chips hold a persistent
1010
+ radio or checkbox value.
1011
+
1012
+ A compact, rounded action chip is exactly as tall as the compact `Badge` it
1013
+ replaces, so a wrapping `Row` of them in a compact `ValueTable` cell keeps the
1014
+ table's row height.
1015
+
1016
+ ```tsx
1017
+ <ValueTable label="Search Filters" density="compact">
1018
+ <ValueTableRow
1019
+ label="Ownership"
1020
+ value={
1021
+ <Row gap="2xs" wrap>
1022
+ {['is:mine', 'is:shared'].map((token) => (
1023
+ <Chip
1024
+ action="search-help-insert"
1025
+ actionLabel={`Insert filter ${token}`}
1026
+ itemId={token}
1027
+ size="compact"
1028
+ shape="rounded"
1029
+ >
1030
+ {token}
1031
+ </Chip>
1032
+ ))}
1033
+ </Row>
1034
+ }
1035
+ />
1036
+ </ValueTable>
1037
+ ```
1038
+
1039
+ ## Wrapping exclusive choices
1040
+
1041
+ Use `ChoiceChips` when one value is chosen from a visible set that does not
1042
+ fit one segmented track: a nine-color palette in a 560px dialog, say, which
1043
+ must wrap onto several rows and still read well at phone width. Each choice is
1044
+ a separate pill backed by a native radio, so the group is one Tab stop, arrow
1045
+ keys move the selection, and the checked radio is the form value under `name`.
1046
+ The pills wrap with the standard 8px control gap; never wrap a
1047
+ `SegmentedControl` or a joined button group instead — their joined
1048
+ borders turn ragged across rows.
1049
+
1050
+ Lead a choice with `swatch` for a color (a `CssColor` from `uiColor()`,
1051
+ `colorVar()`, or the `fillColor` helper — `fillColor('#3b82f6')` — for an
1052
+ application-chosen CSS color; never `foregroundColor()` for a fill), `swatch: 'transparent'` for the
1053
+ no-color option (an outlined dot struck through diagonally), or a decorative
1054
+ `icon`. Keep every label visible: the swatch and the selected tint are
1055
+ supplementary. Name the group with `label`, or with `labelledBy` pointing at a
1056
+ visible `FieldLabel`.
1057
+
1058
+ ```tsx
1059
+ <FieldLabel id="command-color-label">Color</FieldLabel>
1060
+ <ChoiceChips
1061
+ name="color"
1062
+ labelledBy="command-color-label"
1063
+ value={command.color}
1064
+ action="select-command-color"
1065
+ choices={[
1066
+ { value: 'transparent', label: 'Transparent', swatch: 'transparent' },
1067
+ { value: 'blue', label: 'Blue', swatch: fillColor('#3b82f6') },
1068
+ { value: 'green', label: 'Green', swatch: fillColor('#22c55e') },
1069
+ ]}
1070
+ />
1071
+ ```
1072
+
1073
+ ### Wrapping multiple choices
1074
+
1075
+ When the person may turn any number of the visible options on, `value`
1076
+ becomes a `readonly Value[]` (the type rejects a single value, and a single
1077
+ group rejects an array) and `multiple` picks the model:
1078
+
1079
+ - `multiple: 'toggle'` — each pill toggles alone, as label filters or the
1080
+ intents an annotation carries do. The pills are native checkboxes in a
1081
+ `role="group"`: each pill is a Tab stop, a click or Space toggles it, and
1082
+ every checked value submits under `name`. Delegate the `action` on `change`
1083
+ and read the checked boxes by `name`, which lists them in choice order.
1084
+ - `multiple: true` — the desktop multi-select, for picking a working set
1085
+ where a plain click should mean "just this one". The group is an
1086
+ `aria-multiselectable` listbox: a click selects one chip, Cmd (Apple
1087
+ platforms) or Ctrl (elsewhere) toggles one, and Shift extends a range from
1088
+ the last plain or toggled chip. It is one Tab stop; arrows, Home, and End
1089
+ move the selection, Shift with them extends it, Cmd/Ctrl with them moves
1090
+ focus alone, Space toggles, and Cmd/Ctrl+A selects all. Wire it once with
1091
+ `wireChoiceChips` from `@kerfjs/ui/wire-choice-chips`; it fires
1092
+ `change` on the group (which carries the `action`), and `readChoiceChips`
1093
+ returns the new set. Hidden inputs submit each selected value under `name`.
1094
+
1095
+ A multiple group takes no `required`. Prefer a multiple `Select` when the
1096
+ option list is long or space is tight.
1097
+
1098
+ On dark inverse chrome, such as a media viewer, put the chips inside a dark
1099
+ appearance scope (`.wa-dark`, or any `color-scheme: dark` ancestor) rather
1100
+ than restyling them: every chip color is a theme token that follows the scope.
1101
+
1102
+ ```tsx
1103
+ <ChoiceChips
1104
+ name="intents"
1105
+ label="Annotation Intents"
1106
+ multiple="toggle"
1107
+ value={annotation.intents}
1108
+ action="toggle-annotation-intent"
1109
+ choices={[
1110
+ { value: 'comment', label: 'Comment' },
1111
+ { value: 'bug', label: 'Bug' },
1112
+ { value: 'question', label: 'Question' },
1113
+ ]}
1114
+ />
1115
+ ```
1116
+
1117
+ ```ts
1118
+ delegateActions(root, 'change', {
1119
+ 'toggle-annotation-intent': () => {
1120
+ annotation.intents = [
1121
+ ...root.querySelectorAll<HTMLInputElement>(
1122
+ 'input[name="intents"]:checked',
1123
+ ),
1124
+ ].map((box) => box.value);
1125
+ },
1126
+ });
1127
+ ```
1128
+
1129
+ ## Web Awesome integration
1130
+
1131
+ Kerf UI does not need Web Awesome. Every Kerf component renders native
1132
+ elements, reads only `--kui-*` tokens, and ships no Web Awesome code, so a
1133
+ Kerf-only application installs nothing else. Web Awesome is an optional
1134
+ integration for applications that already use it or need one of its
1135
+ specialized elements: import the CSS-only `@kerfjs/ui/webawesome.css` theme
1136
+ bridge, `@kerfjs/ui/webawesome` for Kerf JSX types, and each element's
1137
+ registration module. See the [Web Awesome theme contract](./webawesome-theme.md)
1138
+ and the [migration guide](./webawesome-migration.md).
1139
+
1140
+ Integration coverage means supported and themed, not preferred. The UX catalog
1141
+ lists those elements in its collapsed Web Awesome Integration section and tags
1142
+ every element a Kerf component replaces `Discouraged`. Never render a
1143
+ `Discouraged` element in application, demo, or recipe markup; use the Kerf
1144
+ component below, and file a component gap rather than dropping to the raw tag.
1145
+
1146
+ | Web Awesome element | Kerf choice |
1147
+ | --------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1148
+ | `wa-button`, `wa-dropdown`, `wa-dropdown-item` | Use `Button` (icon-only with `icon` and `ariaLabel`, or a toggle with `pressed`) for actions and `PopupMenu` for a command menu. Use `ListItem` for a navigation row and `Select` for a value. |
1149
+ | `wa-button-group` | Use `ToolbarControlGroup` or `SplitButton` for grouped actions and `SegmentedControl` for one-of-many selection. |
1150
+ | `wa-input`, `wa-textarea`, `wa-tag` | Use `TextField` for free text (`multiline` for a textarea) and `Chip` for removable or disabled tags; use `SearchField` only when text and ordered filter tokens form one editor. |
1151
+ | `wa-checkbox`, `wa-checkbox-group`, `wa-switch` | Use `Checkbox` for a submitted option (`CheckboxGroup` for a labeled set of them, or `ChoiceChips` `multiple: 'toggle'` for wrapping pills) and `Switch` for a setting that applies immediately. |
1152
+ | `wa-radio-group`, `wa-radio` | Use `RadioGroup` for a few labeled options, `ChoiceChips` for wrapping pills, and `SegmentedControl` for a view switch. |
1153
+ | `wa-select`, `wa-option` | Use `Select`, which owns Kerf spacing, controlled rendering, and form participation. |
1154
+ | `wa-dialog`, `wa-drawer` | Use `DialogSurface` with `openDialog` / `closeDialog` (`presentation="side-sheet"` or `"bottom-sheet"` for a drawer), or a `kerfjs/overlay` dialog. Use `CollapsiblePanel` for a rail that overlays content on compact devices. |
1155
+ | `wa-tab-group`, `wa-tab`, `wa-tab-panel` | Use `TabBar`/`TabBarItem` for application tabs or `SegmentedControl` for compact local views. |
1156
+ | `wa-icon` | Use `LucideIcon`. |
1157
+ | `wa-badge`, `wa-spinner`, `wa-skeleton` | Use `Badge`, `LoadingSpinner`, and `Skeleton`. |
1158
+ | `wa-split-panel` | Use `ResizableRegion` for application panes. |
1159
+ | `wa-progress-bar`, `wa-progress-ring` | Use `ProgressBar` (`@kerfjs/ui/progress-bar`, a native progress element) or, where a bar does not fit, `ProgressRing` (`@kerfjs/ui/progress-ring`). |
1160
+ | `wa-callout` | Use `StateBanner` for persistent inline status, alerts, and emphasized messages, and `EmptyState` for absent content. |
1161
+ | `wa-popover`, `wa-popup` | Use `AnchoredSurface` (`openAnchoredSurface` / `openAnchoredSurfaceAt`) for anchored help or popup content; place any other element with `positionAnchored()` or `autoReposition()` from `kerfjs/overlay`. |
1162
+ | `wa-card` | Use `ContentItem` (`appearance="surface"` with `frame="framed"` for a raised card) to contain related content, or `SunkenPanel` for a lowered region. |
1163
+ | `wa-page` | Compose the shell from `Workbench`, `SplitView`, `NavStack`, or `TabNavigator`. |
1164
+ | `wa-tooltip` | Call `tooltip()` from `kerfjs/overlay` with `@kerfjs/ui/overlay-tooltip.css` imported (pass `exitClass: 'kui-tooltip-exit'`, `exitDuration: 100`). Icon-only toolbar and popup controls already get help tags; a native `title` remains fine for a plain-text hint. |
1165
+ | `wa-toast`, `wa-toast-item` | Call `toast()` from `kerfjs/overlay` with `@kerfjs/ui/overlay-toast.css` imported (pass `exitClass: 'kui-toast-exit'`, `exitDuration: 200`); use a `StateBanner` in place for a persistent status. |
1166
+ | `wa-details`, `wa-accordion`, `wa-accordion-item` | Use `Disclosure` (`@kerfjs/ui/disclosure`), a native details element; Disclosures sharing a `name` form an accordion. |
1167
+ | `wa-slider` | Use `Slider` (`@kerfjs/ui/slider`), a native range input, with `wireSliders` for its live readout. |
1168
+ | `wa-tag-input` | Use `TagField` (`@kerfjs/ui/tag-field`) with `wireTagFields` for tags submitted as form values, or `SearchField` for search filters. |
1169
+ | `wa-color-picker` | Use `ColorField` (`@kerfjs/ui/color-field`) with `wireColorFields` for a color in a form, an inline `ColorPicker` when the color is the main task, or `ColorSwatches` for a fixed palette. |
1170
+ | `wa-include` | Fetch remote content with `resource()` from `kerfjs/async` and render it as Kerf content; never inject fetched markup, which bypasses kerf's `SafeHtml` escaping. |
1171
+ | `wa-scroller` | Let a `Pane` own vertical scrolling with its scroll edges (`wireScrollDividers`), or use `ColumnTrack` for a horizontal track. |
1172
+ | `wa-tree`, `wa-tree-item`, `wa-animated-image`, `wa-comparison` | Use only in an integration application, for the specialized behavior named by the component. |
1173
+ | `wa-zoomable-frame` | Avoid for application UI; keep embedded-media behavior application-owned. |
184
1174
 
185
1175
  All other entries in the [Web Awesome theme contract](./webawesome-theme.md#coverage)
186
- remain supported when their native semantic contract matches the product need.
1176
+ remain supported in an integration application when their native semantic
1177
+ contract matches the product need.
1178
+
1179
+ ### Toolbar width visibility
1180
+
1181
+ `ToolbarText` and `ToolbarControlGroup` accept typed `hideBelow` and
1182
+ `showBelow` CSS lengths. Call `wireToolbarVisibility` with the application root from
1183
+ `@kerfjs/ui/wire-toolbar-visibility` after mounting, and call its disposer when
1184
+ the application unmounts. The nearest Toolbar's **content-box width**, excluding
1185
+ padding, borders, and safe-area insets, determines visibility. `hideBelow={px(416)}`
1186
+ hides strictly below 416px; `showBelow={px(416)}` shows strictly below 416px. At
1187
+ 416px the first is visible and the second hidden. Together they define the visible
1188
+ interval `[hideBelow, showBelow)`. Width rules intersect existing visibility and
1189
+ expanded-state rules; they never force a CSS-hidden group visible.
1190
+
1191
+ Use `px`, `rem`, `em`, `pct`, `space`, `lengthVar`, or `calc`/`plus` to construct
1192
+ lengths. Percentages resolve against that content box, `em` uses the child item's
1193
+ font size, and custom properties use its inherited and own token context. The
1194
+ helper follows resizes, theme/token/font changes, inserted items, nested toolbars,
1195
+ and relocated groups. Invalid, unresolved, negative, or contradictory thresholds
1196
+ leave the item visible under this width policy. Server-rendered content is visible
1197
+ until wiring runs; without browser observers, initial wiring and window resize
1198
+ still update it. Dispose to remove measurement probes and restore prior markers.
1199
+
1200
+ Hidden controls leave layout and keyboard navigation. A hidden busy group also
1201
+ hides only its own adjacent busy status. Keep primary actions always available;
1202
+ show a complementary overflow group for secondary actions at narrow widths.