@kerfjs/ui 5.0.0-beta.95 → 5.0.0-beta.96

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 (385) hide show
  1. package/README.md +95 -55
  2. package/ai/component-catalog.json +1328 -94
  3. package/ai/component-composition-rules.json +11 -0
  4. package/ai/component-composition.d.ts +3 -0
  5. package/ai/component-composition.json +955 -23
  6. package/ai/component-composition.schema.json +4 -0
  7. package/ai/components/README.md +12 -0
  8. package/ai/components/badge.md +6 -2
  9. package/ai/components/choice-chips.md +80 -0
  10. package/ai/components/column-track.md +78 -0
  11. package/ai/components/combobox.md +88 -0
  12. package/ai/components/content-item.md +2 -0
  13. package/ai/components/content-swap.md +78 -0
  14. package/ai/components/corner-status.md +88 -0
  15. package/ai/components/document-baseline.md +3 -1
  16. package/ai/components/edge-activity-indicator.md +81 -0
  17. package/ai/components/file-picker.md +88 -0
  18. package/ai/components/foundation.md +1 -1
  19. package/ai/components/framed-list.md +80 -0
  20. package/ai/components/grid.md +2 -1
  21. package/ai/components/icon-button.md +82 -0
  22. package/ai/components/icon-toggle-button.md +80 -0
  23. package/ai/components/list-action-row.md +19 -7
  24. package/ai/components/list-item.md +16 -7
  25. package/ai/components/list.md +5 -2
  26. package/ai/components/nav-stack.md +2 -1
  27. package/ai/components/popup-menu.md +2 -2
  28. package/ai/components/row.md +1 -1
  29. package/ai/components/select.md +2 -1
  30. package/ai/components/split-button.md +80 -0
  31. package/ai/components/split-view.md +1 -1
  32. package/ai/components/state-banner.md +4 -2
  33. package/ai/components/summary-row.md +85 -0
  34. package/ai/components/sunken-panel.md +1 -1
  35. package/ai/components/surface-scaffold.md +8 -2
  36. package/ai/components/text.md +3 -0
  37. package/ai/components/toolbar-control-group.md +4 -2
  38. package/ai/components/toolbar-text.md +1 -0
  39. package/ai/components/toolbar.md +1 -0
  40. package/ai/components/value-table.md +9 -2
  41. package/ai/components/wa-button-group.md +2 -1
  42. package/ai/components/wa-button.md +5 -1
  43. package/ai/public-api-signatures-v1.md +1063 -52
  44. package/ai/skill.md +54 -52
  45. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  46. package/dist/anchored-surface.d.ts +13 -2
  47. package/dist/anchored-surface.js +1 -1
  48. package/dist/app-tab.js +1 -1
  49. package/dist/badge.d.ts +31 -2
  50. package/dist/badge.js +2 -1
  51. package/dist/browser/choice-chips.js +3 -0
  52. package/dist/browser/column-track.js +3 -0
  53. package/dist/browser/combobox.js +3 -0
  54. package/dist/browser/content-swap.js +3 -0
  55. package/dist/browser/corner-status.js +3 -0
  56. package/dist/browser/edge-activity-indicator.js +3 -0
  57. package/dist/browser/file-picker.js +3 -0
  58. package/dist/browser/framed-list.js +3 -0
  59. package/dist/browser/icon-button.js +4 -0
  60. package/dist/browser/icon-toggle-button.js +4 -0
  61. package/dist/browser/list-action-row.js +1 -0
  62. package/dist/browser/split-button.js +5 -0
  63. package/dist/browser/summary-row.js +3 -0
  64. package/dist/catalog-resources.d.ts +1 -0
  65. package/dist/catalog.d.ts +1 -0
  66. package/dist/catalog.js +16 -13
  67. package/dist/catalog.js.map +1 -1
  68. package/dist/chip.d.ts +1 -0
  69. package/dist/choice-chips.d.ts +58 -0
  70. package/dist/choice-chips.js +3 -0
  71. package/dist/choice-chips.js.map +1 -0
  72. package/dist/chunk-2MSPNRWJ.js +82 -0
  73. package/dist/chunk-2MSPNRWJ.js.map +1 -0
  74. package/dist/{chunk-3PO7JEK7.js → chunk-36TL6BCR.js} +18 -4
  75. package/dist/chunk-36TL6BCR.js.map +1 -0
  76. package/dist/{chunk-MORVLMDG.js → chunk-44A6LP54.js} +3 -3
  77. package/dist/chunk-44A6LP54.js.map +1 -0
  78. package/dist/{chunk-7QQ3HE47.js → chunk-4LOK4634.js} +7 -3
  79. package/dist/chunk-4LOK4634.js.map +1 -0
  80. package/dist/chunk-4UB5Z3ZZ.js +68 -0
  81. package/dist/chunk-4UB5Z3ZZ.js.map +1 -0
  82. package/dist/{chunk-PGL6TXFW.js → chunk-6BRRUPJY.js} +6 -2
  83. package/dist/chunk-6BRRUPJY.js.map +1 -0
  84. package/dist/{chunk-KAJVVN7Q.js → chunk-6NOLL5KG.js} +2 -2
  85. package/dist/{chunk-KAJVVN7Q.js.map → chunk-6NOLL5KG.js.map} +1 -1
  86. package/dist/{chunk-IOS2NXW7.js → chunk-76PWEN5Y.js} +13 -2
  87. package/dist/chunk-76PWEN5Y.js.map +1 -0
  88. package/dist/{chunk-B3TROLC2.js → chunk-7IUEBNCO.js} +7 -3
  89. package/dist/chunk-7IUEBNCO.js.map +1 -0
  90. package/dist/{chunk-75YOTZ25.js → chunk-AYHC62OZ.js} +10 -6
  91. package/dist/chunk-AYHC62OZ.js.map +1 -0
  92. package/dist/{chunk-RZYQFGMM.js → chunk-BBU2SPRE.js} +4 -4
  93. package/dist/{chunk-RZYQFGMM.js.map → chunk-BBU2SPRE.js.map} +1 -1
  94. package/dist/{chunk-QCLLBMLA.js → chunk-BU23Z5HZ.js} +37 -12
  95. package/dist/chunk-BU23Z5HZ.js.map +1 -0
  96. package/dist/{chunk-BYHGRKC3.js → chunk-CMLPFIC5.js} +3 -1
  97. package/dist/chunk-CMLPFIC5.js.map +1 -0
  98. package/dist/{chunk-3XPGJUUQ.js → chunk-D5RGM3XA.js} +3 -2
  99. package/dist/chunk-D5RGM3XA.js.map +1 -0
  100. package/dist/chunk-EIET4QLK.js +51 -0
  101. package/dist/chunk-EIET4QLK.js.map +1 -0
  102. package/dist/chunk-ETCWQLJV.js +85 -0
  103. package/dist/chunk-ETCWQLJV.js.map +1 -0
  104. package/dist/chunk-FDZNYD4C.js +138 -0
  105. package/dist/chunk-FDZNYD4C.js.map +1 -0
  106. package/dist/{chunk-XKZPBRU7.js → chunk-FOQK4F3L.js} +25 -5
  107. package/dist/chunk-FOQK4F3L.js.map +1 -0
  108. package/dist/{chunk-FL6J644M.js → chunk-GJYQ27C2.js} +4 -2
  109. package/dist/chunk-GJYQ27C2.js.map +1 -0
  110. package/dist/{chunk-DL55BSQX.js → chunk-GZE2XVKC.js} +8 -1
  111. package/dist/chunk-GZE2XVKC.js.map +1 -0
  112. package/dist/{chunk-YP2G67S7.js → chunk-HO6FU3G7.js} +2 -2
  113. package/dist/{chunk-YP2G67S7.js.map → chunk-HO6FU3G7.js.map} +1 -1
  114. package/dist/{chunk-3DXHNLME.js → chunk-IGTWXPTN.js} +25 -8
  115. package/dist/chunk-IGTWXPTN.js.map +1 -0
  116. package/dist/chunk-IKS72C6P.js +53 -0
  117. package/dist/chunk-IKS72C6P.js.map +1 -0
  118. package/dist/chunk-JYD7G4RG.js +130 -0
  119. package/dist/chunk-JYD7G4RG.js.map +1 -0
  120. package/dist/{chunk-LAZLBC2Q.js → chunk-KH4KEMSP.js} +33 -2
  121. package/dist/chunk-KH4KEMSP.js.map +1 -0
  122. package/dist/chunk-LL45C7BB.js +122 -0
  123. package/dist/chunk-LL45C7BB.js.map +1 -0
  124. package/dist/chunk-M2NRCFRO.js +45 -0
  125. package/dist/chunk-M2NRCFRO.js.map +1 -0
  126. package/dist/chunk-MJ5RU6XT.js +173 -0
  127. package/dist/chunk-MJ5RU6XT.js.map +1 -0
  128. package/dist/{chunk-GIUOXAVL.js → chunk-P74VXMB6.js} +39 -19
  129. package/dist/chunk-P74VXMB6.js.map +1 -0
  130. package/dist/{chunk-TKDDTLG5.js → chunk-PBT3CPPY.js} +31 -3
  131. package/dist/chunk-PBT3CPPY.js.map +1 -0
  132. package/dist/chunk-PRG4CL3Q.js +88 -0
  133. package/dist/chunk-PRG4CL3Q.js.map +1 -0
  134. package/dist/chunk-QH5KOFNS.js +39 -0
  135. package/dist/chunk-QH5KOFNS.js.map +1 -0
  136. package/dist/{chunk-CD5TOO22.js → chunk-QIAPOWHH.js} +2 -2
  137. package/dist/{chunk-CD5TOO22.js.map → chunk-QIAPOWHH.js.map} +1 -1
  138. package/dist/chunk-QQ3TTWFH.js +29 -0
  139. package/dist/chunk-QQ3TTWFH.js.map +1 -0
  140. package/dist/chunk-QYMJHS4K.js +36 -0
  141. package/dist/chunk-QYMJHS4K.js.map +1 -0
  142. package/dist/chunk-R42D2BAO.js +44 -0
  143. package/dist/chunk-R42D2BAO.js.map +1 -0
  144. package/dist/chunk-S2XULQEK.js +52 -0
  145. package/dist/chunk-S2XULQEK.js.map +1 -0
  146. package/dist/{chunk-NMWDHZVM.js → chunk-S4Y3YTAI.js} +2 -2
  147. package/dist/{chunk-NMWDHZVM.js.map → chunk-S4Y3YTAI.js.map} +1 -1
  148. package/dist/{chunk-O27D24CA.js → chunk-TDMHA7C3.js} +3 -2
  149. package/dist/chunk-TDMHA7C3.js.map +1 -0
  150. package/dist/chunk-U6QYTMDB.js +85 -0
  151. package/dist/chunk-U6QYTMDB.js.map +1 -0
  152. package/dist/{chunk-QQICWWNX.js → chunk-V6W56V3N.js} +18 -7
  153. package/dist/chunk-V6W56V3N.js.map +1 -0
  154. package/dist/chunk-W4IK7AWD.js +73 -0
  155. package/dist/chunk-W4IK7AWD.js.map +1 -0
  156. package/dist/{chunk-TNG3XKHB.js → chunk-Y3LC7JQO.js} +26 -8
  157. package/dist/chunk-Y3LC7JQO.js.map +1 -0
  158. package/dist/chunk-YWQGSUF2.js +84 -0
  159. package/dist/chunk-YWQGSUF2.js.map +1 -0
  160. package/dist/{chunk-MTCTX25G.js → chunk-YXOMI7ES.js} +1 -1
  161. package/dist/chunk-YXOMI7ES.js.map +1 -0
  162. package/dist/chunk-ZKKO4MHC.js +25 -0
  163. package/dist/chunk-ZKKO4MHC.js.map +1 -0
  164. package/dist/collapsible-panel.d.ts +10 -3
  165. package/dist/collapsible-panel.js +8 -5
  166. package/dist/collapsible-panel.js.map +1 -1
  167. package/dist/column-track.d.ts +41 -0
  168. package/dist/column-track.js +4 -0
  169. package/dist/column-track.js.map +1 -0
  170. package/dist/combobox.d.ts +40 -0
  171. package/dist/combobox.js +3 -0
  172. package/dist/combobox.js.map +1 -0
  173. package/dist/content-item.d.ts +21 -4
  174. package/dist/content-item.js +1 -1
  175. package/dist/content-swap.d.ts +34 -0
  176. package/dist/content-swap.js +3 -0
  177. package/dist/content-swap.js.map +1 -0
  178. package/dist/corner-status.d.ts +36 -0
  179. package/dist/corner-status.js +3 -0
  180. package/dist/corner-status.js.map +1 -0
  181. package/dist/edge-activity-indicator.d.ts +28 -0
  182. package/dist/edge-activity-indicator.js +3 -0
  183. package/dist/edge-activity-indicator.js.map +1 -0
  184. package/dist/extension-attributes-mu8MFUl0.d.ts +13 -0
  185. package/dist/file-picker.d.ts +47 -0
  186. package/dist/file-picker.js +3 -0
  187. package/dist/file-picker.js.map +1 -0
  188. package/dist/framed-list.d.ts +47 -0
  189. package/dist/framed-list.js +4 -0
  190. package/dist/framed-list.js.map +1 -0
  191. package/dist/grid.js +1 -1
  192. package/dist/help-tags-register.js +1 -1
  193. package/dist/icon-button.d.ts +46 -0
  194. package/dist/icon-button.js +6 -0
  195. package/dist/icon-button.js.map +1 -0
  196. package/dist/icon-toggle-button.d.ts +42 -0
  197. package/dist/icon-toggle-button.js +6 -0
  198. package/dist/icon-toggle-button.js.map +1 -0
  199. package/dist/index.d.ts +23 -6
  200. package/dist/index.js +44 -27
  201. package/dist/list-action-row.d.ts +47 -10
  202. package/dist/list-action-row.js +2 -1
  203. package/dist/list-header.js +1 -1
  204. package/dist/list-inset-text.js +1 -1
  205. package/dist/list-item.d.ts +10 -2
  206. package/dist/list-item.js +1 -1
  207. package/dist/list.d.ts +37 -5
  208. package/dist/list.js +1 -1
  209. package/dist/nav-stack.d.ts +1 -0
  210. package/dist/nav-stack.js +2 -1
  211. package/dist/pane.js +2 -1
  212. package/dist/popup-menu-register.js +18 -1
  213. package/dist/popup-menu-register.js.map +1 -1
  214. package/dist/popup-menu.d.ts +28 -3
  215. package/dist/popup-menu.js +1 -1
  216. package/dist/row.d.ts +6 -2
  217. package/dist/row.js +1 -1
  218. package/dist/select-register.js +1 -1
  219. package/dist/select.js +2 -1
  220. package/dist/split-button.d.ts +57 -0
  221. package/dist/split-button.js +7 -0
  222. package/dist/split-button.js.map +1 -0
  223. package/dist/split-view.d.ts +20 -2
  224. package/dist/split-view.js +22 -1
  225. package/dist/split-view.js.map +1 -1
  226. package/dist/state-banner.d.ts +17 -2
  227. package/dist/state-banner.js +2 -1
  228. package/dist/styles/badge.css +27 -0
  229. package/dist/styles/catalog/components/catalog-example.css +7 -3
  230. package/dist/styles/choice-chips.css +154 -0
  231. package/dist/styles/column-track.css +57 -0
  232. package/dist/styles/combobox.css +113 -0
  233. package/dist/styles/components/actions/icon-button/icon-button.css +22 -0
  234. package/dist/styles/components/actions/icon-toggle-button/icon-toggle-button.css +83 -0
  235. package/dist/styles/components/actions/popup-menu/popup-menu.css +69 -1
  236. package/dist/styles/components/actions/split-button/split-button.css +95 -0
  237. package/dist/styles/components/actions/toolbar/toolbar.css +16 -9
  238. package/dist/styles/components/actions/toolbar-control-group/toolbar-control-group.css +144 -48
  239. package/dist/styles/components/actions/toolbar-text/toolbar-text.css +23 -0
  240. package/dist/styles/components/collections/framed-list/framed-list.css +47 -0
  241. package/dist/styles/components/collections/list/list.css +44 -0
  242. package/dist/styles/components/collections/list-action-row/list-action-row.css +39 -0
  243. package/dist/styles/components/collections/list-item/list-item.css +45 -0
  244. package/dist/styles/components/collections/summary-row/summary-row.css +161 -0
  245. package/dist/styles/components/data-display/value-table/value-table.css +76 -0
  246. package/dist/styles/components/feedback/badge/badge.css +27 -0
  247. package/dist/styles/components/feedback/corner-status/corner-status.css +60 -0
  248. package/dist/styles/components/feedback/edge-activity-indicator/edge-activity-indicator.css +127 -0
  249. package/dist/styles/components/feedback/state-banner/state-banner.css +38 -0
  250. package/dist/styles/components/forms/choice-chips/choice-chips.css +154 -0
  251. package/dist/styles/components/forms/combobox/combobox.css +113 -0
  252. package/dist/styles/components/forms/file-picker/file-picker.css +81 -0
  253. package/dist/styles/components/forms/token-search-field/token-search-field.css +12 -1
  254. package/dist/styles/components/layout/column-track/column-track.css +57 -0
  255. package/dist/styles/components/layout/content-swap/content-swap.css +154 -0
  256. package/dist/styles/components/layout/pane/pane.css +2 -8
  257. package/dist/styles/components/layout/workbench/workbench.css +2 -8
  258. package/dist/styles/components/navigation/tab-navigator/tab-navigator.css +1 -4
  259. package/dist/styles/components/surfaces/content-item/content-item.css +18 -0
  260. package/dist/styles/components/surfaces/sunken-panel/sunken-panel.css +1 -4
  261. package/dist/styles/components/surfaces/surface-scaffold/surface-scaffold.css +119 -0
  262. package/dist/styles/components/typography/text/text.css +62 -0
  263. package/dist/styles/content-item.css +18 -0
  264. package/dist/styles/content-swap.css +154 -0
  265. package/dist/styles/corner-status.css +60 -0
  266. package/dist/styles/document.css +65 -0
  267. package/dist/styles/edge-activity-indicator.css +127 -0
  268. package/dist/styles/file-picker.css +81 -0
  269. package/dist/styles/foundation.css +8 -0
  270. package/dist/styles/framed-list.css +47 -0
  271. package/dist/styles/icon-button.css +22 -0
  272. package/dist/styles/icon-toggle-button.css +83 -0
  273. package/dist/styles/list-action-row.css +39 -0
  274. package/dist/styles/list-item.css +45 -0
  275. package/dist/styles/list.css +44 -0
  276. package/dist/styles/pane.css +2 -8
  277. package/dist/styles/popup-menu.css +69 -1
  278. package/dist/styles/split-button.css +95 -0
  279. package/dist/styles/state-banner.css +38 -0
  280. package/dist/styles/styles.css +12 -0
  281. package/dist/styles/summary-row.css +161 -0
  282. package/dist/styles/sunken-panel.css +1 -4
  283. package/dist/styles/surface-scaffold.css +119 -0
  284. package/dist/styles/tab-navigator.css +1 -4
  285. package/dist/styles/text.css +62 -0
  286. package/dist/styles/token-search-field.css +12 -1
  287. package/dist/styles/toolbar-control-group.css +144 -48
  288. package/dist/styles/toolbar-text.css +23 -0
  289. package/dist/styles/toolbar.css +16 -9
  290. package/dist/styles/value-table.css +76 -0
  291. package/dist/styles/webawesome.css +4 -4
  292. package/dist/styles/workbench.css +2 -8
  293. package/dist/summary-row.d.ts +56 -0
  294. package/dist/summary-row.js +4 -0
  295. package/dist/summary-row.js.map +1 -0
  296. package/dist/sunken-panel.d.ts +8 -1
  297. package/dist/sunken-panel.js +2 -1
  298. package/dist/surface-scaffold-register.js +7 -1
  299. package/dist/surface-scaffold-register.js.map +1 -1
  300. package/dist/surface-scaffold.d.ts +75 -2
  301. package/dist/surface-scaffold.js +2 -1
  302. package/dist/tab-navigator.js +4 -1
  303. package/dist/tab-navigator.js.map +1 -1
  304. package/dist/text.d.ts +39 -4
  305. package/dist/text.js +1 -1
  306. package/dist/toolbar-control-group.d.ts +8 -1
  307. package/dist/toolbar-control-group.js +1 -1
  308. package/dist/toolbar-text.d.ts +14 -1
  309. package/dist/toolbar-text.js +1 -1
  310. package/dist/toolbar.d.ts +14 -3
  311. package/dist/toolbar.js +1 -1
  312. package/dist/value-table.d.ts +20 -2
  313. package/dist/value-table.js +1 -1
  314. package/dist/wire-catalog.d.ts +1 -0
  315. package/dist/wire-comboboxes.d.ts +26 -0
  316. package/dist/wire-comboboxes.js +3 -0
  317. package/dist/wire-comboboxes.js.map +1 -0
  318. package/dist/wire-corner-status.d.ts +11 -0
  319. package/dist/wire-corner-status.js +3 -0
  320. package/dist/wire-corner-status.js.map +1 -0
  321. package/dist/wire-file-pickers.d.ts +26 -0
  322. package/dist/wire-file-pickers.js +3 -0
  323. package/dist/wire-file-pickers.js.map +1 -0
  324. package/dist/wire-list-reorder.d.ts +41 -0
  325. package/dist/wire-list-reorder.js +3 -0
  326. package/dist/wire-list-reorder.js.map +1 -0
  327. package/dist/wire-token-search-fields.js +1 -1
  328. package/dist/workbench.d.ts +1 -0
  329. package/dist/workbench.js +2 -1
  330. package/docs/accessibility.md +45 -2
  331. package/docs/anchored-surface.md +15 -7
  332. package/docs/app-layouts.md +2 -1
  333. package/docs/component-contract.md +26 -6
  334. package/docs/component-selection.md +149 -13
  335. package/docs/design/templates/choice-chips/color-palette-dark.svg +1 -0
  336. package/docs/design/templates/choice-chips/color-palette.svg +1 -0
  337. package/docs/design/templates/choice-chips/compact-icons-dark.svg +1 -0
  338. package/docs/design/templates/choice-chips/compact-icons.svg +1 -0
  339. package/docs/design/templates/choice-chips-dark.svg +1 -0
  340. package/docs/design/templates/choice-chips.svg +1 -0
  341. package/docs/design/templates/list-action-row/trailing-menu-dark.svg +1 -0
  342. package/docs/design/templates/list-action-row/trailing-menu.svg +1 -0
  343. package/docs/design/templates/list-action-row-dark.svg +1 -1
  344. package/docs/design/templates/list-action-row.svg +1 -1
  345. package/docs/design/templates/state-banner/strip-dark.svg +1 -0
  346. package/docs/design/templates/state-banner/strip.svg +1 -0
  347. package/docs/design/templates/state-banner-dark.svg +1 -1
  348. package/docs/design/templates/state-banner.svg +1 -1
  349. package/docs/design/templates.md +1 -1
  350. package/docs/document-baseline.md +51 -0
  351. package/docs/layout.md +52 -1
  352. package/docs/split-view.md +20 -2
  353. package/docs/sunken-panel.md +13 -0
  354. package/docs/surface-scaffold.md +66 -1
  355. package/docs/ux-demo.md +1 -0
  356. package/docs/webawesome-theme.md +6 -2
  357. package/llms.txt +125 -16
  358. package/package.json +89 -1
  359. package/dist/chunk-3DXHNLME.js.map +0 -1
  360. package/dist/chunk-3PO7JEK7.js.map +0 -1
  361. package/dist/chunk-3XPGJUUQ.js.map +0 -1
  362. package/dist/chunk-4Y4L5YEI.js +0 -66
  363. package/dist/chunk-4Y4L5YEI.js.map +0 -1
  364. package/dist/chunk-75YOTZ25.js.map +0 -1
  365. package/dist/chunk-7QQ3HE47.js.map +0 -1
  366. package/dist/chunk-A7DYEERU.js +0 -59
  367. package/dist/chunk-A7DYEERU.js.map +0 -1
  368. package/dist/chunk-B3TROLC2.js.map +0 -1
  369. package/dist/chunk-BYHGRKC3.js.map +0 -1
  370. package/dist/chunk-DL55BSQX.js.map +0 -1
  371. package/dist/chunk-FL6J644M.js.map +0 -1
  372. package/dist/chunk-GIUOXAVL.js.map +0 -1
  373. package/dist/chunk-IOS2NXW7.js.map +0 -1
  374. package/dist/chunk-J3AWE5I4.js +0 -50
  375. package/dist/chunk-J3AWE5I4.js.map +0 -1
  376. package/dist/chunk-LAZLBC2Q.js.map +0 -1
  377. package/dist/chunk-MORVLMDG.js.map +0 -1
  378. package/dist/chunk-MTCTX25G.js.map +0 -1
  379. package/dist/chunk-O27D24CA.js.map +0 -1
  380. package/dist/chunk-PGL6TXFW.js.map +0 -1
  381. package/dist/chunk-QCLLBMLA.js.map +0 -1
  382. package/dist/chunk-QQICWWNX.js.map +0 -1
  383. package/dist/chunk-TKDDTLG5.js.map +0 -1
  384. package/dist/chunk-TNG3XKHB.js.map +0 -1
  385. package/dist/chunk-XKZPBRU7.js.map +0 -1
