@kerfjs/ui 5.0.0-beta.4 → 5.0.0-beta.41

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 (498) hide show
  1. package/README.md +342 -108
  2. package/ai/application-ui-diagnostic-ids-v1.json +100 -0
  3. package/ai/application-ui-profile-sync.cjs +529 -0
  4. package/ai/application-ui-profile.d.mts +1 -0
  5. package/ai/application-ui-profile.d.ts +102 -0
  6. package/ai/application-ui-profile.defaults.json +41 -0
  7. package/ai/application-ui-profile.mjs +626 -0
  8. package/ai/application-ui-profile.schema.json +130 -0
  9. package/ai/catalog-authoring.json +25 -0
  10. package/ai/catalog-authoring.schema.json +61 -0
  11. package/ai/compile-time-contracts-v1.json +132 -0
  12. package/ai/compile-time-contracts-v1.schema.json +51 -0
  13. package/ai/component-catalog-extension-v2.d.ts +7 -0
  14. package/ai/component-catalog-extension-v2.schema.json +7 -0
  15. package/ai/component-catalog-extension.schema.json +79 -0
  16. package/ai/component-catalog-v2-overrides.json +496 -0
  17. package/ai/component-catalog-v2.d.ts +90 -0
  18. package/ai/component-catalog-v2.json +5678 -0
  19. package/ai/component-catalog-v2.schema.json +298 -0
  20. package/ai/component-catalog.json +2694 -417
  21. package/ai/component-catalog.schema.json +39 -0
  22. package/ai/public-api-signatures-v1.md +1591 -126
  23. package/ai/skill.md +140 -54
  24. package/ai/webawesome-jsx-signatures-v1.md +2 -1
  25. package/analyzer/cli.mjs +49 -0
  26. package/analyzer/index.d.mts +46 -0
  27. package/analyzer/index.mjs +1086 -0
  28. package/analyzer/report.schema.json +66 -0
  29. package/dist/app-tab.d.ts +15 -4
  30. package/dist/app-tab.js +3 -1
  31. package/dist/browser/app-tab.js +1 -0
  32. package/dist/browser/floating-toolbar.js +3 -0
  33. package/dist/browser/list-action-row.js +5 -0
  34. package/dist/browser/list-header.js +7 -0
  35. package/dist/browser/list-inset-control.js +3 -0
  36. package/dist/browser/list-inset-text.js +3 -0
  37. package/dist/browser/list-item.js +5 -0
  38. package/dist/browser/list.js +3 -0
  39. package/dist/browser/pane.js +3 -0
  40. package/dist/browser/row.js +3 -0
  41. package/dist/browser/segmented-control.js +1 -0
  42. package/dist/browser/select.js +1 -0
  43. package/dist/browser/skeleton.js +3 -0
  44. package/dist/browser/spacer.js +3 -0
  45. package/dist/browser/state-banner.js +1 -0
  46. package/dist/browser/sunken-panel.js +3 -0
  47. package/dist/browser/surface-scaffold.js +3 -0
  48. package/dist/browser/text.js +3 -0
  49. package/dist/browser/toolbar-text.js +1 -0
  50. package/dist/browser/value-table.js +1 -0
  51. package/dist/catalog-resources.d.ts +35 -0
  52. package/dist/catalog-resources.js +22 -0
  53. package/dist/catalog-resources.js.map +1 -0
  54. package/dist/catalog.d.ts +151 -0
  55. package/dist/catalog.js +396 -0
  56. package/dist/catalog.js.map +1 -0
  57. package/dist/chunk-2TYUFZUC.js +22 -0
  58. package/dist/chunk-2TYUFZUC.js.map +1 -0
  59. package/dist/chunk-6NDBE2OK.js +32 -0
  60. package/dist/chunk-6NDBE2OK.js.map +1 -0
  61. package/dist/chunk-6WTETUZ6.js +21 -0
  62. package/dist/chunk-6WTETUZ6.js.map +1 -0
  63. package/dist/chunk-AQFWBG23.js +83 -0
  64. package/dist/chunk-AQFWBG23.js.map +1 -0
  65. package/dist/chunk-B6JYRX3P.js +51 -0
  66. package/dist/chunk-B6JYRX3P.js.map +1 -0
  67. package/dist/chunk-C34NZOLJ.js +53 -0
  68. package/dist/chunk-C34NZOLJ.js.map +1 -0
  69. package/dist/chunk-CAB6NQ2T.js +102 -0
  70. package/dist/chunk-CAB6NQ2T.js.map +1 -0
  71. package/dist/chunk-CK6P5AUK.js +136 -0
  72. package/dist/chunk-CK6P5AUK.js.map +1 -0
  73. package/dist/chunk-DAO2VFTT.js +129 -0
  74. package/dist/chunk-DAO2VFTT.js.map +1 -0
  75. package/dist/chunk-DEYOGDE7.js +141 -0
  76. package/dist/chunk-DEYOGDE7.js.map +1 -0
  77. package/dist/chunk-DYBPI5O2.js +25 -0
  78. package/dist/chunk-DYBPI5O2.js.map +1 -0
  79. package/dist/{chunk-TRNBHPNW.js → chunk-E34TE2ZI.js} +12 -8
  80. package/dist/chunk-E34TE2ZI.js.map +1 -0
  81. package/dist/chunk-EYALJQQD.js +25 -0
  82. package/dist/chunk-EYALJQQD.js.map +1 -0
  83. package/dist/chunk-I45QO2IZ.js +88 -0
  84. package/dist/chunk-I45QO2IZ.js.map +1 -0
  85. package/dist/chunk-I4V3UDSA.js +79 -0
  86. package/dist/chunk-I4V3UDSA.js.map +1 -0
  87. package/dist/chunk-OGTJNHRG.js +42 -0
  88. package/dist/chunk-OGTJNHRG.js.map +1 -0
  89. package/dist/chunk-OL4TC3U2.js +156 -0
  90. package/dist/chunk-OL4TC3U2.js.map +1 -0
  91. package/dist/chunk-OMSRSL3B.js +120 -0
  92. package/dist/chunk-OMSRSL3B.js.map +1 -0
  93. package/dist/chunk-R3EBGEAW.js +46 -0
  94. package/dist/chunk-R3EBGEAW.js.map +1 -0
  95. package/dist/chunk-SOK5EUF7.js +25 -0
  96. package/dist/chunk-SOK5EUF7.js.map +1 -0
  97. package/dist/{chunk-7BR3DO2A.js → chunk-SRSJO5QE.js} +13 -4
  98. package/dist/chunk-SRSJO5QE.js.map +1 -0
  99. package/dist/chunk-T7DOWS6T.js +61 -0
  100. package/dist/chunk-T7DOWS6T.js.map +1 -0
  101. package/dist/chunk-TIGSG6BX.js +218 -0
  102. package/dist/chunk-TIGSG6BX.js.map +1 -0
  103. package/dist/chunk-UDHHKZWO.js +41 -0
  104. package/dist/chunk-UDHHKZWO.js.map +1 -0
  105. package/dist/{chunk-MQIZAD4A.js → chunk-UKKSMZYT.js} +76 -22
  106. package/dist/chunk-UKKSMZYT.js.map +1 -0
  107. package/dist/chunk-V6GQKOX2.js +39 -0
  108. package/dist/chunk-V6GQKOX2.js.map +1 -0
  109. package/dist/chunk-V6HCTCVD.js +46 -0
  110. package/dist/chunk-V6HCTCVD.js.map +1 -0
  111. package/dist/chunk-VDUJZF5G.js +515 -0
  112. package/dist/chunk-VDUJZF5G.js.map +1 -0
  113. package/dist/chunk-VXFGMDA7.js +31 -0
  114. package/dist/chunk-VXFGMDA7.js.map +1 -0
  115. package/dist/chunk-WN52USHV.js +115 -0
  116. package/dist/chunk-WN52USHV.js.map +1 -0
  117. package/dist/chunk-WSXUPSID.js +43 -0
  118. package/dist/chunk-WSXUPSID.js.map +1 -0
  119. package/dist/chunk-X5GRDQ7V.js +50 -0
  120. package/dist/chunk-X5GRDQ7V.js.map +1 -0
  121. package/dist/{chunk-56RJXPHG.js → chunk-Y6LYKFXY.js} +1 -1
  122. package/dist/{chunk-56RJXPHG.js.map → chunk-Y6LYKFXY.js.map} +1 -1
  123. package/dist/chunk-ZASJJMGV.js +17 -0
  124. package/dist/chunk-ZASJJMGV.js.map +1 -0
  125. package/dist/chunk-ZPWZIVI6.js +47 -0
  126. package/dist/chunk-ZPWZIVI6.js.map +1 -0
  127. package/dist/collapsible-panel.d.ts +77 -0
  128. package/dist/collapsible-panel.js +84 -0
  129. package/dist/collapsible-panel.js.map +1 -0
  130. package/dist/css-values.d.ts +75 -0
  131. package/dist/css-values.js +3 -0
  132. package/dist/css-values.js.map +1 -0
  133. package/dist/device-class.d.ts +62 -0
  134. package/dist/device-class.js +103 -0
  135. package/dist/device-class.js.map +1 -0
  136. package/dist/disclosure-arrow.js +1 -1
  137. package/dist/divider-sides-BzB6rphT.d.ts +6 -0
  138. package/dist/empty-state.d.ts +3 -2
  139. package/dist/empty-state.js +1 -1
  140. package/dist/flex-alignment-CF8NLj7i.d.ts +4 -0
  141. package/dist/floating-toolbar.d.ts +29 -0
  142. package/dist/floating-toolbar.js +3 -0
  143. package/dist/floating-toolbar.js.map +1 -0
  144. package/dist/index.d.ts +28 -14
  145. package/dist/index.js +34 -23
  146. package/dist/{menu-action-row.d.ts → list-action-row.d.ts} +19 -8
  147. package/dist/list-action-row.js +7 -0
  148. package/dist/list-action-row.js.map +1 -0
  149. package/dist/list-header.d.ts +80 -0
  150. package/dist/list-header.js +9 -0
  151. package/dist/list-header.js.map +1 -0
  152. package/dist/list-inset-control.d.ts +20 -0
  153. package/dist/list-inset-control.js +3 -0
  154. package/dist/list-inset-control.js.map +1 -0
  155. package/dist/list-inset-text.d.ts +29 -0
  156. package/dist/list-inset-text.js +3 -0
  157. package/dist/list-inset-text.js.map +1 -0
  158. package/dist/list-item.d.ts +45 -0
  159. package/dist/list-item.js +7 -0
  160. package/dist/list-item.js.map +1 -0
  161. package/dist/list.d.ts +30 -0
  162. package/dist/list.js +5 -0
  163. package/dist/list.js.map +1 -0
  164. package/dist/loading-spinner.js +1 -1
  165. package/dist/nav-stack.d.ts +41 -0
  166. package/dist/nav-stack.js +6 -0
  167. package/dist/nav-stack.js.map +1 -0
  168. package/dist/pane.d.ts +50 -0
  169. package/dist/pane.js +4 -0
  170. package/dist/pane.js.map +1 -0
  171. package/dist/resizable-region.d.ts +21 -3
  172. package/dist/resizable-region.js +1 -1
  173. package/dist/row.d.ts +28 -0
  174. package/dist/row.js +5 -0
  175. package/dist/row.js.map +1 -0
  176. package/dist/segmented-control.d.ts +11 -8
  177. package/dist/segmented-control.js +3 -1
  178. package/dist/select-register.d.ts +5 -1
  179. package/dist/select-register.js +129 -1
  180. package/dist/select-register.js.map +1 -1
  181. package/dist/select.d.ts +34 -8
  182. package/dist/select.js +3 -1
  183. package/dist/semantic-content-BbzjvSu9.d.ts +14 -0
  184. package/dist/skeleton.d.ts +25 -0
  185. package/dist/skeleton.js +4 -0
  186. package/dist/skeleton.js.map +1 -0
  187. package/dist/spacer.d.ts +16 -0
  188. package/dist/spacer.js +4 -0
  189. package/dist/spacer.js.map +1 -0
  190. package/dist/split-view.d.ts +43 -0
  191. package/dist/split-view.js +82 -0
  192. package/dist/split-view.js.map +1 -0
  193. package/dist/state-banner.d.ts +11 -5
  194. package/dist/state-banner.js +3 -1
  195. package/dist/styles/app-tab.css +26 -0
  196. package/dist/styles/catalog.css +582 -0
  197. package/dist/styles/collapsible-panel.css +212 -0
  198. package/dist/styles/floating-toolbar.css +38 -0
  199. package/dist/styles/foundation.css +80 -0
  200. package/dist/styles/layout.css +2 -20
  201. package/dist/styles/list-action-row.css +224 -0
  202. package/dist/styles/list-header.css +224 -0
  203. package/dist/styles/list-inset-control.css +23 -0
  204. package/dist/styles/list-inset-text.css +30 -0
  205. package/dist/styles/list-item.css +171 -0
  206. package/dist/styles/list.css +118 -0
  207. package/dist/styles/nav-stack.css +141 -0
  208. package/dist/styles/pane.css +62 -0
  209. package/dist/styles/resizable-region.css +158 -0
  210. package/dist/styles/row.css +92 -0
  211. package/dist/styles/segmented-control.css +10 -7
  212. package/dist/styles/select.css +115 -2
  213. package/dist/styles/skeleton.css +31 -0
  214. package/dist/styles/spacer.css +11 -0
  215. package/dist/styles/split-view.css +35 -0
  216. package/dist/styles/state-banner.css +49 -10
  217. package/dist/styles/styles.css +10 -5
  218. package/dist/styles/sunken-panel.css +22 -0
  219. package/dist/styles/surface-scaffold.css +51 -0
  220. package/dist/styles/tab-bar.css +24 -0
  221. package/dist/styles/tab-scaffold.css +85 -0
  222. package/dist/styles/text.css +6 -0
  223. package/dist/styles/token-search-field.css +14 -2
  224. package/dist/styles/toolbar-control-group.css +235 -8
  225. package/dist/styles/toolbar-text.css +65 -2
  226. package/dist/styles/toolbar.css +47 -2
  227. package/dist/styles/webawesome.css +171 -0
  228. package/dist/styles/workbench.css +187 -0
  229. package/dist/sunken-panel.d.ts +20 -0
  230. package/dist/sunken-panel.js +3 -0
  231. package/dist/sunken-panel.js.map +1 -0
  232. package/dist/surface-scaffold.d.ts +26 -0
  233. package/dist/surface-scaffold.js +3 -0
  234. package/dist/surface-scaffold.js.map +1 -0
  235. package/dist/tab-bar.d.ts +24 -6
  236. package/dist/tab-bar.js +1 -1
  237. package/dist/tab-scaffold.d.ts +31 -0
  238. package/dist/tab-scaffold.js +51 -0
  239. package/dist/tab-scaffold.js.map +1 -0
  240. package/dist/text.d.ts +20 -0
  241. package/dist/text.js +3 -0
  242. package/dist/text.js.map +1 -0
  243. package/dist/token-search-field.d.ts +30 -13
  244. package/dist/token-search-field.js +1 -1
  245. package/dist/toolbar-control-group.d.ts +33 -7
  246. package/dist/toolbar-control-group.js +1 -1
  247. package/dist/toolbar-text.d.ts +31 -4
  248. package/dist/toolbar-text.js +3 -1
  249. package/dist/toolbar.d.ts +10 -7
  250. package/dist/toolbar.js +1 -1
  251. package/dist/value-table.d.ts +7 -3
  252. package/dist/value-table.js +3 -1
  253. package/dist/webawesome.d.ts +1 -0
  254. package/dist/wire-catalog.d.ts +57 -0
  255. package/dist/wire-catalog.js +302 -0
  256. package/dist/wire-catalog.js.map +1 -0
  257. package/dist/wire-nav-stack.d.ts +18 -0
  258. package/dist/wire-nav-stack.js +228 -0
  259. package/dist/wire-nav-stack.js.map +1 -0
  260. package/dist/wire-resizable-regions.d.ts +1 -1
  261. package/dist/wire-resizable-regions.js +1 -1
  262. package/dist/wire-sidebar.d.ts +48 -0
  263. package/dist/wire-sidebar.js +147 -0
  264. package/dist/wire-sidebar.js.map +1 -0
  265. package/dist/wire-tab-bars.d.ts +19 -2
  266. package/dist/wire-tab-bars.js +1 -1
  267. package/dist/wire-tab-scaffold.d.ts +11 -0
  268. package/dist/wire-tab-scaffold.js +21 -0
  269. package/dist/wire-tab-scaffold.js.map +1 -0
  270. package/dist/wire-token-search-fields.d.ts +104 -4
  271. package/dist/wire-token-search-fields.js +1 -1
  272. package/dist/workbench.d.ts +44 -0
  273. package/dist/workbench.js +106 -0
  274. package/dist/workbench.js.map +1 -0
  275. package/docs/accessibility.md +155 -20
  276. package/docs/app-layouts.md +61 -0
  277. package/docs/catalog.md +364 -0
  278. package/docs/collapsible-panel.md +142 -0
  279. package/docs/component-contract.md +258 -28
  280. package/docs/component-integration.md +63 -0
  281. package/docs/component-selection.md +219 -57
  282. package/docs/design/templates/empty-state/filtered-dark.svg +1 -0
  283. package/docs/design/templates/empty-state/filtered.svg +1 -0
  284. package/docs/design/templates/empty-state/with-action-dark.svg +1 -0
  285. package/docs/design/templates/empty-state/with-action.svg +1 -0
  286. package/docs/design/templates/empty-state-dark.svg +1 -0
  287. package/docs/design/templates/empty-state.svg +1 -0
  288. package/docs/design/templates/list/compact-dark.svg +1 -0
  289. package/docs/design/templates/list/compact.svg +1 -0
  290. package/docs/design/templates/list/stack-dark.svg +1 -0
  291. package/docs/design/templates/list/stack.svg +1 -0
  292. package/docs/design/templates/list-action-row/default-dark.svg +1 -0
  293. package/docs/design/templates/list-action-row/default.svg +1 -0
  294. package/docs/design/templates/list-action-row/selected-dark.svg +1 -0
  295. package/docs/design/templates/list-action-row/selected.svg +1 -0
  296. package/docs/design/templates/list-action-row-dark.svg +1 -0
  297. package/docs/design/templates/list-action-row.svg +1 -0
  298. package/docs/design/templates/list-dark.svg +1 -0
  299. package/docs/design/templates/list-header/action-dark.svg +1 -0
  300. package/docs/design/templates/list-header/action.svg +1 -0
  301. package/docs/design/templates/list-header/count-dark.svg +1 -0
  302. package/docs/design/templates/list-header/count.svg +1 -0
  303. package/docs/design/templates/list-header/inline-action-dark.svg +1 -0
  304. package/docs/design/templates/list-header/inline-action.svg +1 -0
  305. package/docs/design/templates/list-header/toggle-collapsed-dark.svg +1 -0
  306. package/docs/design/templates/list-header/toggle-collapsed.svg +1 -0
  307. package/docs/design/templates/list-header/toggle-expanded-dark.svg +1 -0
  308. package/docs/design/templates/list-header/toggle-expanded.svg +1 -0
  309. package/docs/design/templates/list-header-dark.svg +1 -0
  310. package/docs/design/templates/list-header.svg +1 -0
  311. package/docs/design/templates/list-item/default-dark.svg +1 -0
  312. package/docs/design/templates/list-item/default.svg +1 -0
  313. package/docs/design/templates/list-item/multiline-dark.svg +1 -0
  314. package/docs/design/templates/list-item/multiline.svg +1 -0
  315. package/docs/design/templates/list-item/selected-dark.svg +1 -0
  316. package/docs/design/templates/list-item/selected.svg +1 -0
  317. package/docs/design/templates/list-item/trailing-dark.svg +1 -0
  318. package/docs/design/templates/list-item/trailing.svg +1 -0
  319. package/docs/design/templates/list-item-dark.svg +1 -0
  320. package/docs/design/templates/list-item.svg +1 -0
  321. package/docs/design/templates/list.svg +1 -0
  322. package/docs/design/templates/segmented-control/equal-dark.svg +1 -0
  323. package/docs/design/templates/segmented-control/equal.svg +1 -0
  324. package/docs/design/templates/segmented-control/pill-small-dark.svg +1 -0
  325. package/docs/design/templates/segmented-control/pill-small.svg +1 -0
  326. package/docs/design/templates/segmented-control-dark.svg +1 -0
  327. package/docs/design/templates/segmented-control.svg +1 -0
  328. package/docs/design/templates/skeleton/avatar-dark.svg +1 -0
  329. package/docs/design/templates/skeleton/avatar.svg +1 -0
  330. package/docs/design/templates/skeleton/block-dark.svg +1 -0
  331. package/docs/design/templates/skeleton/block.svg +1 -0
  332. package/docs/design/templates/skeleton/lines-dark.svg +1 -0
  333. package/docs/design/templates/skeleton/lines.svg +1 -0
  334. package/docs/design/templates/skeleton-dark.svg +1 -0
  335. package/docs/design/templates/skeleton.svg +1 -0
  336. package/docs/design/templates/state-banner/danger-dark.svg +1 -0
  337. package/docs/design/templates/state-banner/danger.svg +1 -0
  338. package/docs/design/templates/state-banner/info-badge-dark.svg +1 -0
  339. package/docs/design/templates/state-banner/info-badge.svg +1 -0
  340. package/docs/design/templates/state-banner/info-dark.svg +1 -0
  341. package/docs/design/templates/state-banner/info.svg +1 -0
  342. package/docs/design/templates/state-banner/success-dark.svg +1 -0
  343. package/docs/design/templates/state-banner/success.svg +1 -0
  344. package/docs/design/templates/state-banner/warning-dark.svg +1 -0
  345. package/docs/design/templates/state-banner/warning.svg +1 -0
  346. package/docs/design/templates/state-banner-dark.svg +1 -0
  347. package/docs/design/templates/state-banner.svg +1 -0
  348. package/docs/design/templates/tab-bar/workspace-tabs-dark.svg +1 -0
  349. package/docs/design/templates/tab-bar/workspace-tabs.svg +1 -0
  350. package/docs/design/templates/tab-bar-dark.svg +1 -0
  351. package/docs/design/templates/tab-bar.svg +1 -0
  352. package/docs/design/templates/token-search-field/empty-dark.svg +1 -0
  353. package/docs/design/templates/token-search-field/empty.svg +1 -0
  354. package/docs/design/templates/token-search-field/tokens-dark.svg +1 -0
  355. package/docs/design/templates/token-search-field/tokens.svg +1 -0
  356. package/docs/design/templates/token-search-field-dark.svg +1 -0
  357. package/docs/design/templates/token-search-field.svg +1 -0
  358. package/docs/design/templates/toolbar/title-and-actions-dark.svg +1 -0
  359. package/docs/design/templates/toolbar/title-and-actions.svg +1 -0
  360. package/docs/design/templates/toolbar-control-group/borderless-single-dark.svg +1 -0
  361. package/docs/design/templates/toolbar-control-group/borderless-single.svg +1 -0
  362. package/docs/design/templates/toolbar-control-group/icon-buttons-dark.svg +1 -0
  363. package/docs/design/templates/toolbar-control-group/icon-buttons.svg +1 -0
  364. package/docs/design/templates/toolbar-control-group/push-buttons-dark.svg +1 -0
  365. package/docs/design/templates/toolbar-control-group/push-buttons.svg +1 -0
  366. package/docs/design/templates/toolbar-control-group/with-text-dark.svg +1 -0
  367. package/docs/design/templates/toolbar-control-group/with-text.svg +1 -0
  368. package/docs/design/templates/toolbar-control-group-dark.svg +1 -0
  369. package/docs/design/templates/toolbar-control-group.svg +1 -0
  370. package/docs/design/templates/toolbar-dark.svg +1 -0
  371. package/docs/design/templates/toolbar-text/default-dark.svg +1 -0
  372. package/docs/design/templates/toolbar-text/default.svg +1 -0
  373. package/docs/design/templates/toolbar-text/large-dark.svg +1 -0
  374. package/docs/design/templates/toolbar-text/large.svg +1 -0
  375. package/docs/design/templates/toolbar-text/small-dark.svg +1 -0
  376. package/docs/design/templates/toolbar-text/small.svg +1 -0
  377. package/docs/design/templates/toolbar-text-dark.svg +1 -0
  378. package/docs/design/templates/toolbar-text.svg +1 -0
  379. package/docs/design/templates/toolbar.svg +1 -0
  380. package/docs/design/templates/value-table/details-dark.svg +1 -0
  381. package/docs/design/templates/value-table/details.svg +1 -0
  382. package/docs/design/templates/value-table-dark.svg +1 -0
  383. package/docs/design/templates/value-table.svg +1 -0
  384. package/docs/design/templates.md +128 -0
  385. package/docs/design-philosophy.md +33 -11
  386. package/docs/device-class.md +54 -0
  387. package/docs/examples/application-ui-profile.json +60 -0
  388. package/docs/examples/command-palette-adapter.tsx +68 -17
  389. package/docs/examples/component-catalog-extension-v2.json +80 -0
  390. package/docs/examples/component-catalog-extension.json +45 -0
  391. package/docs/layout.md +169 -38
  392. package/docs/nav-stack.md +77 -0
  393. package/docs/recipes.md +64 -16
  394. package/docs/split-view.md +55 -0
  395. package/docs/sunken-panel.md +53 -0
  396. package/docs/surface-scaffold.md +25 -0
  397. package/docs/tab-scaffold.md +52 -0
  398. package/docs/type-contracts.md +127 -0
  399. package/docs/ui-analyzer.md +118 -0
  400. package/docs/ui-doctor.md +91 -0
  401. package/docs/ui-evaluator.md +122 -0
  402. package/docs/ux-demo.md +29 -10
  403. package/docs/webawesome-theme.md +82 -8
  404. package/docs/workbench.md +123 -0
  405. package/doctor/cli.mjs +115 -0
  406. package/doctor/config.schema.json +68 -0
  407. package/doctor/eslint-diagnostics.d.mts +24 -0
  408. package/doctor/eslint-diagnostics.mjs +24 -0
  409. package/doctor/index.d.mts +116 -0
  410. package/doctor/index.mjs +1272 -0
  411. package/doctor/report.schema.json +118 -0
  412. package/evaluator/cli.mjs +89 -0
  413. package/evaluator/index.d.mts +90 -0
  414. package/evaluator/index.mjs +1138 -0
  415. package/evaluator/report.schema.json +152 -0
  416. package/llms.txt +260 -32
  417. package/package.json +205 -38
  418. package/traversal-exclusions.mjs +27 -0
  419. package/ux-demo/recipes/app-shell.tsx +223 -13
  420. package/ux-demo/recipes/collapsible-sidebar.tsx +230 -0
  421. package/ux-demo/recipes/compact-toolbar.tsx +116 -12
  422. package/ux-demo/recipes/composer-form.tsx +120 -19
  423. package/ux-demo/recipes/list-detail-dialog.tsx +205 -0
  424. package/ux-demo/recipes/list-workspace-states.tsx +176 -9
  425. package/ux-demo/recipes/loaders.ts +13 -4
  426. package/ux-demo/recipes/loading-inspector.tsx +191 -0
  427. package/ux-demo/recipes/mount-recipe.ts +31 -5
  428. package/ux-demo/recipes/navigation-sidebar.tsx +123 -11
  429. package/ux-demo/recipes/navigation-stack.tsx +121 -0
  430. package/ux-demo/recipes/recipes.css +125 -16
  431. package/ux-demo/recipes/types.ts +9 -1
  432. package/ux-demo/recipes/workspace-header.tsx +72 -3
  433. package/dist/browser/dialog-header.js +0 -5
  434. package/dist/browser/menu-action-row.js +0 -3
  435. package/dist/browser/menu-header.js +0 -5
  436. package/dist/browser/menu-item.js +0 -3
  437. package/dist/browser/page-header.js +0 -3
  438. package/dist/chunk-2PES33HS.js +0 -13
  439. package/dist/chunk-2PES33HS.js.map +0 -1
  440. package/dist/chunk-55DATV3A.js +0 -10
  441. package/dist/chunk-55DATV3A.js.map +0 -1
  442. package/dist/chunk-7BR3DO2A.js.map +0 -1
  443. package/dist/chunk-7LDCTU7D.js +0 -134
  444. package/dist/chunk-7LDCTU7D.js.map +0 -1
  445. package/dist/chunk-AQNKJRFH.js +0 -79
  446. package/dist/chunk-AQNKJRFH.js.map +0 -1
  447. package/dist/chunk-CTQKI2XL.js +0 -28
  448. package/dist/chunk-CTQKI2XL.js.map +0 -1
  449. package/dist/chunk-DAFFDO33.js +0 -14
  450. package/dist/chunk-DAFFDO33.js.map +0 -1
  451. package/dist/chunk-EGHL5S4P.js +0 -33
  452. package/dist/chunk-EGHL5S4P.js.map +0 -1
  453. package/dist/chunk-GY5WH7TO.js +0 -10
  454. package/dist/chunk-GY5WH7TO.js.map +0 -1
  455. package/dist/chunk-H5AGGVU5.js +0 -75
  456. package/dist/chunk-H5AGGVU5.js.map +0 -1
  457. package/dist/chunk-K3G72I6D.js +0 -24
  458. package/dist/chunk-K3G72I6D.js.map +0 -1
  459. package/dist/chunk-M5JRI6MN.js +0 -27
  460. package/dist/chunk-M5JRI6MN.js.map +0 -1
  461. package/dist/chunk-MBR3TYNL.js +0 -14
  462. package/dist/chunk-MBR3TYNL.js.map +0 -1
  463. package/dist/chunk-MFKMHK5W.js +0 -10
  464. package/dist/chunk-MFKMHK5W.js.map +0 -1
  465. package/dist/chunk-MQIZAD4A.js.map +0 -1
  466. package/dist/chunk-NPPD2A6O.js +0 -40
  467. package/dist/chunk-NPPD2A6O.js.map +0 -1
  468. package/dist/chunk-R6JHHBKQ.js +0 -19
  469. package/dist/chunk-R6JHHBKQ.js.map +0 -1
  470. package/dist/chunk-S3TPM2LP.js +0 -23
  471. package/dist/chunk-S3TPM2LP.js.map +0 -1
  472. package/dist/chunk-TRNBHPNW.js.map +0 -1
  473. package/dist/chunk-VHW5YNIB.js +0 -17
  474. package/dist/chunk-VHW5YNIB.js.map +0 -1
  475. package/dist/chunk-WVPYVDXY.js +0 -15
  476. package/dist/chunk-WVPYVDXY.js.map +0 -1
  477. package/dist/chunk-XZXRLY5Q.js +0 -33
  478. package/dist/chunk-XZXRLY5Q.js.map +0 -1
  479. package/dist/dialog-header.d.ts +0 -15
  480. package/dist/dialog-header.js +0 -5
  481. package/dist/dialog-header.js.map +0 -1
  482. package/dist/menu-action-row.js +0 -4
  483. package/dist/menu-action-row.js.map +0 -1
  484. package/dist/menu-header.d.ts +0 -41
  485. package/dist/menu-header.js +0 -6
  486. package/dist/menu-header.js.map +0 -1
  487. package/dist/menu-item.d.ts +0 -31
  488. package/dist/menu-item.js +0 -4
  489. package/dist/menu-item.js.map +0 -1
  490. package/dist/page-header.d.ts +0 -9
  491. package/dist/page-header.js +0 -3
  492. package/dist/page-header.js.map +0 -1
  493. package/dist/styles/dialog-header.css +0 -87
  494. package/dist/styles/menu-action-row.css +0 -160
  495. package/dist/styles/menu-header.css +0 -143
  496. package/dist/styles/menu-item.css +0 -123
  497. package/dist/styles/page-header.css +0 -33
  498. package/ux-demo/recipes/master-detail-dialog.tsx +0 -45