@@ -7,7 +7,9 @@
7
7
  {
8
8
  "export": "wireCatalog",
9
9
  "import": "@kerfjs/ui/wire-catalog",
10
- "provides": ["wireScrollDividers"]
10
+ "provides": [
11
+ "wireScrollDividers"
12
+ ]
11
13
  }
12
14
  ],
13
15
  "entries": [
@@ -41,11 +43,15 @@
41
43
  "quiet, solid, or outline appearance",
42
44
  "pill or rounded shape",
43
45
  "compact or default size, or a text-free dot (size: 'dot')",
44
- "labeled or decorative duplicate"
46
+ "labeled or decorative duplicate",
47
+ "leading icon",
48
+ "title tooltip and data-* rootAttributes",
49
+ "maxWidth caps the badge and truncates long text with an ellipsis, defaulting the title to string or number content"
45
50
  ],
46
51
  "accessibility": [
47
52
  "Badge is non-interactive. Supply label when visible content is abbreviated, and ariaHidden when it repeats an accessible name owned by the surrounding component. A text-free dot must take either label (exposed as an image) or ariaHidden, which the types enforce.",
48
- "Keep meaningful text visible because tone is supplementary."
53
+ "Keep meaningful text visible because tone is supplementary.",
54
+ "A label replaces abbreviated or symbolic visible text; the badge is then a labeled image (role img)."
49
55
  ],
50
56
  "geometry": {
51
57
  "margin": "none",
@@ -61,7 +67,9 @@
61
67
  },
62
68
  "wiring": [],
63
69
  "publicClasses": [
64
- "kui-badge"
70
+ "kui-badge",
71
+ "kui-badge__icon",
72
+ "kui-badge__label"
65
73
  ],
66
74
  "publicTokens": [],
67
75
  "links": {
@@ -394,6 +402,8 @@
394
402
  "--kui-color-surface",
395
403
  "--kui-color-surface-raised",
396
404
  "--kui-color-surface-lowered",
405
+ "--kui-sunken-texture",
406
+ "--kui-sunken-surface",
397
407
  "--kui-color-text",
398
408
  "--kui-color-text-quiet",
399
409
  "--kui-color-text-link",
@@ -472,7 +482,7 @@
472
482
  "category": "Foundation",
473
483
  "kind": "composition",
474
484
  "source": "kerf",
475
- "description": "Opt-in document-level defaults: border-box sizing, body margin/font/surface, native table-cell and form-control font metrics, link color, and the html → body → .kui-app-root full-height chain.",
485
+ "description": "Opt-in document-level defaults: border-box sizing, body margin/font/surface, native table-cell and form-control font metrics, semantic control cursors, link color, and the html → body → .kui-app-root full-height chain.",
476
486
  "uses": [],
477
487
  "purpose": "Let an application opt into Kerf UI-owned document defaults and a definite full-height chain for a percentage-height application shell.",
478
488
  "publicExports": [],
@@ -497,10 +507,12 @@
497
507
  ],
498
508
  "variants": [
499
509
  "document-flow page (no .kui-app-root)",
500
- "full-height application root"
510
+ "full-height application root",
511
+ "viewport-locked application root (data-viewport=\"locked\" on a body-child .kui-app-root: 100dvh and overflow clip on html, body, and the root)"
501
512
  ],
502
513
  "accessibility": [
503
- "Links keep the semantic link color at zero specificity so application focus and link styles still apply."
514
+ "Links keep the semantic link color at zero specificity so application focus and link styles still apply.",
515
+ "Native controls get semantic cursors at zero specificity: pointer on enabled buttons, links, role=button, checkbox/radio/button-type inputs, selects, and checkbox/radio labels; not-allowed on disabled controls, aria-disabled role=button, and a disabled wa-button's base part; text on text-like inputs and textareas."
504
516
  ],
505
517
  "geometry": {
506
518
  "margin": "none",
@@ -671,7 +683,7 @@
671
683
  "border": "conditional",
672
684
  "padding": "child",
673
685
  "notes": [
674
- "The pane is unpadded; separators are independently opt-in on logical edges and default off.",
686
+ "The pane is unpadded; separators are independently opt-in on logical edges and default off.",
675
687
  "Safe areas: the root and separators paint through unsafe areas while header, content, and footer pad the sides the pane still reaches (routed by --kui-edge-inset-*); content block insets are scroll padding.",
676
688
  "The scrolling content exposes its resolved logical inline padding to descendants as --kui-pane-content-inset-inline-start/end, including safe areas and deepInset.",
677
689
  "deepInset adds --kui-space-xs to every side of the scrolling content and its block scroll padding; header/footer chrome still owns safe-area padding at its edge.",
@@ -767,6 +779,11 @@
767
779
  "id": "tab-navigator",
768
780
  "relationship": "composes-with",
769
781
  "when": "Use one NavStack as each TabNavigator tab's persistent content."
782
+ },
783
+ {
784
+ "id": "content-swap",
785
+ "relationship": "nearest",
786
+ "when": "Use ContentSwap to swap content in place inside one region without navigation chrome."
770
787
  }
771
788
  ],
772
789
  "appOwns": [
@@ -932,7 +949,7 @@
932
949
  "back action"
933
950
  ],
934
951
  "variants": [
935
- "fixed roomy split",
952
+ "fixed roomy split with listWidth: a pixel size, optionally capped at a fraction of the split's width",
936
953
  "resizable roomy split",
937
954
  "collapsed resizable list with a restore control",
938
955
  "compact list",
@@ -1471,7 +1488,8 @@
1471
1488
  "uses": [],
1472
1489
  "purpose": "Group a vertical list of application content on a visually lowered surface with one owned 8px inset and an explicit rounded or square-corner shape.",
1473
1490
  "publicExports": [
1474
- "SunkenPanel"
1491
+ "SunkenPanel",
1492
+ "ensureSunkenTexture"
1475
1493
  ],
1476
1494
  "useWhen": [
1477
1495
  "A main content region or nested work area needs a darker/lowered background and one compact inset around a vertical stack.",
@@ -1578,6 +1596,7 @@
1578
1596
  "trailing priority for an expanded trailing control at compact or narrow widths",
1579
1597
  "trailing groups and a standalone primary wa-button wrap instead of clipping",
1580
1598
  "outer inset independently configurable from zone gap",
1599
+ "compact density: a 40px header (34px band, 3px block insets) for an embedded panel, filled with compact ToolbarControlGroups",
1581
1600
  "app bar or bottom bar claiming its screen edges (safeAreaEdges)",
1582
1601
  "typed hideBelow/showBelow thresholds at the nearest Toolbar content width"
1583
1602
  ],
@@ -1713,6 +1732,11 @@
1713
1732
  {
1714
1733
  "id": "wa-button-group",
1715
1734
  "relationship": "prefer-over"
1735
+ },
1736
+ {
1737
+ "id": "icon-toggle-button",
1738
+ "relationship": "nearest",
1739
+ "when": "Outside a Toolbar, a standalone icon-only toggle is an IconToggleButton."
1716
1740
  }
1717
1741
  ],
1718
1742
  "appOwns": [
@@ -1730,7 +1754,7 @@
1730
1754
  "default or compact size",
1731
1755
  "comfortable or tight density",
1732
1756
  "icon, text, mixed, or avatar content",
1733
- "raised, filled, or outline selected chrome",
1757
+ "raised, filled, outline, or no selected chrome (group-wide or one control via data-selected-chrome=\"none\")",
1734
1758
  "brand, neutral, or pop selected tone",
1735
1759
  "nested dropdown trigger",
1736
1760
  "standard, compact, or list-zero dropdown menu inset",
@@ -1745,6 +1769,7 @@
1745
1769
  ],
1746
1770
  "accessibility": [
1747
1771
  "Name the group when its relationship is not evident from context.",
1772
+ "A disabled native button (disabled, or aria-disabled=\"true\" when it must stay focusable) dims to half opacity with the not-allowed cursor and no hover surface; a disabled raw wa-button paints no hover surface either. Do not add disabled styling yourself.",
1748
1773
  "Name an icon-only button or link with aria-label, not title. Once any help-tag installer is imported (select/register, popup-menu/register, or help-tags/register), it shows an aria-hidden Web Awesome help tag repeating that name after a 500ms hover and at once on keyboard focus, hidden on a press and on Escape, and never joins aria-labelledby. A native title keeps the browser tooltip and gets no second tag."
1749
1774
  ],
1750
1775
  "geometry": {
@@ -1901,12 +1926,14 @@
1901
1926
  "purpose": "Configure recurring dialog and popup geometry without consumer ::part() overrides.",
1902
1927
  "publicExports": [
1903
1928
  "DialogSurface",
1929
+ "PopoverDialogSurface",
1904
1930
  "PopupSurface"
1905
1931
  ],
1906
1932
  "useWhen": [
1907
1933
  "A Web Awesome dialog or dropdown needs a standard size, presentation, body/footer inset, or list-compatible menu inset.",
1908
1934
  "A dialog body should compose rows, sections, or aligned bare prose through List and ListInsetText.",
1909
- "A modal needs a typed preferred width, viewport gutter, or dynamic viewport-bounded height cap while retaining native body scrolling and footer actions."
1935
+ "A modal needs a typed preferred width, viewport gutter, or dynamic viewport-bounded height cap while retaining native body scrolling and footer actions.",
1936
+ "A dialog that must leave the page interactive and close on Escape or an outside press uses PopoverDialogSurface; one that fills its body with a SplitView or Pane uses height and bodyLayout=\"fill\"."
1910
1937
  ],
1911
1938
  "avoidWhen": [
1912
1939
  "Do not use it as a generic layout wrapper or to replace application-owned modal state and focus lifecycle.",
@@ -1922,8 +1949,11 @@
1922
1949
  ],
1923
1950
  "variants": [
1924
1951
  "small, medium, or large dialog",
1952
+ "data-* rootAttributes (a data-key) so sibling dialogs morph by identity",
1925
1953
  "modal, side-sheet, or fullscreen dialog",
1926
1954
  "typed modal preferred width, viewport gutter, and maximum height, including viewport cap",
1955
+ "definite viewport-bounded modal height and a fill body layout for one child",
1956
+ "non-modal light-dismiss PopoverDialogSurface, overlay or embedded in flow",
1927
1957
  "none, compact, or comfortable body and footer inset",
1928
1958
  "standard, compact, or zero-inset popup menu"
1929
1959
  ],
@@ -1948,6 +1978,7 @@
1948
1978
  "wiring": [],
1949
1979
  "publicClasses": [
1950
1980
  "kui-dialog-surface",
1981
+ "kui-popover-dialog-surface",
1951
1982
  "kui-popup-surface"
1952
1983
  ],
1953
1984
  "publicTokens": [
@@ -2185,6 +2216,7 @@
2185
2216
  "small",
2186
2217
  "xsmall",
2187
2218
  "placeholder (loading)",
2219
+ "description: quiet single-line supporting copy under a read-only title, aligned with its text, with descriptionId for aria-describedby",
2188
2220
  "dark (loud-surface foreground)",
2189
2221
  "typed hideBelow/showBelow thresholds at the nearest Toolbar content width"
2190
2222
  ],
@@ -2347,13 +2379,16 @@
2347
2379
  "compact, default, large, or xlarge size",
2348
2380
  "default or monospace font",
2349
2381
  "flush item geometry and tight line height",
2350
- "controlMargins selects exterior 8px gutters with canonical physical Sides"
2382
+ "align start (default), center, or end for centered status copy or trailing values",
2383
+ "controlMargins selects exterior 8px gutters with canonical physical Sides",
2384
+ "wrap normal, anywhere, nowrap, or truncate; truncate places its ellipsis at the end, the start (keeping the tail), or the middle (keeping the last path segment or a character suffix)"
2351
2385
  ],
2352
2386
  "accessibility": [
2353
2387
  "Text renders a native paragraph by default; choose an h1 through h6 variant by document outline rather than appearance, or span for inline secondary text.",
2354
2388
  "Ordinary global, data, and ARIA attributes pass through to the native element.",
2355
2389
  "Choose tone, size, and font independently of the heading level so appearance does not distort the document outline.",
2356
- "FieldLabel is plain text, not a native label; give it an id and associate the preview group with aria-labelledby."
2390
+ "FieldLabel is plain text, not a native label; give it an id and associate the preview group with aria-labelledby.",
2391
+ "Start and middle truncation clip visually only: the whole value stays in the DOM in reading order, and Text shows it as the element's title unless the app supplies one."
2357
2392
  ],
2358
2393
  "geometry": {
2359
2394
  "margin": "self",
@@ -2466,7 +2501,13 @@
2466
2501
  "avoidWhen": [
2467
2502
  "Do not use for editable fields or row/column tabular data."
2468
2503
  ],
2469
- "alternatives": [],
2504
+ "alternatives": [
2505
+ {
2506
+ "id": "framed-list",
2507
+ "relationship": "nearest",
2508
+ "when": "Use FramedList for rows of arbitrary content (copy and controls) in the same frame."
2509
+ }
2510
+ ],
2470
2511
  "appOwns": [
2471
2512
  "values",
2472
2513
  "formatting",
@@ -2476,7 +2517,10 @@
2476
2517
  "icon rows",
2477
2518
  "iconless rows",
2478
2519
  "compact density",
2479
- "placeholder (loading)"
2520
+ "placeholder (loading)",
2521
+ "minimum label column (labelWidth)",
2522
+ "stacked presentation",
2523
+ "stack below a compact or narrow table width"
2480
2524
  ],
2481
2525
  "accessibility": [
2482
2526
  "Name ValueTable with its label; ValueTableRow supplies dt/dd semantics, and row icons stay decorative unless meaning requires an accessible label."
@@ -2513,8 +2557,8 @@
2513
2557
  "--kui-value-table-border",
2514
2558
  "--kui-value-table-icon-size",
2515
2559
  "--kui-value-table-row-columns",
2516
- "--kui-value-table-row-padding-block",
2517
- "--kui-value-table-row-gap"
2560
+ "--kui-value-table-row-gap",
2561
+ "--kui-value-table-row-padding-block"
2518
2562
  ],
2519
2563
  "links": {
2520
2564
  "catalogRoute": "?component=value-table",
@@ -2522,6 +2566,193 @@
2522
2566
  "recipe": "docs/component-selection.md#problem-to-component-matrix"
2523
2567
  }
2524
2568
  },