@@ -0,0 +1,230 @@
1
+ import '@kerfjs/ui/layout.css';
2
+ import '@kerfjs/ui/collapsible-panel.css';
3
+ import './recipes.css';
4
+
5
+ import {
6
+ CollapsiblePanel,
7
+ CollapsiblePanelToggle,
8
+ } from '@kerfjs/ui/collapsible-panel';
9
+ import { deviceClass } from '@kerfjs/ui/device-class';
10
+ import { ListHeader } from '@kerfjs/ui/list-header';
11
+ import { ListItem } from '@kerfjs/ui/list-item';
12
+ import { LucideIcon } from '@kerfjs/ui/lucide-icon';
13
+ import { Text } from '@kerfjs/ui/text';
14
+ import { Toolbar } from '@kerfjs/ui/toolbar';
15
+ import { ToolbarControlGroup } from '@kerfjs/ui/toolbar-control-group';
16
+ import { ToolbarText } from '@kerfjs/ui/toolbar-text';
17
+ import { type SidebarStorage, wireSidebar } from '@kerfjs/ui/wire-sidebar';
18
+ import { signal } from 'kerfjs';
19
+ import { Bell, Folder, Inbox, Users } from 'lucide';
20
+
21
+ import type { RecipeFactory } from './types.js';
22
+
23
+ const RAIL_ACTION = 'recipe-sidebar-rail';
24
+ const DRAWER_ACTION = 'recipe-sidebar-drawer';
25
+
26
+ /**
27
+ * A memory-backed store so the recipe demonstrates the persistence hook without
28
+ * writing to the shared `localStorage` the catalog page runs in.
29
+ */
30
+ function memoryStorage(): SidebarStorage {
31
+ const map = new Map<string, string>();
32
+ return {
33
+ getItem: (key) => map.get(key) ?? null,
34
+ setItem: (key, value) => {
35
+ map.set(key, value);
36
+ },
37
+ };
38
+ }
39
+
40
+ export const createRecipe: RecipeFactory = (announce) => {
41
+ const selected = signal('inbox');
42
+ const railCollapsed = signal(false);
43
+ const drawerCollapsed = signal(true);
44
+ const storage = memoryStorage();
45
+ // A shared window-backed device class: when the viewport is compact the wire
46
+ // switches the rail/drawer to a dismissable overlay presentation.
47
+ const device = deviceClass();
48
+
49
+ const railToggle = (inPanel: boolean) => (
50
+ <CollapsiblePanelToggle
51
+ side="left"
52
+ collapsed={railCollapsed.value}
53
+ action={RAIL_ACTION}
54
+ panelId="sidebar-rail"
55
+ label={railCollapsed.value ? 'Show navigation' : 'Hide navigation'}
56
+ className={inPanel ? '' : 'recipe-collapsible-sidebar__reveal'}
57
+ />
58
+ );
59
+ const drawerToggle = () => (
60
+ <CollapsiblePanelToggle
61
+ side="bottom"
62
+ collapsed={drawerCollapsed.value}
63
+ action={DRAWER_ACTION}
64
+ panelId="sidebar-console"
65
+ label={drawerCollapsed.value ? 'Show activity' : 'Hide activity'}
66
+ />
67
+ );
68
+
69
+ const render = () => (
70
+ <section
71
+ class="kui-recipe recipe-collapsible-sidebar kui-recipe__surface"
72
+ data-recipe="recipe-collapsible-sidebar"
73
+ data-rail-collapsed={String(railCollapsed.value)}
74
+ data-drawer-collapsed={String(drawerCollapsed.value)}
75
+ >
76
+ <CollapsiblePanel
77
+ id="sidebar-rail"
78
+ side="left"
79
+ size={232}
80
+ collapsed={railCollapsed.value}
81
+ label="Workspace navigation"
82
+ className="recipe-collapsible-sidebar__rail kui-pane"
83
+ >
84
+ <div class="recipe-collapsible-sidebar__rail-head">
85
+ <ToolbarText text="Atlas" />
86
+ <ToolbarControlGroup appearance="borderless" single>
87
+ {railToggle(true)}
88
+ </ToolbarControlGroup>
89
+ </div>
90
+ <nav
91
+ class="recipe-collapsible-sidebar__nav kui-pane__content kui-content"
92
+ aria-label="Workspace"
93
+ >
94
+ <section>
95
+ <ListHeader label="Workspace" />
96
+ <ListItem
97
+ action="recipe-action"
98
+ itemId="inbox"
99
+ label="Inbox"
100
+ icon={<LucideIcon icon={Inbox} name="inbox" />}
101
+ trailing={<span>12</span>}
102
+ selected={selected.value === 'inbox'}
103
+ />
104
+ <ListItem
105
+ action="recipe-action"
106
+ itemId="projects"
107
+ label="Projects"
108
+ icon={<LucideIcon icon={Folder} name="folder" />}
109
+ selected={selected.value === 'projects'}
110
+ />
111
+ <ListItem
112
+ action="recipe-action"
113
+ itemId="shared"
114
+ label="Shared with me"
115
+ icon={<LucideIcon icon={Users} name="users" />}
116
+ selected={selected.value === 'shared'}
117
+ />
118
+ </section>
119
+ </nav>
120
+ </CollapsiblePanel>
121
+ <main class="recipe-collapsible-sidebar__main kui-pane">
122
+ <Toolbar
123
+ label="Current navigation view"
124
+ dividerSides=""
125
+ leading={
126
+ <>
127
+ <ToolbarControlGroup appearance="borderless" single>
128
+ {railToggle(false)}
129
+ </ToolbarControlGroup>
130
+ <ToolbarText
131
+ text={
132
+ selected.value === 'projects'
133
+ ? 'Projects'
134
+ : selected.value === 'shared'
135
+ ? 'Shared with me'
136
+ : 'Inbox'
137
+ }
138
+ size="xlarge"
139
+ id="recipe-collapsible-main-title"
140
+ />
141
+ </>
142
+ }
143
+ trailing={
144
+ <ToolbarControlGroup appearance="borderless" single>
145
+ {drawerToggle()}
146
+ </ToolbarControlGroup>
147
+ }
148
+ />
149
+ <div class="recipe-collapsible-sidebar__body kui-pane__content kui-content">
150
+ <Text variant="p" class="kui-recipe__ownership kui-content-item">
151
+ The app owns each panel's <code>collapsed</code> signal, sizes, and
152
+ content; <code>wireSidebar</code> owns the toggle, focus
153
+ move/restore, the compact overlay, and persistence.
154
+ </Text>
155
+ <article class="recipe-collapsible-sidebar__card kui-content-item">
156
+ <strong>Narrow the window to a compact width</strong>
157
+ <Text variant="p" class="kui-recipe__muted">
158
+ The rail and drawer become a dismissable overlay: a backdrop,
159
+ Escape, and a trapped Tab ring, all managed by the wire.
160
+ </Text>
161
+ </article>
162
+ </div>
163
+ </main>
164
+ <CollapsiblePanel
165
+ id="sidebar-console"
166
+ side="bottom"
167
+ size={168}
168
+ collapsed={drawerCollapsed.value}
169
+ label="Activity"
170
+ className="recipe-collapsible-sidebar__drawer kui-pane"
171
+ >
172
+ <Toolbar
173
+ label="Activity"
174
+ dividerSides="b"
175
+ leading={<ToolbarText text="Activity" size="small" />}
176
+ trailing={
177
+ <ToolbarControlGroup appearance="borderless" single>
178
+ {drawerToggle()}
179
+ </ToolbarControlGroup>
180
+ }
181
+ />
182
+ <div class="recipe-collapsible-sidebar__drawer-body kui-pane__content kui-content">
183
+ <ul class="recipe-collapsible-sidebar__log">
184
+ <li>
185
+ <LucideIcon icon={Bell} name="bell" />
186
+ Deploy finished · 2m ago
187
+ </li>
188
+ <li>
189
+ <LucideIcon icon={Bell} name="bell" />
190
+ Review requested · 9m ago
191
+ </li>
192
+ </ul>
193
+ </div>
194
+ </CollapsiblePanel>
195
+ </section>
196
+ );
197
+
198
+ return {
199
+ render,
200
+ action(command, element) {
201
+ const id = element.dataset.itemId;
202
+ if (id) {
203
+ selected.value = id;
204
+ announce(`Opened ${id}`);
205
+ return;
206
+ }
207
+ announce(`${command} requested`);
208
+ },
209
+ wire(root) {
210
+ return wireSidebar(root, {
211
+ deviceClass: device,
212
+ storage,
213
+ panels: [
214
+ {
215
+ id: 'sidebar-rail',
216
+ collapsed: railCollapsed,
217
+ toggleAction: RAIL_ACTION,
218
+ storageKey: 'recipe-sidebar-rail',
219
+ },
220
+ {
221
+ id: 'sidebar-console',
222
+ collapsed: drawerCollapsed,
223
+ toggleAction: DRAWER_ACTION,
224
+ storageKey: 'recipe-sidebar-console',
225
+ },
226
+ ],
227
+ });
228
+ },
229
+ };
230
+ };
@@ -5,6 +5,7 @@ import './recipes.css';
5
5
  import { LucideIcon } from '@kerfjs/ui/lucide-icon';