2569
+ {
2570
+ "id": "framed-list",
2571
+ "name": "FramedList",
2572
+ "category": "Structure",
2573
+ "kind": "component",
2574
+ "source": "kerf",
2575
+ "description": "An inset-grouped list: one rounded, bordered frame with dividers between rows of arbitrary content.",
2576
+ "uses": [],
2577
+ "purpose": "Group settings-style rows of arbitrary content (copy, keycaps, controls) in one framed surface with between-row dividers and an optional highlighted row, without app list CSS.",
2578
+ "publicExports": [
2579
+ "FramedList",
2580
+ "FramedListRow"
2581
+ ],
2582
+ "useWhen": [
2583
+ "Settings rows, account or source cards, or shortcut lists group several rows of arbitrary content in one framed surface."
2584
+ ],
2585
+ "avoidWhen": [
2586
+ "Do not use for read-only label/value facts; use ValueTable.",
2587
+ "Do not use for selectable navigation rows; use List with ListItem.",
2588
+ "Do not pad or border its rows from application CSS; FramedListRow owns the inset and divider."
2589
+ ],
2590
+ "alternatives": [
2591
+ {
2592
+ "id": "value-table",
2593
+ "relationship": "nearest",
2594
+ "when": "Use ValueTable when every row is a label and a value."
2595
+ },
2596
+ {
2597
+ "id": "list",
2598
+ "relationship": "nearest",
2599
+ "when": "Use List with ListItem for navigation or selectable rows."
2600
+ }
2601
+ ],
2602
+ "appOwns": [
2603
+ "row content and its controls",
2604
+ "which row is highlighted",
2605
+ "the list's accessible name"
2606
+ ],
2607
+ "variants": [
2608
+ "lowered surface",
2609
+ "base surface",
2610
+ "highlighted row"
2611
+ ],
2612
+ "accessibility": [
2613
+ "Renders a list (ul role=list, li rows); pass label when no heading names it. Highlight is visual; carry its meaning in row content or a control's state."
2614
+ ],
2615
+ "geometry": {
2616
+ "margin": "self",
2617
+ "border": "self",
2618
+ "padding": "self",
2619
+ "notes": [
2620
+ "Rows own the 8px inset and the inset 1px divider above them; the frame owns the 8px margin, border, and radius."
2621
+ ]
2622
+ },
2623
+ "delivery": {
2624
+ "browserImport": "@kerfjs/ui/framed-list",
2625
+ "manualCssImport": "@kerfjs/ui/framed-list.css",
2626
+ "sideEffects": [
2627
+ "browser-condition-css"
2628
+ ]
2629
+ },
2630
+ "wiring": [],
2631
+ "publicClasses": [
2632
+ "kui-framed-list",
2633
+ "kui-framed-list__row"
2634
+ ],
2635
+ "publicTokens": [
2636
+ "--kui-framed-list-border",
2637
+ "--kui-color-neutral-border-normal",
2638
+ "--kui-color-surface-lowered",
2639
+ "--kui-color-surface",
2640
+ "--kui-color-brand-fill-quiet",
2641
+ "--kui-layout-inline-margin",
2642
+ "--kui-layout-item-padding",
2643
+ "--kui-layout-rounded-radius"
2644
+ ],
2645
+ "rootElement": "ul",
2646
+ "links": {
2647
+ "catalogRoute": "?component=framed-list",
2648
+ "documentation": "docs/component-selection.md",
2649
+ "recipe": "docs/component-selection.md#problem-to-component-matrix"
2650
+ }
2651
+ },
2652
+ {
2653
+ "id": "summary-row",
2654
+ "name": "SummaryRow",
2655
+ "category": "Structure",
2656
+ "kind": "component",
2657
+ "source": "kerf",
2658
+ "description": "A selectable, focusable summary of one item as a list row or a board card, with a state rail, a clamped title, trailing meta, and a metadata line.",
2659
+ "uses": [],
2660
+ "purpose": "Present dense item summaries (tickets, tasks, messages) as selectable list rows or board cards with Kerf-owned selection, hover, focus, rail, clamping, list-edge rounding, and narrow compaction, without app row CSS.",
2661
+ "publicExports": [
2662
+ "SummaryRow"
2663
+ ],
2664
+ "useWhen": [
2665
+ "A list or board shows many items as dense, selectable summaries with an identifier, a title, a timestamp, and metadata."
2666
+ ],
2667
+ "avoidWhen": [
2668
+ "Do not use for navigation rows with a single label; use ListItem.",
2669
+ "Do not use for selectable tiles of free-form content; use ContentItem with selectionMode.",
2670
+ "Do not hand-roll row chrome (selection fill, rail, title clamp, edge rounding) in app CSS."
2671
+ ],
2672
+ "alternatives": [
2673
+ {
2674
+ "id": "list-item",
2675
+ "relationship": "nearest",
2676
+ "when": "Use ListItem for navigation rows."
2677
+ },
2678
+ {
2679
+ "id": "content-item",
2680
+ "relationship": "nearest",
2681
+ "when": "Use ContentItem for selectable rich tiles."
2682
+ }
2683
+ ],
2684
+ "appOwns": [
2685
+ "the listbox container, selection set, and keyboard movement",
2686
+ "the title, leading glyph, trailing meta, and metadata content",
2687
+ "rail tone and dimming policy"
2688
+ ],
2689
+ "variants": [
2690
+ "row",
2691
+ "card",
2692
+ "selected",
2693
+ "dimmed",
2694
+ "state rail",
2695
+ "list edge start, end, or only",
2696
+ "title line budget",
2697
+ "deferred rendering"
2698
+ ],
2699
+ "accessibility": [
2700
+ "Each SummaryRow is role=option with tabindex=0 and aria-selected; place rows in a labeled role=listbox and move focus with the arrow keys in the app. The rail is decorative; carry its meaning in text."
2701
+ ],
2702
+ "geometry": {
2703
+ "margin": "none",
2704
+ "border": "self",
2705
+ "padding": "self",
2706
+ "notes": [
2707
+ "Rows sit flush in a list section and round only the corners at its edges; cards are borderless rounded cards."
2708
+ ]
2709
+ },
2710
+ "delivery": {
2711
+ "browserImport": "@kerfjs/ui/summary-row",
2712
+ "manualCssImport": "@kerfjs/ui/summary-row.css",
2713
+ "sideEffects": [
2714
+ "browser-condition-css"
2715
+ ]
2716
+ },
2717
+ "wiring": [],
2718
+ "publicClasses": [
2719
+ "kui-summary-row",
2720
+ "kui-summary-row__rail",
2721
+ "kui-summary-row__body",
2722
+ "kui-summary-row__leading",
2723
+ "kui-summary-row__content",
2724
+ "kui-summary-row__title",
2725
+ "kui-summary-row__trailing",
2726
+ "kui-summary-row__metadata"
2727
+ ],
2728
+ "publicTokens": [
2729
+ "--kui-color-neutral-border-quiet",
2730
+ "--kui-color-text",
2731
+ "--kui-color-surface",
2732
+ "--kui-color-brand-border-normal",
2733
+ "--kui-color-text-link",
2734
+ "--kui-color-brand-fill-quiet",
2735
+ "--kui-color-neutral-on-quiet",
2736
+ "--kui-color-brand-fill-loud",
2737
+ "--kui-color-pop-fill-loud",
2738
+ "--kui-color-success-fill-loud",
2739
+ "--kui-color-warning-fill-loud",
2740
+ "--kui-color-danger-fill-loud",
2741
+ "--kui-color-text-quiet",
2742
+ "--kui-font-2xs",
2743
+ "--kui-font-xs",
2744
+ "--kui-layout-rounded-radius",
2745
+ "--kui-space-2xs",
2746
+ "--kui-space-s",
2747
+ "--kui-space-xs"
2748
+ ],
2749
+ "rootElement": "div",
2750
+ "links": {
2751
+ "catalogRoute": "?component=summary-row",
2752
+ "documentation": "docs/component-selection.md",
2753
+ "recipe": "docs/component-selection.md#problem-to-component-matrix"
2754
+ }
2755
+ },
2525
2756
  {
2526
2757
  "id": "row",
2527
2758
  "name": "Row",
@@ -2641,7 +2872,7 @@
2641
2872
  "nowrap or wrapping",
2642
2873
  "top/right/bottom/left text and control inset combinations",
2643
2874
  "fill: the layout root fills a definite-height parent",
2644
- "rootAttributes: safe data-* metadata on the root"
2875
+ "rootAttributes: safe data-*, aria-*, and structural role metadata on the root"
2645
2876
  ],
2646
2877
  "accessibility": [
2647
2878
  "Row adds layout only and no grouping role; children retain responsibility for native or ARIA semantics.",
@@ -2807,6 +3038,11 @@
2807
3038
  "id": "resize",
2808
3039
  "relationship": "interactive-alternative",
2809
3040
  "when": "Use ResizableRegion when people must adjust the boundary between tracks."
3041
+ },
3042
+ {
3043
+ "id": "column-track",
3044
+ "relationship": "nearest",
3045
+ "when": "Use ColumnTrack for a board of columns that scroll sideways or page instead of wrapping."
2810
3046
  }
2811
3047
  ],
2812
3048
  "appOwns": [
@@ -2860,6 +3096,144 @@
2860
3096
  "recipe": "docs/layout.md#grid"
2861
3097
  }
2862
3098
  },
3099
+ {
3100
+ "id": "column-track",
3101
+ "name": "ColumnTrack",
3102
+ "category": "Structure",
3103
+ "kind": "component",
3104
+ "source": "kerf",
3105
+ "description": "A horizontal track of equal, min-width columns that scrolls sideways, or pages one column at a time with peek and snapping.",
3106
+ "uses": [],
3107
+ "purpose": "Lay out a board of columns (kanban) as one horizontal scroll owner: equal columns that never shrink below a minimum, or a paged phone layout with a peeking next column and start snapping, without app track CSS.",
3108
+ "publicExports": [
3109
+ "ColumnTrack"
3110
+ ],
3111
+ "useWhen": [
3112
+ "A board shows several parallel columns (kanban lanes) that must keep a readable width and scroll sideways, or page one at a time on a phone."
3113
+ ],
3114
+ "avoidWhen": [
3115
+ "Do not use for a responsive grid that wraps; use Grid.",
3116
+ "Do not use for two resizable panes; use SplitView or ResizableRegion.",
3117
+ "Do not re-track a Grid from application CSS to get overflowing columns."
3118
+ ],
3119
+ "alternatives": [
3120
+ {
3121
+ "id": "grid",
3122
+ "relationship": "nearest",
3123
+ "when": "Use Grid when columns should wrap or collapse instead of scrolling."
3124
+ }
3125
+ ],
3126
+ "appOwns": [
3127
+ "the columns and their content",
3128
+ "choosing scroll or paged layout (for example by device class)",
3129
+ "drag and drop between columns"
3130
+ ],
3131
+ "variants": [
3132
+ "scroll with a minimum column width",
3133
+ "paged with peek and mandatory snapping"
3134
+ ],
3135
+ "accessibility": [
3136
+ "Name the track with aria-label through rootAttributes when it is a landmark-like region; give each column a region name. Paged scrolling is smooth unless reduced motion is preferred."
3137
+ ],
3138
+ "geometry": {
3139
+ "margin": "none",
3140
+ "border": "none",
3141
+ "padding": "self",
3142
+ "notes": [
3143
+ "The track pads 8px inline and fills its parent's height; columns sit flush and own their insets and vertical scrolling."
3144
+ ]
3145
+ },
3146
+ "delivery": {
3147
+ "browserImport": "@kerfjs/ui/column-track",
3148
+ "manualCssImport": "@kerfjs/ui/column-track.css",
3149
+ "sideEffects": [
3150
+ "browser-condition-css"
3151
+ ]
3152
+ },
3153
+ "wiring": [],
3154
+ "publicClasses": [
3155
+ "kui-column-track",
3156
+ "kui-column-track__columns"
3157
+ ],
3158
+ "publicTokens": [
3159
+ "--kui-layout-inline-margin"
3160
+ ],
3161
+ "rootElement": "div",
3162
+ "links": {
3163
+ "catalogRoute": "?component=column-track",
3164
+ "documentation": "docs/layout.md",
3165
+ "recipe": "docs/component-selection.md#problem-to-component-matrix"
3166
+ }
3167
+ },
3168
+ {
3169
+ "id": "content-swap",
3170
+ "name": "ContentSwap",
3171
+ "category": "Structure",
3172
+ "kind": "component",
3173
+ "source": "kerf",
3174
+ "description": "Two content sides sharing one cell, swapped in place with a push, a crossfade, or no motion.",
3175
+ "uses": [],
3176
+ "purpose": "Swap arbitrary content in place (a dialog body that steps to a second page, a label or footer whose actions change) with Kerf-owned push or crossfade motion, reduced-motion handling, and an inert, hidden inactive side.",
3177
+ "publicExports": [
3178
+ "ContentSwap"
3179
+ ],
3180
+ "useWhen": [
3181
+ "A region swaps between two contents in place, such as a dialog's two steps or a footer's action sets, and the change should read as motion."
3182
+ ],
3183
+ "avoidWhen": [
3184
+ "Do not use for full navigation views with their own toolbars; use NavStack.",
3185
+ "Do not use to swap more than two states at once; render the current pair.",
3186
+ "Do not hand-roll stacked cells, inert handling, or push keyframes in app CSS."
3187
+ ],
3188
+ "alternatives": [
3189
+ {
3190
+ "id": "nav-stack",
3191
+ "relationship": "nearest",
3192
+ "when": "Use NavStack for full views with toolbars and back navigation."
3193
+ }
3194
+ ],
3195
+ "appOwns": [
3196
+ "which side is active and the push direction",
3197
+ "both sides' content",
3198
+ "the region's name"
3199
+ ],
3200
+ "variants": [
3201
+ "push forward or backward",
3202
+ "crossfade",
3203
+ "none",
3204
+ "full-width slot region"
3205
+ ],
3206
+ "accessibility": [
3207
+ "The inactive side is inert and aria-hidden; label makes the swap a named region. Push mirrors in right-to-left documents. Reduced motion replaces the slide with a short fade."
3208
+ ],
3209
+ "geometry": {
3210
+ "margin": "none",
3211
+ "border": "none",
3212
+ "padding": "none",
3213
+ "notes": [
3214
+ "Both sides share one grid cell; the region keeps the active side's height and clips the motion."
3215
+ ]
3216
+ },
3217
+ "delivery": {
3218
+ "browserImport": "@kerfjs/ui/content-swap",
3219
+ "manualCssImport": "@kerfjs/ui/content-swap.css",
3220
+ "sideEffects": [
3221
+ "browser-condition-css"
3222
+ ]
3223
+ },
3224
+ "wiring": [],
3225
+ "publicClasses": [
3226
+ "kui-content-swap",
3227
+ "kui-content-swap__side"
3228
+ ],
3229
+ "publicTokens": [],
3230
+ "rootElement": "div",
3231
+ "links": {
3232
+ "catalogRoute": "?component=content-swap",
3233
+ "documentation": "docs/component-selection.md",
3234
+ "recipe": "docs/component-selection.md#problem-to-component-matrix"
3235
+ }
3236
+ },
2863
3237
  {
2864
3238
  "id": "spacer",
2865
3239
  "name": "Spacer",
@@ -3151,18 +3525,21 @@
3151
3525
  "typed CssLength gap",
3152
3526
  "boolean, finite-keyword, or typed CssFlex flex",
3153
3527
  "scrollable",
3528
+ "base or raised solid surface",
3529
+ "document reading inset",
3154
3530
  "left/center/right/full horizontal alignment",
3155
3531
  "top/middle/bottom/full vertical alignment",
3156
3532
  "top/right/bottom/left divider combinations",
3157
3533
  "top/right/bottom/left text and control inset combinations",
3158
3534
  "fill: the layout root fills a definite-height parent",
3159
- "rootAttributes: safe data-* metadata on the root",
3535
+ "rootAttributes: safe data-*, aria-*, and structural role on the root",
3160
3536
  "scroll dividers when named as wireScrollDividers targets chrome",
3161
3537
  "multi-select grid for rich ContentItem rows"
3162
3538
  ],
3163
3539
  "accessibility": [
3164
3540
  "List adds layout only and no list role by default; selectionMode=\"multiple\" makes it an aria-multiselectable grid with a required ariaLabel for selectable ContentItem rows.",
3165
- "Give a scrollable List a bounded block size and keep keyboard focus visible as its contents scroll."
3541
+ "Give a scrollable List a bounded block size and keep keyboard focus visible as its contents scroll.",
3542
+ "A focused scrollable List (a keyboard-focusable scroller) draws the theme focus ring inset and rounded inside its own box, so a rounded or clipping parent never cuts it off; do not restyle its focus."
3166
3543
  ],
3167
3544
  "geometry": {
3168
3545
  "margin": "none",
@@ -3203,9 +3580,14 @@
3203
3580
  ],
3204
3581
  "publicTokens": [
3205
3582
  "--kui-color-neutral-border-normal",
3583
+ "--kui-color-surface",
3584
+ "--kui-color-surface-raised",
3206
3585
  "--kui-layout-item-gap",
3207
3586
  "--kui-list-divider-color",
3208
- "--kui-list-gap"
3587
+ "--kui-list-gap",
3588
+ "--kui-space-l",
3589
+ "--kui-space-m",
3590
+ "--kui-space-xl"
3209
3591
  ],
3210
3592
  "links": {
3211
3593
  "catalogRoute": "?component=list",
@@ -3319,10 +3701,11 @@
3319
3701
  "category": "Navigation",
3320
3702
  "kind": "component",
3321
3703
  "source": "kerf",
3322
- "description": "Configurable navigation rows with structured labels, status/busy metadata, density, group dividers, and sibling primary/trailing native-button actions.",
3704
+ "description": "Configurable navigation rows with structured labels, status/busy metadata, density, group dividers, and a primary native-button action beside a sibling trailing native button or trailing overflow PopupMenu.",
3323
3705
  "uses": [
3324
3706
  "lucide-icon",
3325
- "loading-spinner"
3707
+ "loading-spinner",
3708
+ "popup-menu"
3326
3709
  ],
3327
3710
  "purpose": "Keep a selectable primary row action and an independently named trailing action as sibling native controls inside one noninteractive visual row.",
3328
3711
  "publicExports": [
@@ -3343,7 +3726,8 @@
3343
3726
  }
3344
3727
  ],
3345
3728
  "useWhen": [
3346
- "A navigation or item row needs both a primary selectable action and an independently focusable trailing action."
3729
+ "A navigation or item row needs both a primary selectable action and an independently focusable trailing action.",
3730
+ "A command row needs a trailing \"…\" overflow menu (trailingMenu), optionally also opened at the pointer from the row's contextmenu with openPopupMenuAt."
3347
3731
  ],
3348
3732
  "avoidWhen": [
3349
3733
  "Use ListItem when trailing content is dormant metadata; use AppTab only for tablist semantics and ToolbarControlGroup only for toolbar controls.",
@@ -3366,7 +3750,8 @@
3366
3750
  "selection",
3367
3751
  "action handling",
3368
3752
  "domain data attributes",
3369
- "popover or context-menu policy"
3753
+ "popover or context-menu policy",
3754
+ "row order"
3370
3755
  ],
3371
3756
  "variants": [
3372
3757
  "selected",
@@ -3379,11 +3764,15 @@
3379
3764
  "description and status",
3380
3765
  "busy while retaining content",
3381
3766
  "interaction-revealed trailing action",
3382
- "before, after, or paired group divider"
3767
+ "trailing overflow menu",
3768
+ "before, after, or paired group divider",
3769
+ "draggable row with dragging and drop-before / drop-after insertion states"
3383
3770
  ],
3384
3771
  "accessibility": [
3385
3772
  "The noninteractive root contains two sibling native buttons in primary-then-trailing focus order; each button has its own action, item identity, accessible name, and disabled state.",
3386
- "Selection semantics are exposed only by the primary button; label, icon, and trailingActionIcon are dormant SafeHtml and must not contain interactive descendants; never place an interactive descendant in ListItem.trailing."
3773
+ "A trailingMenu replaces the trailing button with a PopupMenu trigger in the same position: an icon-only button named by trailingMenu.label that exposes aria-haspopup=\"menu\" and aria-expanded, moves focus into the menu, and returns focus to the trigger on Escape or a choice.",
3774
+ "Selection semantics are exposed only by the primary button; label, icon, and trailingActionIcon are dormant SafeHtml and must not contain interactive descendants; never place an interactive descendant in ListItem.trailing.",
3775
+ "A draggable row is dragged by its noninteractive root; with wireListReorder, Alt+Shift+ArrowUp/ArrowDown on its primary button moves it, and focus returns to that button after the application re-renders."
3387
3776
  ],
3388
3777
  "geometry": {
3389
3778
  "margin": "self",
@@ -3397,19 +3786,43 @@
3397
3786
  "browser-condition-css"
3398
3787
  ]
3399
3788
  },
3400
- "wiring": [],
3401
- "publicClasses": [
3402
- "kui-list-action-row",
3403
- "kui-list-action-row__icon",
3404
- "kui-list-action-row__label",
3405
- "kui-list-action-row__primary-label",
3406
- "kui-list-action-row__description",
3407
- "kui-list-action-row__status",
3408
- "kui-list-action-row__primary",
3409
- "kui-list-action-row__trailing-action"
3410
- ],
3411
- "publicTokens": [
3412
- "--kui-color-brand-border-quiet",
3789
+ "wiring": [
3790
+ {
3791
+ "export": "wireListReorder",
3792
+ "import": "@kerfjs/ui/wire-list-reorder",
3793
+ "required": false,
3794
+ "stateAttributes": [
3795
+ {
3796
+ "name": "data-dragging",
3797
+ "on": "ListActionRow rows being dragged",
3798
+ "meaning": "\"true\" on every row a pointer drag is moving (the dragged row, or every selected row of its list when the dragged row is selected). Same attribute the `dragging` prop renders."
3799
+ },
3800
+ {
3801
+ "name": "data-drop-position",
3802
+ "on": "ListActionRow row under the pointer",
3803
+ "meaning": "\"before\" or \"after\": the edge of this row the dragged rows would land beside. Same attribute the `dropPosition` prop renders."
3804
+ }
3805
+ ]
3806
+ },
3807
+ {
3808
+ "export": "reorderListItems",
3809
+ "import": "@kerfjs/ui/wire-list-reorder",
3810
+ "required": false
3811
+ }
3812
+ ],
3813
+ "publicClasses": [
3814
+ "kui-list-action-row",
3815
+ "kui-list-action-row__icon",
3816
+ "kui-list-action-row__label",
3817
+ "kui-list-action-row__primary-label",
3818
+ "kui-list-action-row__description",
3819
+ "kui-list-action-row__status",
3820
+ "kui-list-action-row__primary",
3821
+ "kui-list-action-row__trailing-action"
3822
+ ],
3823
+ "publicTokens": [
3824
+ "--kui-color-brand-border-loud",
3825
+ "--kui-color-brand-border-quiet",
3413
3826
  "--kui-color-brand-fill-normal",
3414
3827
  "--kui-color-neutral-border-normal",
3415
3828
  "--kui-color-neutral-fill-normal",
@@ -3426,6 +3839,9 @@
3426
3839
  "--kui-list-action-row-background",
3427
3840
  "--kui-list-action-row-border",
3428
3841
  "--kui-list-action-row-color",
3842
+ "--kui-list-action-row-dragging-opacity",
3843
+ "--kui-list-action-row-drop-indicator",
3844
+ "--kui-list-action-row-drop-indicator-width",
3429
3845
  "--kui-list-action-row-hover-background",
3430
3846
  "--kui-list-action-row-hover-border",
3431
3847
  "--kui-list-action-row-selected-background",
@@ -3455,7 +3871,9 @@
3455
3871
  "purpose": "Selectable, disabled, trailing, and multiline action or link rows.",
3456
3872
  "publicExports": [
3457
3873
  "ListItem",
3458
- "ListItemLink"
3874
+ "ListItemLink",
3875
+ "wireListReorder",
3876
+ "reorderListItems"
3459
3877
  ],
3460
3878
  "cssValueProps": [
3461
3879
  {
@@ -3483,6 +3901,11 @@
3483
3901
  "id": "list-action-row",
3484
3902
  "relationship": "nearest",
3485
3903
  "when": "The trailing region must be independently interactive."
3904
+ },
3905
+ {
3906
+ "id": "summary-row",
3907
+ "relationship": "nearest",
3908
+ "when": "Use SummaryRow for dense selectable item summaries with metadata."
3486
3909
  }
3487
3910
  ],
3488
3911
  "appOwns": [
@@ -3491,7 +3914,8 @@
3491
3914
  "selection",
3492
3915
  "permissions",
3493
3916
  "action handling",
3494
- "domain data attributes"
3917
+ "domain data attributes",
3918
+ "row order"
3495
3919
  ],
3496
3920
  "variants": [
3497
3921
  "native link and external link",
@@ -3505,12 +3929,13 @@
3505
3929
  "spacious density",
3506
3930
  "centered icon beside a multiline label",
3507
3931
  "drag-target state",
3932
+ "draggable row with dragging and drop-before / drop-after insertion states",
3508
3933
  "description and status",
3509
3934
  "busy while retaining content",
3510
3935
  "before, after, or paired group divider"
3511
3936
  ],
3512
3937
  "accessibility": [
3513
- "ListItem uses native button activation and pressed maps to aria-pressed; ListItemLink uses native anchor activation and external opens a new tab with safe rel and an announced default label. Both map selected to aria-current; disabled or loading links omit href and leave the tab order. rootAttributes cannot add role=menuitem or replace owned ARIA; trailing is dormant content and must not contain controls."
3938
+ "ListItem uses native button activation and pressed maps to aria-pressed; ListItemLink uses native anchor activation and external opens a new tab with safe rel and an announced default label. Both map selected to aria-current; disabled or loading links omit href and leave the tab order. rootAttributes cannot add role=menuitem or replace owned ARIA; trailing is dormant content and must not contain controls. A draggable row reorders by pointer drag or, with wireListReorder, Alt+Shift+ArrowUp/ArrowDown; a placeholder is never draggable."
3514
3939
  ],
3515
3940
  "geometry": {
3516
3941
  "margin": "self",
@@ -3527,7 +3952,30 @@
3527
3952
  "browser-condition-css"
3528
3953
  ]
3529
3954
  },
3530
- "wiring": [],
3955
+ "wiring": [
3956
+ {
3957
+ "export": "wireListReorder",
3958
+ "import": "@kerfjs/ui/wire-list-reorder",
3959
+ "required": false,
3960
+ "stateAttributes": [
3961
+ {
3962
+ "name": "data-dragging",
3963
+ "on": "ListItem / ListItemLink rows being dragged",
3964
+ "meaning": "\"true\" on every row a pointer drag is moving (the dragged row, or every selected row of its list when the dragged row is selected). Same attribute the `dragging` prop renders."
3965
+ },
3966
+ {
3967
+ "name": "data-drop-position",
3968
+ "on": "ListItem / ListItemLink row under the pointer",
3969
+ "meaning": "\"before\" or \"after\": the edge of this row the dragged rows would land beside. Same attribute the `dropPosition` prop renders."
3970
+ }
3971
+ ]
3972
+ },
3973
+ {
3974
+ "export": "reorderListItems",
3975
+ "import": "@kerfjs/ui/wire-list-reorder",
3976
+ "required": false
3977
+ }
3978
+ ],
3531
3979
  "publicClasses": [
3532
3980
  "kui-list-item",
3533
3981
  "kui-list-item__icon",
@@ -3538,6 +3986,7 @@
3538
3986
  "kui-list-item__trailing"
3539
3987
  ],
3540
3988
  "publicTokens": [
3989
+ "--kui-color-brand-border-loud",
3541
3990
  "--kui-color-brand-border-normal",
3542
3991
  "--kui-color-brand-border-quiet",
3543
3992
  "--kui-color-brand-fill-quiet",
@@ -3547,6 +3996,7 @@
3547
3996
  "--kui-color-neutral-on-quiet",
3548
3997
  "--kui-color-neutral-border-quiet",
3549
3998
  "--kui-color-neutral-border-normal",
3999
+ "--kui-radius-pill",
3550
4000
  "--kui-focus-ring",
3551
4001
  "--kui-list-item-color",
3552
4002
  "--kui-list-item-background",
@@ -3557,6 +4007,9 @@
3557
4007
  "--kui-list-item-drag-target-background",
3558
4008
  "--kui-list-item-drag-target-outline",
3559
4009
  "--kui-list-item-drag-target-outline-offset",
4010
+ "--kui-list-item-dragging-opacity",
4011
+ "--kui-list-item-drop-indicator",
4012
+ "--kui-list-item-drop-indicator-width",
3560
4013
  "--kui-list-item-gap",
3561
4014
  "--kui-list-item-hover-background",
3562
4015
  "--kui-list-item-hover-border",
@@ -3760,6 +4213,8 @@
3760
4213
  "framed pill item",
3761
4214
  "base surface item",
3762
4215
  "neutral, info, pop, success, warning, or danger semantic item",
4216
+ "brand-loud item (solid brand fill, on-loud foreground)",
4217
+ "chat bubble at the start or end of the row (bubble), fit to its content up to 80%",
3763
4218
  "named focus-target region",
3764
4219
  "multi-select rich grid row"
3765
4220
  ],
@@ -4228,6 +4683,83 @@
4228
4683
  "recipe": "docs/accessibility.md#segmentedcontrol"
4229
4684
  }
4230
4685
  },