6
6
  import { SegmentedControl } from '@kerfjs/ui/segmented-control';
7
7
  import { Select } from '@kerfjs/ui/select';
8
+ import { Text } from '@kerfjs/ui/text';
8
9
  import { Toolbar } from '@kerfjs/ui/toolbar';
9
10
  import { ToolbarControlGroup } from '@kerfjs/ui/toolbar-control-group';
10
11
  import { ToolbarText } from '@kerfjs/ui/toolbar-text';
@@ -17,27 +18,130 @@ export const createRecipe: RecipeFactory = (announce) => {
17
18
  const view = signal('list');
18
19
  const sort = signal('updated');
19
20
  const filtered = signal(false);
20
- const render = () => <section class="kui-recipe recipe-compact-toolbar kui-recipe__surface kui-layout" data-recipe="recipe-compact-toolbar">
21
- <Toolbar
22
- label="Task workspace controls"
23
- leading={<ToolbarControlGroup appearance="borderless" single><ToolbarText text="Tasks" size="small" /></ToolbarControlGroup>}
24
- center={<ToolbarControlGroup><SegmentedControl id="recipe-view" label="View" value={view.value} action="recipe-action" appearance="toolbar" shape="pill" size="small" choices={[{ value: 'list', label: 'List' }, { value: 'board', label: 'Board' }, { value: 'timeline', label: 'Timeline' }]} /></ToolbarControlGroup>}
25
- trailing={<div class="kui-control-cluster"><Select name="recipe-sort" value={sort.value} ariaLabel="Sort tasks" fitMenu choices={[{ value: 'updated', label: 'Recently updated' }, { value: 'priority', label: 'Priority' }, { value: 'owner', label: 'Owner' }, { value: 'created', label: 'Created date' }]} /><ToolbarControlGroup label="Task actions" buttonAppearance="push"><button type="button" aria-label="Toggle filters" aria-pressed={String(filtered.value)} data-action="recipe-action" data-recipe-command="filter"><LucideIcon icon={Filter} name="filter" /></button><button type="button" aria-label="Refresh tasks" data-action="recipe-action" data-recipe-command="refresh"><LucideIcon icon={RefreshCw} name="refresh-cw" /></button></ToolbarControlGroup><button class="kui-recipe__button" type="button" aria-label="More task actions" data-action="recipe-action" data-recipe-command="more"><LucideIcon icon={MoreHorizontal} name="more-horizontal" /></button></div>}
26
- />
27
- <div class="recipe-compact-toolbar__guide kui-content-item"><div><strong>ToolbarControlGroup</strong><span class="kui-recipe__muted">Related commands or pressed tools.</span></div><div><strong>SegmentedControl</strong><span class="kui-recipe__muted">A few visible exclusive choices.</span></div><div><strong>Select</strong><span class="kui-recipe__muted">A longer controlled value list.</span></div><div><strong>Ordinary button</strong><span class="kui-recipe__muted">One independent command.</span></div></div>
28
- <p class="kui-recipe__ownership kui-content-item">The recipe owns control semantics and wrapping. The app owns values, actions, persistence, and responsive priority.</p>
29
- </section>;
21
+ const render = () => (
22
+ <section
23
+ class="kui-recipe recipe-compact-toolbar kui-recipe__surface kui-layout"
24
+ data-recipe="recipe-compact-toolbar"
25
+ >
26
+ <Toolbar
27
+ label="Task workspace controls"
28
+ leading={
29
+ <ToolbarControlGroup appearance="borderless" single>
30
+ <ToolbarText text="Tasks" size="small" />
31
+ </ToolbarControlGroup>
32
+ }
33
+ center={
34
+ <ToolbarControlGroup>
35
+ <SegmentedControl<string>
36
+ id="recipe-view"
37
+ label="View"
38
+ value={view.value}
39
+ action="recipe-action"
40
+ appearance="toolbar"
41
+ shape="pill"
42
+ size="small"
43
+ choices={[
44
+ { value: 'list', label: 'List' },
45
+ { value: 'board', label: 'Board' },
46
+ { value: 'timeline', label: 'Timeline' },
47
+ ]}
48
+ />
49
+ </ToolbarControlGroup>
50
+ }
51
+ trailing={
52
+ <div class="kui-control-cluster">
53
+ <Select<string>
54
+ name="recipe-sort"
55
+ value={sort.value}
56
+ ariaLabel="Sort tasks"
57
+ fitMenu
58
+ choices={[
59
+ { value: 'updated', label: 'Recently updated' },
60
+ { value: 'priority', label: 'Priority' },
61
+ { value: 'owner', label: 'Owner' },
62
+ { value: 'created', label: 'Created date' },
63
+ ]}
64
+ />
65
+ <ToolbarControlGroup label="Task actions" buttonAppearance="push">
66
+ <button
67
+ type="button"
68
+ aria-label="Toggle filters"
69
+ aria-pressed={String(filtered.value)}
70
+ data-action="recipe-action"
71
+ data-recipe-command="filter"
72
+ >
73
+ <LucideIcon icon={Filter} name="filter" />
74
+ </button>
75
+ <button
76
+ type="button"
77
+ aria-label="Refresh tasks"
78
+ data-action="recipe-action"
79
+ data-recipe-command="refresh"
80
+ >
81
+ <LucideIcon icon={RefreshCw} name="refresh-cw" />
82
+ </button>
83
+ </ToolbarControlGroup>
84
+ <ToolbarControlGroup label="More task actions" single>
85
+ <button
86
+ type="button"
87
+ aria-label="More task actions"
88
+ data-action="recipe-action"
89
+ data-recipe-command="more"
90
+ >
91
+ <LucideIcon icon={MoreHorizontal} name="more-horizontal" />
92
+ </button>
93
+ </ToolbarControlGroup>
94
+ </div>
95
+ }
96
+ />
97
+ <div class="recipe-compact-toolbar__guide kui-content-item">
98
+ <div>
99
+ <strong>ToolbarControlGroup</strong>
100
+ <span class="kui-recipe__muted">
101
+ Related commands or pressed tools.
102
+ </span>
103
+ </div>
104
+ <div>
105
+ <strong>SegmentedControl</strong>
106
+ <span class="kui-recipe__muted">
107
+ A few visible exclusive choices.
108
+ </span>
109
+ </div>
110
+ <div>
111
+ <strong>Select</strong>
112
+ <span class="kui-recipe__muted">A longer controlled value list.</span>
113
+ </div>
114
+ <div>
115
+ <strong>Ordinary button</strong>
116
+ <span class="kui-recipe__muted">One independent command.</span>
117
+ </div>
118
+ </div>
119
+ <Text variant="p" class="kui-recipe__ownership kui-content-item">
120
+ The recipe owns control semantics and wrapping. The app owns values,
121
+ actions, persistence, and responsive priority.
122
+ </Text>
123
+ </section>
124
+ );
30
125
  return {
31
126
  render,
32
127
  action(command, element) {
33
128
  const value = element.dataset.segmentValue;
34
129
  if (value) view.value = value;
35
130
  if (command === 'filter') filtered.value = !filtered.value;
36
- announce(value ? `View: ${value}` : command === 'filter' ? `Filters ${filtered.value ? 'on' : 'off'}` : `${command} requested`);
131
+ announce(
132
+ value
133
+ ? `View: ${value}`
134
+ : command === 'filter'
135
+ ? `Filters ${filtered.value ? 'on' : 'off'}`
136
+ : `${command} requested`,
137
+ );
37
138
  },
38
139
  change(element) {
39
140
  const value = (element as HTMLElement & { value?: string }).value;
40
- if (element.getAttribute('name') === 'recipe-sort' && value) { sort.value = value; announce(`Sort: ${value}`); }
141
+ if (element.getAttribute('name') === 'recipe-sort' && value) {
142
+ sort.value = value;
143
+ announce(`Sort: ${value}`);
144
+ }
41
145
  },
42
146
  };
43
147
  };