4686
+ {
4687
+ "id": "choice-chips",
4688
+ "name": "ChoiceChips",
4689
+ "category": "Controls",
4690
+ "kind": "component",
4691
+ "source": "kerf",
4692
+ "description": "An exclusive, wrapping set of separated pill chips backed by native radios, with optional leading color swatches or icons.",
4693
+ "uses": [
4694
+ "lucide-icon"
4695
+ ],
4696
+ "purpose": "Choose one value from a visible set too large for a segmented track, such as a color palette with labeled swatches.",
4697
+ "publicExports": [
4698
+ "ChoiceChips"
4699
+ ],
4700
+ "useWhen": [
4701
+ "Expose one exclusive choice among several visible options that must wrap onto more rows, such as a labeled color palette with swatches."
4702
+ ],
4703
+ "avoidWhen": [
4704
+ "Use SegmentedControl for a few compact choices on one track.",
4705
+ "Use Select when the choice list is long or space is tight.",
4706
+ "Do not use it for removable tags (Chip) or for multiple selection."
4707
+ ],
4708
+ "alternatives": [
4709
+ {
4710
+ "id": "segmented-control",
4711
+ "relationship": "nearest"
4712
+ },
4713
+ {
4714
+ "id": "select",
4715
+ "relationship": "nearest"
4716
+ },
4717
+ {
4718
+ "id": "wa-radio-group",
4719
+ "relationship": "prefer-over",
4720
+ "when": "Use ChoiceChips instead of button-appearance radios that must wrap; a joined button group wraps into ragged rows with shared borders."
4721
+ }
4722
+ ],
4723
+ "appOwns": [
4724
+ "value",
4725
+ "choices and labels",
4726
+ "swatch colors",
4727
+ "change action",
4728
+ "form submission"
4729
+ ],
4730
+ "variants": [
4731
+ "color swatch, transparent (struck-through) swatch, icon, or text-only choices",
4732
+ "default or compact size",
4733
+ "disabled group or disabled choices",
4734
+ "required"
4735
+ ],
4736
+ "accessibility": [
4737
+ "The group is a named role=\"radiogroup\" of native radios: one Tab stop, arrow keys move the selection, and the checked radio submits the form value.",
4738
+ "Every choice keeps a visible text label; the swatch is decorative and the selection adds a heavier border, so neither relies on color alone."
4739
+ ],
4740
+ "geometry": {
4741
+ "margin": "none",
4742
+ "border": "self",
4743
+ "padding": "self"
4744
+ },
4745
+ "delivery": {
4746
+ "browserImport": "@kerfjs/ui/choice-chips",
4747
+ "manualCssImport": "@kerfjs/ui/choice-chips.css",
4748
+ "sideEffects": [
4749
+ "browser-condition-css"
4750
+ ]
4751
+ },
4752
+ "wiring": [],
4753
+ "publicClasses": [
4754
+ "kui-choice-chips"
4755
+ ],
4756
+ "publicTokens": [],
4757
+ "links": {
4758
+ "catalogRoute": "?component=choice-chips",
4759
+ "documentation": "docs/component-selection.md",
4760
+ "recipe": "docs/accessibility.md#choicechips"
4761
+ }
4762
+ },
4231
4763
  {
4232
4764
  "id": "token-search-field",
4233
4765
  "name": "TokenSearchField",
@@ -4391,13 +4923,25 @@
4391
4923
  {
4392
4924
  "path": "restoreInset",
4393
4925
  "grammar": "length",
4394
- "helpers": ["px", "rem", "em", "pct", "space", "lengthVar", "calc"],
4395
- "nonStandaloneHelpers": ["plus"],
4926
+ "helpers": [
4927
+ "px",
4928
+ "rem",
4929
+ "em",
4930
+ "pct",
4931
+ "space",
4932
+ "lengthVar",
4933
+ "calc"
4934
+ ],
4935
+ "nonStandaloneHelpers": [
4936
+ "plus"
4937
+ ],
4396
4938
  "shorthands": [],
4397
4939
  "canonicalShorthands": [],
4398
4940
  "exceptionalShorthands": [],
4399
4941
  "rawPolicy": "forbid",
4400
- "examples": ["restoreInset={space(\"xs\")}"]
4942
+ "examples": [
4943
+ "restoreInset={space(\"xs\")}"
4944
+ ]
4401
4945
  }
4402
4946
  ],
4403
4947
  "useWhen": [
@@ -4433,8 +4977,8 @@
4433
4977
  "slide, fade-slide, or instant content",
4434
4978
  "clipped, scrolling, or popup-visible content",
4435
4979
  "inline, overlay, or hidden responsive presentation",
4436
- "safe-area restore control"
4437
- ,"top-corner or inline restore placement"
4980
+ "safe-area restore control",
4981
+ "top-corner or inline restore placement"
4438
4982
  ],
4439
4983
  "accessibility": [
4440
4984
  "Preserve separator naming, value ARIA, and keyboard behavior.",
@@ -4581,6 +5125,11 @@
4581
5125
  {
4582
5126
  "id": "wa-dropdown",
4583
5127
  "relationship": "prefer-over"
5128
+ },
5129
+ {
5130
+ "id": "combobox",
5131
+ "relationship": "nearest",
5132
+ "when": "Use Combobox when people may type to filter or create a new value."
4584
5133
  }
4585
5134
  ],
4586
5135
  "appOwns": [
@@ -4665,6 +5214,117 @@
4665
5214
  "recipe": "docs/component-selection.md#web-awesome-overlap-policy"
4666
5215
  }
4667
5216
  },
5217
+ {
5218
+ "id": "combobox",
5219
+ "name": "Combobox",
5220
+ "category": "Controls",
5221
+ "kind": "component",
5222
+ "source": "kerf",
5223
+ "description": "A free-text field with a filtered suggestion list that can also create a new value.",
5224
+ "uses": [],
5225
+ "purpose": "Let people pick an existing value or create a new one by typing (tags, labels, recipients), with the themed field chrome, the ARIA combobox pattern, and a touch-safe font size, without a native datalist or app CSS.",
5226
+ "publicExports": [
5227
+ "Combobox",
5228
+ "wireComboboxes"
5229
+ ],
5230
+ "useWhen": [
5231
+ "People type to find an existing value among many, or create a new one (tags, labels, recipients)."
5232
+ ],
5233
+ "avoidWhen": [
5234
+ "Do not use when only existing values are allowed and nothing needs typing; use Select.",
5235
+ "Do not use for free text plus removable filter tokens in one editor; use TokenSearchField.",
5236
+ "Do not style a native input with a datalist from app CSS."
5237
+ ],
5238
+ "alternatives": [
5239
+ {
5240
+ "id": "select",
5241
+ "relationship": "nearest",
5242
+ "when": "Use Select when only existing values are allowed."
5243
+ },
5244
+ {
5245
+ "id": "token-search-field",
5246
+ "relationship": "nearest",
5247
+ "when": "Use TokenSearchField for search text with removable filter tokens."
5248
+ }
5249
+ ],
5250
+ "appOwns": [
5251
+ "the suggestions and the committed values",
5252
+ "normalizing and validating created values",
5253
+ "clearing the field after a commit"
5254
+ ],
5255
+ "variants": [
5256
+ "with create",
5257
+ "suggestions only (createLabel={false})",
5258
+ "hint",
5259
+ "disabled"
5260
+ ],
5261
+ "accessibility": [
5262
+ "Native input with role=combobox, aria-autocomplete=list, aria-expanded, aria-controls, and aria-activedescendant; options are role=option in a listbox. The visible label is a real label; the hint is aria-describedby."
5263
+ ],
5264
+ "geometry": {
5265
+ "margin": "none",
5266
+ "border": "self",
5267
+ "padding": "self",
5268
+ "notes": [
5269
+ "Label and hint sit on the value's text column (1px border + 8px padding); the 44px field matches a themed wa-input."
5270
+ ]
5271
+ },
5272
+ "delivery": {
5273
+ "browserImport": "@kerfjs/ui/combobox",
5274
+ "manualCssImport": "@kerfjs/ui/combobox.css",
5275
+ "sideEffects": [
5276
+ "browser-condition-css"
5277
+ ]
5278
+ },
5279
+ "wiring": [
5280
+ {
5281
+ "export": "wireComboboxes",
5282
+ "import": "@kerfjs/ui/wire-comboboxes",
5283
+ "required": true,
5284
+ "reason": "Filters suggestions, moves the active option, and reports commits; without it the list never opens.",
5285
+ "stateAttributes": [
5286
+ {
5287
+ "name": "data-value",
5288
+ "on": "the create option (kui-combobox__option[data-create])",
5289
+ "meaning": "The typed text the create option would commit; rewritten as the person types."
5290
+ }
5291
+ ]
5292
+ }
5293
+ ],
5294
+ "publicClasses": [
5295
+ "kui-combobox",
5296
+ "kui-combobox__label",
5297
+ "kui-combobox__hint",
5298
+ "kui-combobox__control",
5299
+ "kui-combobox__input",
5300
+ "kui-combobox__listbox",
5301
+ "kui-combobox__option"
5302
+ ],
5303
+ "publicTokens": [
5304
+ "--kui-combobox-z-index",
5305
+ "--kui-color-neutral-on-quiet",
5306
+ "--kui-color-text-quiet",
5307
+ "--kui-color-neutral-border-normal",
5308
+ "--kui-color-text",
5309
+ "--kui-color-surface",
5310
+ "--kui-color-surface-raised",
5311
+ "--kui-color-text-link",
5312
+ "--kui-color-brand-fill-quiet",
5313
+ "--kui-font-xs",
5314
+ "--kui-font-s",
5315
+ "--kui-layout-item-padding",
5316
+ "--kui-layout-rounded-radius",
5317
+ "--kui-shadow-l",
5318
+ "--kui-space-2xs",
5319
+ "--kui-space-xs"
5320
+ ],
5321
+ "rootElement": "div",
5322
+ "links": {
5323
+ "catalogRoute": "?component=combobox",
5324
+ "documentation": "docs/component-selection.md",
5325
+ "recipe": "docs/component-selection.md#problem-to-component-matrix"
5326
+ }
5327
+ },
4668
5328
  {
4669
5329
  "id": "anchored-surface",
4670
5330
  "name": "AnchoredSurface",
@@ -4685,8 +5345,14 @@
4685
5345
  "Use PopupMenu for a typed action menu, Select for a choice, and a modal dialog for a task that must block the page."
4686
5346
  ],
4687
5347
  "alternatives": [
4688
- { "id": "popup-menu", "relationship": "nearest" },
4689
- { "id": "wa-popup", "relationship": "prefer-over" }
5348
+ {
5349
+ "id": "popup-menu",
5350
+ "relationship": "nearest"
5351
+ },
5352
+ {
5353
+ "id": "wa-popup",
5354
+ "relationship": "prefer-over"
5355
+ }
4690
5356
  ],
4691
5357
  "appOwns": [
4692
5358
  "content and action policy",
@@ -4717,7 +5383,9 @@
4717
5383
  "delivery": {
4718
5384
  "browserImport": "@kerfjs/ui/anchored-surface",
4719
5385
  "manualCssImport": "@kerfjs/ui/anchored-surface.css",
4720
- "sideEffects": ["browser-condition-css"]
5386
+ "sideEffects": [
5387
+ "browser-condition-css"
5388
+ ]
4721
5389
  },
4722
5390
  "wiring": [],
4723
5391
  "publicClasses": [],
@@ -4747,6 +5415,7 @@
4747
5415
  "purpose": "A typed action menu with nested choices, selected state, and optional pointer-anchored context opening, built on the Web Awesome dropdown.",
4748
5416
  "publicExports": [
4749
5417
  "PopupMenu",
5418
+ "openPopupMenu",
4750
5419
  "openPopupMenuAt",
4751
5420
  "closePopupMenu"
4752
5421
  ],
@@ -4785,7 +5454,7 @@
4785
5454
  "nested actions",
4786
5455
  "checked choices and trailing details",
4787
5456
  "danger tone and disabled reasons",
4788
- "context trigger",
5457
+ "context trigger with a rendered anchor point and a zero-footprint anchor host",
4789
5458
  "placement"
4790
5459
  ],
4791
5460
  "usageExamples": [
@@ -4839,72 +5508,431 @@
4839
5508
  }
4840
5509
  },
4841
5510
  {
4842
- "id": "feedback",
4843
- "name": "Feedback",
4844
- "category": "Feedback",
4845
- "kind": "composition",
5511
+ "id": "icon-button",
5512
+ "name": "IconButton",
5513
+ "category": "Controls",
5514
+ "kind": "component",
4846
5515
  "source": "kerf",
4847
- "description": "Banners, empty states, and labeled progress.",
5516
+ "description": "Square, icon-only Web Awesome button with a LucideIcon and a required accessible name.",
4848
5517
  "uses": [
4849
- "state-banner",
4850
- "empty-state",
4851
- "loading-spinner"
5518
+ "wa-button",
5519
+ "lucide-icon"
5520
+ ],
5521
+ "purpose": "Render an icon-only action as a square one form-control height on each side, so it matches an adjacent wa-input or Select, without ::part overrides.",
5522
+ "publicExports": [
5523
+ "IconButton"
4852
5524
  ],
4853
- "purpose": "Banners, empty states, and labeled progress.",
4854
- "publicExports": [],
4855
5525
  "useWhen": [
4856
- "Compose persistent status, empty/busy content, and compact loading feedback."
5526
+ "An icon-only action stands alone or beside a form field, such as a Browse button next to a path input."
4857
5527
  ],
4858
5528
  "avoidWhen": [
4859
- "Do not collapse different message lifetimes or urgency into one visual treatment."
5529
+ "Do not use inside a ToolbarControlGroup; the group owns its controls' geometry, so compose a native button with a LucideIcon there.",
5530
+ "Do not use when the action needs a visible text label; use wa-button with text.",
5531
+ "Do not override wa-button::part(base) width, min-height, or padding to square an icon button; use IconButton."
4860
5532
  ],
4861
5533
  "alternatives": [
4862
5534
  {
4863
- "id": "state-banner",
4864
- "relationship": "nearest"
4865
- },
4866
- {
4867
- "id": "empty-state",
4868
- "relationship": "nearest"
4869
- },
4870
- {
4871
- "id": "wa-callout",
4872
- "relationship": "prefer-over"
5535
+ "id": "wa-button",
5536
+ "relationship": "prefer-over",
5537
+ "when": "Web Awesome squares a button only for a lone wa-icon; with a LucideIcon use IconButton."
4873
5538
  },
4874
5539
  {
4875
- "id": "wa-toast",
4876
- "relationship": "prefer-over"
5540
+ "id": "list-inset-control",
5541
+ "relationship": "composes-with",
5542
+ "when": "Beside a field in a ListInsetControl the square keeps its size and aligns with the field below its label."
4877
5543
  }
4878
5544
  ],
4879
5545
  "appOwns": [
4880
- "state mapping",
4881
- "message lifetime",
4882
- "recovery policy"
5546
+ "the delegated action",
5547
+ "the accessible name",
5548
+ "appearance, variant, and size choice"
4883
5549
  ],
4884
5550
  "variants": [
4885
- "banner",
4886
- "empty",
4887
- "busy",
4888
- "spinner"
5551
+ "default appearance",
5552
+ "plain",
5553
+ "outlined",
5554
+ "danger variant",
5555
+ "disabled",
5556
+ "xs, s, m, l, or xl size"
4889
5557
  ],
4890
5558
  "accessibility": [
4891
- "Choose polite status versus assertive alert deliberately."
5559
+ "label is required and names the button through its LucideIcon (role img), since the button shows no text."
4892
5560
  ],
4893
5561
  "geometry": {
4894
- "margin": "child",
4895
- "border": "child",
4896
- "padding": "child"
5562
+ "margin": "none",
5563
+ "border": "self",
5564
+ "padding": "self"
4897
5565
  },
4898
5566
  "delivery": {
5567
+ "browserImport": "@kerfjs/ui/icon-button",
5568
+ "manualCssImport": "@kerfjs/ui/icon-button.css",
5569
+ "registrationImport": "@awesome.me/webawesome/dist/components/button/button.js",
5570
+ "themeCssImport": "@kerfjs/ui/webawesome.css",
4899
5571
  "sideEffects": [
4900
- "css"
5572
+ "browser-condition-css",
5573
+ "custom-element-registration"
4901
5574
  ]
4902
5575
  },
4903
5576
  "wiring": [],
4904
- "publicClasses": [],
5577
+ "publicClasses": [
5578
+ "kui-icon-button"
5579
+ ],
4905
5580
  "publicTokens": [],
5581
+ "rootElement": "wa-button",
4906
5582
  "links": {
4907
- "catalogRoute": "?component=feedback",
5583
+ "catalogRoute": "?component=icon-button",
5584
+ "documentation": "docs/component-selection.md",
5585
+ "recipe": "docs/component-selection.md#problem-to-component-matrix"
5586
+ }
5587
+ },
5588
+ {
5589
+ "id": "icon-toggle-button",
5590
+ "name": "IconToggleButton",
5591
+ "category": "Controls",
5592
+ "kind": "component",
5593
+ "source": "kerf",
5594
+ "description": "A standalone icon-only toggle with a single contained toolbar group's geometry and pressed chrome.",
5595
+ "uses": [
5596
+ "lucide-icon"
5597
+ ],
5598
+ "purpose": "Render an icon-only aria-pressed toggle in content or a pane footer, where a Toolbar does not belong, with the 44px contained geometry and raised pressed face of a single ToolbarControlGroup.",
5599
+ "publicExports": [
5600
+ "IconToggleButton"
5601
+ ],
5602
+ "useWhen": [
5603
+ "An icon-only on/off control (show a panel, a conversation) sits in content or a pane footer outside any Toolbar."
5604
+ ],
5605
+ "avoidWhen": [
5606
+ "Do not use inside a Toolbar; compose a ToolbarControlGroup there.",
5607
+ "Do not use for a momentary action; use IconButton.",
5608
+ "Do not use for one-of-several choices; use SegmentedControl."
5609
+ ],
5610
+ "alternatives": [
5611
+ {
5612
+ "id": "toolbar-control-group",
5613
+ "relationship": "nearest",
5614
+ "when": "Inside a Toolbar, a single ToolbarControlGroup with a pressed button is the same control."
5615
+ },
5616
+ {
5617
+ "id": "icon-button",
5618
+ "relationship": "nearest",
5619
+ "when": "Use IconButton for a momentary icon-only action."
5620
+ }
5621
+ ],
5622
+ "appOwns": [
5623
+ "the pressed state and its delegated action",
5624
+ "the accessible name"
5625
+ ],
5626
+ "variants": [
5627
+ "pressed",
5628
+ "unpressed",
5629
+ "pill or rounded shape",
5630
+ "disabled"
5631
+ ],
5632
+ "accessibility": [
5633
+ "Native button with aria-pressed and a required aria-label; with help tags registered it shows that label on hover and keyboard focus."
5634
+ ],
5635
+ "geometry": {
5636
+ "margin": "none",
5637
+ "border": "self",
5638
+ "padding": "self"
5639
+ },
5640
+ "delivery": {
5641
+ "browserImport": "@kerfjs/ui/icon-toggle-button",
5642
+ "manualCssImport": "@kerfjs/ui/icon-toggle-button.css",
5643
+ "sideEffects": [
5644
+ "browser-condition-css"
5645
+ ]
5646
+ },
5647
+ "wiring": [],
5648
+ "publicClasses": [
5649
+ "kui-icon-toggle-button",
5650
+ "kui-icon-toggle-button__face"
5651
+ ],
5652
+ "publicTokens": [
5653
+ "--kui-color-neutral-border-normal",
5654
+ "--kui-color-neutral-fill-normal",
5655
+ "--kui-color-neutral-on-quiet",
5656
+ "--kui-color-surface",
5657
+ "--kui-color-brand-on-quiet",
5658
+ "--kui-shadow-s",
5659
+ "--kui-focus-ring",
5660
+ "--kui-layout-pill-radius",
5661
+ "--kui-layout-rounded-radius",
5662
+ "--kui-layout-highlight-inset"
5663
+ ],
5664
+ "rootElement": "button",
5665
+ "links": {
5666
+ "catalogRoute": "?component=icon-toggle-button",
5667
+ "documentation": "docs/component-selection.md",
5668
+ "recipe": "docs/component-selection.md#problem-to-component-matrix"
5669
+ }
5670
+ },
5671
+ {
5672
+ "id": "split-button",
5673
+ "name": "SplitButton",
5674
+ "category": "Controls",
5675
+ "kind": "component",
5676
+ "source": "kerf",
5677
+ "description": "A primary action with an attached options trigger on one loud semantic fill.",
5678
+ "uses": [
5679
+ "lucide-icon",
5680
+ "loading-spinner"
5681
+ ],
5682
+ "purpose": "Render a prominent primary action plus an options trigger (provider, model, target) as one control with a semantic tone, full-width sizing, a busy presentation, and native aria-expanded on the trigger, outside any Toolbar.",
5683
+ "publicExports": [
5684
+ "SplitButton"
5685
+ ],
5686
+ "useWhen": [
5687
+ "A prominent primary action has a closely related set of options chosen from an attached trigger, such as Drive with a provider menu or Deploy with targets."
5688
+ ],
5689
+ "avoidWhen": [
5690
+ "Do not use for a plain action without options; use wa-button.",
5691
+ "Do not use inside a Toolbar for a command menu; use PopupMenu in a ToolbarControlGroup.",
5692
+ "Do not use wa-button-group to build one; its hosts do not forward aria-expanded or names to their inner buttons."
5693
+ ],
5694
+ "alternatives": [
5695
+ {
5696
+ "id": "wa-button-group",
5697
+ "relationship": "prefer-over",
5698
+ "when": "SplitButton's native halves expose names and aria-expanded directly."
5699
+ },
5700
+ {
5701
+ "id": "popup-menu",
5702
+ "relationship": "composes-with",
5703
+ "when": "Open the app's options menu from optionsAction; PopupMenu remains the command menu inside a toolbar."
5704
+ }
5705
+ ],
5706
+ "appOwns": [
5707
+ "the primary and options actions",
5708
+ "the options menu and its open state",
5709
+ "the running state, tone switch, and copy"
5710
+ ],
5711
+ "variants": [
5712
+ "brand, neutral, success, warning, or danger tone",
5713
+ "content width or fill",
5714
+ "busy",
5715
+ "disabled primary or options"
5716
+ ],
5717
+ "accessibility": [
5718
+ "Both halves are native buttons in a group; the options trigger exposes aria-haspopup, aria-expanded, and optional aria-controls, and needs optionsLabel. busy sets aria-busy on the primary."
5719
+ ],
5720
+ "geometry": {
5721
+ "margin": "none",
5722
+ "border": "self",
5723
+ "padding": "self"
5724
+ },
5725
+ "delivery": {
5726
+ "browserImport": "@kerfjs/ui/split-button",
5727
+ "manualCssImport": "@kerfjs/ui/split-button.css",
5728
+ "sideEffects": [
5729
+ "browser-condition-css"
5730
+ ]
5731
+ },
5732
+ "wiring": [],
5733
+ "publicClasses": [
5734
+ "kui-split-button",
5735
+ "kui-split-button__options",
5736
+ "kui-split-button__icon",
5737
+ "kui-split-button__label"
5738
+ ],
5739
+ "publicTokens": [
5740
+ "--kui-color-brand-fill-loud",
5741
+ "--kui-color-brand-on-loud",
5742
+ "--kui-color-neutral-fill-loud",
5743
+ "--kui-color-neutral-on-loud",
5744
+ "--kui-color-success-fill-loud",
5745
+ "--kui-color-success-on-loud",
5746
+ "--kui-color-warning-fill-loud",
5747
+ "--kui-color-warning-on-loud",
5748
+ "--kui-color-danger-fill-loud",
5749
+ "--kui-color-danger-on-loud",
5750
+ "--kui-focus-ring",
5751
+ "--kui-font-weight-semibold",
5752
+ "--kui-layout-rounded-radius",
5753
+ "--kui-space-s",
5754
+ "--kui-space-xs"
5755
+ ],
5756
+ "rootElement": "div",
5757
+ "links": {
5758
+ "catalogRoute": "?component=split-button",
5759
+ "documentation": "docs/component-selection.md",
5760
+ "recipe": "docs/component-selection.md#problem-to-component-matrix"
5761
+ }
5762
+ },
5763
+ {
5764
+ "id": "file-picker",
5765
+ "name": "FilePicker",
5766
+ "category": "Controls",
5767
+ "kind": "component",
5768
+ "source": "kerf",
5769
+ "description": "A compact browse trigger and a dashed drop zone around native file inputs, with wiring that reports chosen and dropped files.",
5770
+ "uses": [],
5771
+ "purpose": "Let people choose or drop files (attachments, evidence, imports) without app CSS: a link-toned browse trigger and a dashed drop target that highlights while dragging, both around visually hidden native file inputs.",
5772
+ "publicExports": [
5773
+ "FilePickerTrigger",
5774
+ "FileDropZone",
5775
+ "wireFilePickers",
5776
+ "fileMatchesAccept"
5777
+ ],
5778
+ "useWhen": [
5779
+ "People attach or import files by browsing or by dropping them onto a target."
5780
+ ],
5781
+ "avoidWhen": [
5782
+ "Do not style a native file input or label from app CSS; use these components.",
5783
+ "Do not rely on the drop zone alone; it also opens the chooser when clicked or activated from the keyboard."
5784
+ ],
5785
+ "alternatives": [
5786
+ {
5787
+ "id": "wa-button",
5788
+ "relationship": "prefer-over",
5789
+ "when": "A button cannot open the native chooser without script; the trigger is a label around the input."
5790
+ }
5791
+ ],
5792
+ "appOwns": [
5793
+ "what happens to the reported files (upload, validation, limits)",
5794
+ "the list of chosen files",
5795
+ "copy and accepted types"
5796
+ ],
5797
+ "variants": [
5798
+ "browse trigger",
5799
+ "drop zone",
5800
+ "dragging",
5801
+ "disabled",
5802
+ "accept filter",
5803
+ "multiple or single"
5804
+ ],
5805
+ "accessibility": [
5806
+ "Each control is a label around a real file input that receives keyboard focus; the visible control shows the focus ring. Give the input an accessibleLabel when the visible copy is short."
5807
+ ],
5808
+ "geometry": {
5809
+ "margin": "self",
5810
+ "border": "self",
5811
+ "padding": "self",
5812
+ "notes": [
5813
+ "The drop zone carries the 8px content-item inline margin; the trigger is a compact 32px inline control."
5814
+ ]
5815
+ },
5816
+ "delivery": {
5817
+ "browserImport": "@kerfjs/ui/file-picker",
5818
+ "manualCssImport": "@kerfjs/ui/file-picker.css",
5819
+ "sideEffects": [
5820
+ "browser-condition-css"
5821
+ ]
5822
+ },
5823
+ "wiring": [
5824
+ {
5825
+ "export": "wireFilePickers",
5826
+ "import": "@kerfjs/ui/wire-file-pickers",
5827
+ "required": true,
5828
+ "reason": "Reports chosen and dropped files and accepts drops on the zone; without it drops open the file in the browser.",
5829
+ "stateAttributes": [
5830
+ {
5831
+ "name": "data-dragging",
5832
+ "on": "kui-file-picker (drop zone)",
5833
+ "meaning": "\"true\" while files are dragged over the zone."
5834
+ }
5835
+ ]
5836
+ }
5837
+ ],
5838
+ "publicClasses": [
5839
+ "kui-file-picker",
5840
+ "kui-file-picker__title",
5841
+ "kui-file-picker__detail",
5842
+ "kui-file-picker__input",
5843
+ "kui-file-picker__icon"
5844
+ ],
5845
+ "publicTokens": [
5846
+ "--kui-color-text-link",
5847
+ "--kui-color-brand-fill-quiet",
5848
+ "--kui-color-neutral-border-loud",
5849
+ "--kui-color-neutral-on-quiet",
5850
+ "--kui-color-text",
5851
+ "--kui-focus-ring",
5852
+ "--kui-font-xs",
5853
+ "--kui-font-2xs",
5854
+ "--kui-font-weight-semibold",
5855
+ "--kui-layout-inline-margin",
5856
+ "--kui-layout-rounded-radius",
5857
+ "--kui-radius-pill",
5858
+ "--kui-space-2xs",
5859
+ "--kui-space-s",
5860
+ "--kui-space-xs"
5861
+ ],
5862
+ "rootElement": "label",
5863
+ "links": {
5864
+ "catalogRoute": "?component=file-picker",
5865
+ "documentation": "docs/component-selection.md",
5866
+ "recipe": "docs/component-selection.md#problem-to-component-matrix"
5867
+ }
5868
+ },
5869
+ {
5870
+ "id": "feedback",
5871
+ "name": "Feedback",
5872
+ "category": "Feedback",
5873
+ "kind": "composition",
5874
+ "source": "kerf",
5875
+ "description": "Banners, empty states, and labeled progress.",
5876
+ "uses": [
5877
+ "state-banner",
5878
+ "empty-state",
5879
+ "loading-spinner"
5880
+ ],
5881
+ "purpose": "Banners, empty states, and labeled progress.",
5882
+ "publicExports": [],
5883
+ "useWhen": [
5884
+ "Compose persistent status, empty/busy content, and compact loading feedback."
5885
+ ],
5886
+ "avoidWhen": [
5887
+ "Do not collapse different message lifetimes or urgency into one visual treatment."
5888
+ ],
5889
+ "alternatives": [
5890
+ {
5891
+ "id": "state-banner",
5892
+ "relationship": "nearest"
5893
+ },
5894
+ {
5895
+ "id": "empty-state",
5896
+ "relationship": "nearest"
5897
+ },
5898
+ {
5899
+ "id": "wa-callout",
5900
+ "relationship": "prefer-over"
5901
+ },
5902
+ {
5903
+ "id": "wa-toast",
5904
+ "relationship": "prefer-over"
5905
+ }
5906
+ ],
5907
+ "appOwns": [
5908
+ "state mapping",
5909
+ "message lifetime",
5910
+ "recovery policy"
5911
+ ],
5912
+ "variants": [
5913
+ "banner",
5914
+ "empty",
5915
+ "busy",
5916
+ "spinner"
5917
+ ],
5918
+ "accessibility": [
5919
+ "Choose polite status versus assertive alert deliberately."
5920
+ ],
5921
+ "geometry": {
5922
+ "margin": "child",
5923
+ "border": "child",
5924
+ "padding": "child"
5925
+ },
5926
+ "delivery": {
5927
+ "sideEffects": [
5928
+ "css"
5929
+ ]
5930
+ },
5931
+ "wiring": [],
5932
+ "publicClasses": [],
5933
+ "publicTokens": [],
5934
+ "links": {
5935
+ "catalogRoute": "?component=feedback",
4908
5936
  "documentation": "docs/component-selection.md",
4909
5937
  "recipe": "docs/component-selection.md#ambiguous-choices"
4910
5938
  }
@@ -4943,6 +5971,11 @@
4943
5971
  {
4944
5972
  "id": "wa-toast",
4945
5973
  "relationship": "prefer-over"
5974
+ },
5975
+ {
5976
+ "id": "corner-status",
5977
+ "relationship": "composes-with",
5978
+ "when": "Host app-level progress in a viewport corner with CornerStatus instead of fixed-position CSS."
4946
5979
  }
4947
5980
  ],