@@ -6,17 +6,25 @@ import '@awesome.me/webawesome/dist/components/input/input.js';
6
6
  import '@awesome.me/webawesome/dist/components/textarea/textarea.js';
7
7
  import './recipes.css';
8
8
 
9
- import { DialogHeader } from '@kerfjs/ui/dialog-header';
9
+ import { ListInsetText } from '@kerfjs/ui/list-inset-text';
10
10
  import { Select } from '@kerfjs/ui/select';
11
11
  import { StateBanner } from '@kerfjs/ui/state-banner';
12
+ import { Text } from '@kerfjs/ui/text';
13
+ import { Toolbar } from '@kerfjs/ui/toolbar';
14
+ import { ToolbarText } from '@kerfjs/ui/toolbar-text';
12
15
  import { signal } from 'kerfjs';
13
16
 
14
17
  import type { RecipeFactory } from './types.js';
15
18
 
16
19
  type ValueField = HTMLElement & { value: string };
17
20
 
18
- const syncControlledFieldValues = (action: HTMLElement, values: Record<string, string>) => {
19
- const form = action.closest<HTMLElement>('[data-recipe="recipe-composer-form"]');
21
+ const syncControlledFieldValues = (
22
+ action: HTMLElement,
23
+ values: Record<string, string>,
24
+ ) => {
25
+ const form = action.closest<HTMLElement>(
26
+ '[data-recipe="recipe-composer-form"]',
27
+ );
20
28
  if (!form) return;
21
29
  for (const [name, value] of Object.entries(values)) {
22
30
  const field = form.querySelector<ValueField>(`[name="${name}"]`);
@@ -26,20 +34,103 @@ const syncControlledFieldValues = (action: HTMLElement, values: Record<string, s
26
34
 
27
35
  export const createRecipe: RecipeFactory = (announce) => {
28
36
  const title = signal('');
29
- const body = signal('The tablet layout now keeps navigation, content, and inspector focus order aligned.');
37
+ const body = signal(
38
+ 'The tablet layout now keeps navigation, content, and inspector focus order aligned.',
39
+ );
30
40
  const audience = signal('team');
31
41
  const status = signal<'idle' | 'error' | 'saved'>('idle');
32
- const render = () => <form class="kui-recipe recipe-form kui-recipe__surface kui-content" data-recipe="recipe-composer-form" aria-labelledby="recipe-composer-title" aria-describedby="recipe-composer-summary" noValidate>
33
- <DialogHeader title="Publish workspace update" titleId="recipe-composer-title" summary="Share a concise, actionable update with collaborators." summaryId="recipe-composer-summary" />
34
- {status.value === 'error' && <StateBanner title="Add a title before publishing" detail="The update body and audience are preserved." tone="danger" urgency="alert" />}
35
- {status.value === 'saved' && <StateBanner title="Update published" detail="The team audience can now read it." tone="success" />}
36
- <div class="recipe-form__section recipe-form__fields">
37
- <wa-input name="recipe-title" label="Update title" hint="Summarize the outcome in one line." required value={title.value}></wa-input>
38
- <wa-textarea name="recipe-body" label="Details" hint="Include decisions, owners, and the next checkpoint." rows="5" maxlength="400" with-count value={body.value}></wa-textarea>
39
- <Select name="recipe-audience" value={audience.value} label="Audience" choices={[{ value: 'team', label: 'Workspace team' }, { value: 'reviewers', label: 'Reviewers' }, { value: 'organization', label: 'Entire organization' }]} />
40
- </div>
41
- <footer class="recipe-form__section recipe-form__footer"><div class="recipe-form__actions kui-control-cluster"><wa-button appearance="outlined" data-action="recipe-action" data-recipe-command="reset">Reset</wa-button><wa-button variant="brand" appearance="accent" data-action="recipe-action" data-recipe-command="submit">Publish update</wa-button></div><p class="kui-recipe__ownership">The recipe owns field, message, and action rhythm. The app owns validation rules, draft persistence, permissions, and transport.</p></footer>
42
- </form>;
42
+ const render = () => (
43
+ <form
44
+ class="kui-recipe recipe-form kui-recipe__surface kui-content"
45
+ data-recipe="recipe-composer-form"
46
+ aria-labelledby="recipe-composer-title"
47
+ aria-describedby="recipe-composer-summary"
48
+ noValidate
49
+ >
50
+ <Toolbar
51
+ label="Publish workspace update"
52
+ dividerSides=""
53
+ leading={
54
+ <ToolbarText
55
+ text="Publish workspace update"
56
+ size="xlarge"
57
+ id="recipe-composer-title"
58
+ />
59
+ }
60
+ />
61
+ <ListInsetText className="kui-recipe__heading-summary">
62
+ <span id="recipe-composer-summary">
63
+ Share a concise, actionable update with collaborators.
64
+ </span>
65
+ </ListInsetText>
66
+ {status.value === 'error' && (
67
+ <StateBanner
68
+ title="Add a title before publishing"
69
+ detail="The update body and audience are preserved."
70
+ tone="danger"
71
+ urgency="alert"
72
+ />
73
+ )}
74
+ {status.value === 'saved' && (
75
+ <StateBanner
76
+ title="Update published"
77
+ detail="The team audience can now read it."
78
+ tone="success"
79
+ />
80
+ )}
81
+ <div class="recipe-form__section recipe-form__fields">
82
+ <wa-input
83
+ name="recipe-title"
84
+ label="Update title"
85
+ hint="Summarize the outcome in one line."
86
+ required
87
+ value={title.value}
88
+ ></wa-input>
89
+ <wa-textarea
90
+ name="recipe-body"
91
+ label="Details"
92
+ hint="Include decisions, owners, and the next checkpoint."
93
+ rows="5"
94
+ maxlength="400"
95
+ with-count
96
+ value={body.value}
97
+ ></wa-textarea>
98
+ <Select<string>
99
+ name="recipe-audience"
100
+ value={audience.value}
101
+ label="Audience"
102
+ choices={[
103
+ { value: 'team', label: 'Workspace team' },
104
+ { value: 'reviewers', label: 'Reviewers' },
105
+ { value: 'organization', label: 'Entire organization' },
106
+ ]}
107
+ />
108
+ </div>
109
+ <footer class="recipe-form__section recipe-form__footer">
110
+ <div class="recipe-form__actions kui-control-cluster">
111
+ <wa-button
112
+ appearance="outlined"
113
+ data-action="recipe-action"
114
+ data-recipe-command="reset"
115
+ >
116
+ Reset
117
+ </wa-button>
118
+ <wa-button
119
+ variant="brand"
120
+ appearance="accent"
121
+ data-action="recipe-action"
122
+ data-recipe-command="submit"
123
+ >
124
+ Publish update
125
+ </wa-button>
126
+ </div>
127
+ <Text variant="p" class="kui-recipe__ownership">
128
+ The recipe owns field, message, and action rhythm. The app owns
129
+ validation rules, draft persistence, permissions, and transport.
130
+ </Text>
131
+ </footer>
132
+ </form>
133
+ );
43
134
  return {
44
135
  render,
45
136
  action(command, element) {
@@ -47,17 +138,27 @@ export const createRecipe: RecipeFactory = (announce) => {
47
138
  title.value = '';
48
139
  body.value = '';
49
140
  status.value = 'idle';
50
- syncControlledFieldValues(element, { 'recipe-title': title.value, 'recipe-body': body.value });
141
+ syncControlledFieldValues(element, {
142
+ 'recipe-title': title.value,
143
+ 'recipe-body': body.value,
144
+ });
51
145
  announce('Draft reset');
52
146
  return;
53
147
  }
54
- if (command === 'submit') { status.value = title.value.trim() ? 'saved' : 'error'; announce(status.value === 'saved' ? 'Update published' : 'Title required'); }
148
+ if (command === 'submit') {
149
+ status.value = title.value.trim() ? 'saved' : 'error';
150
+ announce(
151
+ status.value === 'saved' ? 'Update published' : 'Title required',
152
+ );
153
+ }
55
154
  },
56
155
  change(element) {
57
- const value = (element as HTMLElement & { value?: string | null }).value ?? '';
156
+ const value =
157
+ (element as HTMLElement & { value?: string | null }).value ?? '';
58
158
  if (element.getAttribute('name') === 'recipe-title') title.value = value;
59
159
  if (element.getAttribute('name') === 'recipe-body') body.value = value;
60
- if (element.getAttribute('name') === 'recipe-audience') audience.value = value;
160
+ if (element.getAttribute('name') === 'recipe-audience')
161
+ audience.value = value;
61
162
  },
62
163
  };
63
164
  };