4948
5981
  "appOwns": [
@@ -4964,6 +5997,7 @@
4964
5997
  "badge",
4965
5998
  "stacked copy",
4966
5999
  "action below",
6000
+ "strip presentation",
4967
6001
  "placeholder (loading)"
4968
6002
  ],
4969
6003
  "accessibility": [
@@ -5040,7 +6074,8 @@
5040
6074
  "--kui-state-banner-success-foreground",
5041
6075
  "--kui-state-banner-warning-background",
5042
6076
  "--kui-state-banner-warning-border",
5043
- "--kui-state-banner-warning-foreground"
6077
+ "--kui-state-banner-warning-foreground",
6078
+ "--kui-shadow-l"
5044
6079
  ],
5045
6080
  "links": {
5046
6081
  "catalogRoute": "?component=state-banner",
@@ -5048,6 +6083,194 @@
5048
6083
  "recipe": "docs/component-selection.md#ambiguous-choices"
5049
6084
  }
5050
6085
  },
6086
+ {
6087
+ "id": "corner-status",
6088
+ "name": "CornerStatus",
6089
+ "category": "Feedback",
6090
+ "kind": "component",
6091
+ "source": "kerf",
6092
+ "description": "Non-dismissible app-level status pinned to a viewport corner in the top layer, hosting StateBanner.",
6093
+ "uses": [
6094
+ "state-banner"
6095
+ ],
6096
+ "purpose": "Show ongoing app-level progress such as \"Loading…\" or \"Updating tickets… 3 of 12\" in a viewport corner above page chrome and any dialog opened before it, without a close button, light dismiss, Escape, or focus change.",
6097
+ "publicExports": [
6098
+ "CornerStatus",
6099
+ "wireCornerStatus"
6100
+ ],
6101
+ "useWhen": [
6102
+ "Show ongoing app-level progress or status that has no better home beside the affected work and must stay visible until the work ends."
6103
+ ],
6104
+ "avoidWhen": [
6105
+ "Do not use for transient, dismissible confirmation; use a toast.",
6106
+ "Do not use for status that belongs beside the affected work; place a StateBanner there.",
6107
+ "Do not position a StateBanner with fixed-position application CSS; use CornerStatus."
6108
+ ],
6109
+ "alternatives": [
6110
+ {
6111
+ "id": "state-banner",
6112
+ "relationship": "composes-with",
6113
+ "when": "Compose one or more StateBanners (urgency=\"status\") inside it; they stack."
6114
+ },
6115
+ {
6116
+ "id": "wa-toast",
6117
+ "relationship": "prefer-over",
6118
+ "when": "A toast item is transient and always dismissible; CornerStatus stays until the application removes it."
6119
+ }
6120
+ ],
6121
+ "appOwns": [
6122
+ "status lifetime (render while the work runs, remove when it ends)",
6123
+ "the composed StateBanner copy and progress",
6124
+ "corner placement"
6125
+ ],
6126
+ "variants": [
6127
+ "bottom-end",
6128
+ "bottom-start",
6129
+ "top-end",
6130
+ "top-start",
6131
+ "embedded (in flow)"
6132
+ ],
6133
+ "accessibility": [
6134
+ "The host adds no role; the composed StateBanner with urgency=\"status\" is the polite live region.",
6135
+ "Opening never moves focus, and there is no close button, light dismiss, or Escape handling to compete with dialogs.",
6136
+ "A modal dialog opened while it shows stacks above it and makes it inert (unannounced); show progress the dialog's task depends on inside the dialog."
6137
+ ],
6138
+ "geometry": {
6139
+ "margin": "none",
6140
+ "border": "child",
6141
+ "padding": "child",
6142
+ "notes": [
6143
+ "Placement owns the 16px viewport gutter plus device safe-area insets; a StateBanner inside drops its inline margin and gains elevation."
6144
+ ]
6145
+ },
6146
+ "delivery": {
6147
+ "browserImport": "@kerfjs/ui/corner-status",
6148
+ "manualCssImport": "@kerfjs/ui/corner-status.css",
6149
+ "sideEffects": [
6150
+ "browser-condition-css"
6151
+ ]
6152
+ },
6153
+ "wiring": [
6154
+ {
6155
+ "export": "wireCornerStatus",
6156
+ "import": "@kerfjs/ui/wire-corner-status",
6157
+ "required": true,
6158
+ "reason": "Opens each overlay host in the top layer as renders insert it; without it the Popover API keeps the host hidden."
6159
+ }
6160
+ ],
6161
+ "publicClasses": [
6162
+ "kui-corner-status"
6163
+ ],
6164
+ "publicTokens": [
6165
+ "--kui-corner-status-gutter",
6166
+ "--kui-corner-status-z-index",
6167
+ "--kui-safe-area-block-end",
6168
+ "--kui-safe-area-block-start",
6169
+ "--kui-safe-area-inline-end",
6170
+ "--kui-safe-area-inline-start",
6171
+ "--kui-space-m",
6172
+ "--kui-space-xs"
6173
+ ],
6174
+ "rootElement": "div",
6175
+ "links": {
6176
+ "catalogRoute": "?component=corner-status",
6177
+ "documentation": "docs/component-selection.md",
6178
+ "recipe": "docs/component-selection.md#ambiguous-choices"
6179
+ }
6180
+ },
6181
+ {
6182
+ "id": "edge-activity-indicator",
6183
+ "name": "EdgeActivityIndicator",
6184
+ "category": "Feedback",
6185
+ "kind": "component",
6186
+ "source": "kerf",
6187
+ "description": "A layout-free top-edge activity strip with a traveling wave and an optional hanging status pill.",
6188
+ "uses": [],
6189
+ "purpose": "Signal ambient background activity (server work, sync) along the top edge of the viewport without allocating layout or taking the pointer, with Kerf-owned motion and reduced-motion handling.",
6190
+ "publicExports": [
6191
+ "EdgeActivityIndicator"
6192
+ ],
6193
+ "useWhen": [
6194
+ "Ambient, app-wide background activity (server work, sync) should be visible without a modal, a banner, or any layout shift."
6195
+ ],
6196
+ "avoidWhen": [
6197
+ "Do not use for progress the user waits on or must read; use CornerStatus or a StateBanner.",
6198
+ "Do not use for known progress; use a progress bar.",
6199
+ "Do not use it as the only record of important state; the bars are hidden from assistive technology."
6200
+ ],
6201
+ "alternatives": [
6202
+ {
6203
+ "id": "corner-status",
6204
+ "relationship": "nearest",
6205
+ "when": "Use CornerStatus for readable, non-dismissible app-level progress."
6206
+ },
6207
+ {
6208
+ "id": "loading-spinner",
6209
+ "relationship": "nearest",
6210
+ "when": "Use LoadingSpinner for local activity beside the affected control."
6211
+ }
6212
+ ],
6213
+ "appOwns": [
6214
+ "the busy state",
6215
+ "the optional status message",
6216
+ "the tone"
6217
+ ],
6218
+ "variants": [
6219
+ "busy or idle",
6220
+ "with or without a status pill",
6221
+ "semantic tone",
6222
+ "safe-area inset or flush"
6223
+ ],
6224
+ "accessibility": [
6225
+ "The strip is aria-hidden and pointer-inert; the optional pill is a polite live region that holds text only while it shows. Under reduced motion the wave and scale stop and the strip and pill only fade."
6226
+ ],
6227
+ "geometry": {
6228
+ "margin": "none",
6229
+ "border": "none",
6230
+ "padding": "none",
6231
+ "notes": [
6232
+ "Fixed to the top edge below the device safe area; it allocates no layout."
6233
+ ]
6234
+ },
6235
+ "delivery": {
6236
+ "browserImport": "@kerfjs/ui/edge-activity-indicator",
6237
+ "manualCssImport": "@kerfjs/ui/edge-activity-indicator.css",
6238
+ "sideEffects": [
6239
+ "browser-condition-css"
6240
+ ]
6241
+ },
6242
+ "wiring": [],
6243
+ "publicClasses": [
6244
+ "kui-edge-activity-indicator",
6245
+ "kui-edge-activity-indicator__strip",
6246
+ "kui-edge-activity-indicator__message"
6247
+ ],
6248
+ "publicTokens": [
6249
+ "--kui-edge-activity-indicator-z-index",
6250
+ "--kui-safe-area-block-start",
6251
+ "--kui-color-brand-fill-loud",
6252
+ "--kui-color-brand-on-loud",
6253
+ "--kui-color-neutral-fill-loud",
6254
+ "--kui-color-neutral-on-loud",
6255
+ "--kui-color-pop-fill-loud",
6256
+ "--kui-color-pop-on-loud",
6257
+ "--kui-color-success-fill-loud",
6258
+ "--kui-color-success-on-loud",
6259
+ "--kui-color-warning-fill-loud",
6260
+ "--kui-color-warning-on-loud",
6261
+ "--kui-color-danger-fill-loud",
6262
+ "--kui-color-danger-on-loud",
6263
+ "--kui-font-2xs",
6264
+ "--kui-space-m",
6265
+ "--kui-space-s"
6266
+ ],
6267
+ "rootElement": "div",
6268
+ "links": {
6269
+ "catalogRoute": "?component=edge-activity-indicator",
6270
+ "documentation": "docs/component-selection.md",
6271
+ "recipe": "docs/component-selection.md#problem-to-component-matrix"
6272
+ }
6273
+ },
5051
6274
  {
5052
6275
  "id": "empty-state",
5053
6276
  "name": "EmptyState",
@@ -5374,7 +6597,13 @@
5374
6597
  "Do not choose it from catalog presence alone; confirm that its semantic and interaction contract matches the product need."
5375
6598
  ],
5376
6599
  "recommendation": "supported",
5377
- "alternatives": [],
6600
+ "alternatives": [
6601
+ {
6602
+ "id": "icon-button",
6603
+ "relationship": "prefer-kerf",
6604
+ "when": "For an icon-only button with a LucideIcon, use IconButton for Web Awesome's square icon-button geometry."
6605
+ }
6606
+ ],
5378
6607
  "geometry": {
5379
6608
  "margin": "none",
5380
6609
  "border": "self",
@@ -5416,6 +6645,11 @@
5416
6645
  {
5417
6646
  "id": "segmented-control",
5418
6647
  "relationship": "prefer-kerf"
6648
+ },
6649
+ {
6650
+ "id": "split-button",
6651
+ "relationship": "prefer-kerf",
6652
+ "when": "For a primary action with an attached options trigger, use SplitButton."
5419
6653
  }
5420
6654
  ],
5421
6655
  "geometry": {