@kerfjs/ui 5.0.0-beta.49 → 5.0.0-beta.51

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 (319) hide show
  1. package/README.md +69 -15
  2. package/ai/catalog-authoring.json +12 -1
  3. package/ai/catalog-authoring.schema.json +49 -1
  4. package/ai/compile-time-contracts-v1.json +19 -2
  5. package/ai/compile-time-contracts-v1.schema.json +1 -0
  6. package/ai/component-catalog-v2-overrides.json +7 -0
  7. package/ai/component-catalog-v2.d.ts +19 -1
  8. package/ai/component-catalog-v2.json +920 -149
  9. package/ai/component-catalog-v2.schema.json +33 -1
  10. package/ai/component-catalog.json +689 -153
  11. package/ai/component-catalog.schema.json +21 -1
  12. package/ai/public-api-signatures-v1.md +404 -184
  13. package/ai/skill.md +31 -14
  14. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  15. package/analyzer/index.mjs +105 -35
  16. package/dist/app-tab.d.ts +3 -1
  17. package/dist/app-tab.js +1 -1
  18. package/dist/badge.d.ts +24 -0
  19. package/dist/badge.js +3 -0
  20. package/dist/badge.js.map +1 -0
  21. package/dist/browser/badge.js +3 -0
  22. package/dist/browser/list-header.js +1 -0
  23. package/dist/browser/state-banner.js +1 -0
  24. package/dist/catalog-resources.d.ts +2 -2
  25. package/dist/catalog.d.ts +47 -125
  26. package/dist/catalog.js +429 -262
  27. package/dist/catalog.js.map +1 -1
  28. package/dist/{chunk-W2FK7ZNY.js → chunk-4R777DUZ.js} +10 -2
  29. package/dist/chunk-4R777DUZ.js.map +1 -0
  30. package/dist/{chunk-OMSRSL3B.js → chunk-5FZZMIMD.js} +6 -4
  31. package/dist/chunk-5FZZMIMD.js.map +1 -0
  32. package/dist/{chunk-AQFWBG23.js → chunk-5PMGQDG7.js} +5 -3
  33. package/dist/chunk-5PMGQDG7.js.map +1 -0
  34. package/dist/{chunk-SOK5EUF7.js → chunk-6ZXOQEAN.js} +4 -2
  35. package/dist/chunk-6ZXOQEAN.js.map +1 -0
  36. package/dist/{chunk-I4V3UDSA.js → chunk-7GUQYHKA.js} +25 -6
  37. package/dist/chunk-7GUQYHKA.js.map +1 -0
  38. package/dist/{chunk-XKFRMGMW.js → chunk-7IUSV4XG.js} +3 -1
  39. package/dist/chunk-7IUSV4XG.js.map +1 -0
  40. package/dist/{chunk-IU4QUY5I.js → chunk-AEPXGCNF.js} +20 -3
  41. package/dist/chunk-AEPXGCNF.js.map +1 -0
  42. package/dist/{chunk-VDUJZF5G.js → chunk-CMUIXJZM.js} +2 -2
  43. package/dist/{chunk-VDUJZF5G.js.map → chunk-CMUIXJZM.js.map} +1 -1
  44. package/dist/{chunk-DAO2VFTT.js → chunk-D547PH4L.js} +7 -5
  45. package/dist/chunk-D547PH4L.js.map +1 -0
  46. package/dist/{chunk-2TYUFZUC.js → chunk-D7GWXIAS.js} +4 -2
  47. package/dist/chunk-D7GWXIAS.js.map +1 -0
  48. package/dist/{chunk-E34TE2ZI.js → chunk-DVZCMMB3.js} +6 -4
  49. package/dist/chunk-DVZCMMB3.js.map +1 -0
  50. package/dist/{chunk-6NDBE2OK.js → chunk-E36EVCKG.js} +5 -3
  51. package/dist/chunk-E36EVCKG.js.map +1 -0
  52. package/dist/chunk-EKYZCRCX.js +256 -0
  53. package/dist/chunk-EKYZCRCX.js.map +1 -0
  54. package/dist/{chunk-TIGSG6BX.js → chunk-HJKRCKDR.js} +7 -3
  55. package/dist/chunk-HJKRCKDR.js.map +1 -0
  56. package/dist/{chunk-Y6LYKFXY.js → chunk-HMQ2ZDGG.js} +5 -3
  57. package/dist/chunk-HMQ2ZDGG.js.map +1 -0
  58. package/dist/{chunk-UDHHKZWO.js → chunk-JM53SMVF.js} +9 -5
  59. package/dist/chunk-JM53SMVF.js.map +1 -0
  60. package/dist/{chunk-OGTJNHRG.js → chunk-JMGKM7RK.js} +6 -4
  61. package/dist/chunk-JMGKM7RK.js.map +1 -0
  62. package/dist/{chunk-GYGM363P.js → chunk-KX7DP2GO.js} +17 -7
  63. package/dist/chunk-KX7DP2GO.js.map +1 -0
  64. package/dist/{chunk-OL4TC3U2.js → chunk-MO56ZZLG.js} +6 -2
  65. package/dist/chunk-MO56ZZLG.js.map +1 -0
  66. package/dist/{chunk-VXFGMDA7.js → chunk-MTM43SJO.js} +16 -2
  67. package/dist/chunk-MTM43SJO.js.map +1 -0
  68. package/dist/{chunk-ZPWZIVI6.js → chunk-N3GKMPDW.js} +7 -3
  69. package/dist/chunk-N3GKMPDW.js.map +1 -0
  70. package/dist/{chunk-DYBPI5O2.js → chunk-NDUGJ4TU.js} +4 -2
  71. package/dist/chunk-NDUGJ4TU.js.map +1 -0
  72. package/dist/{chunk-I45QO2IZ.js → chunk-NMGTHYW3.js} +7 -5
  73. package/dist/chunk-NMGTHYW3.js.map +1 -0
  74. package/dist/{chunk-WSXUPSID.js → chunk-NN6GYOA2.js} +7 -3
  75. package/dist/chunk-NN6GYOA2.js.map +1 -0
  76. package/dist/{chunk-OGNE3OFT.js → chunk-NZXWU4R5.js} +24 -3
  77. package/dist/chunk-NZXWU4R5.js.map +1 -0
  78. package/dist/{chunk-V6GQKOX2.js → chunk-O3RCCSQJ.js} +6 -4
  79. package/dist/chunk-O3RCCSQJ.js.map +1 -0
  80. package/dist/{chunk-WVLMZ5SG.js → chunk-S4QRSBFI.js} +25 -3
  81. package/dist/chunk-S4QRSBFI.js.map +1 -0
  82. package/dist/{chunk-CK6P5AUK.js → chunk-UBH743HV.js} +10 -7
  83. package/dist/chunk-UBH743HV.js.map +1 -0
  84. package/dist/{chunk-T7DOWS6T.js → chunk-ULCDZTWL.js} +7 -4
  85. package/dist/chunk-ULCDZTWL.js.map +1 -0
  86. package/dist/{chunk-V6HCTCVD.js → chunk-UPZ6EEJN.js} +9 -5
  87. package/dist/chunk-UPZ6EEJN.js.map +1 -0
  88. package/dist/{chunk-CAB6NQ2T.js → chunk-VOCPXGQN.js} +3 -1
  89. package/dist/chunk-VOCPXGQN.js.map +1 -0
  90. package/dist/chunk-XD7DWYXG.js +34 -0
  91. package/dist/chunk-XD7DWYXG.js.map +1 -0
  92. package/dist/{chunk-B6JYRX3P.js → chunk-ZIYOJFZD.js} +43 -4
  93. package/dist/chunk-ZIYOJFZD.js.map +1 -0
  94. package/dist/{chunk-EYALJQQD.js → chunk-ZK5EGVFP.js} +4 -2
  95. package/dist/chunk-ZK5EGVFP.js.map +1 -0
  96. package/dist/{chunk-6WTETUZ6.js → chunk-ZLWQZUGF.js} +8 -2
  97. package/dist/chunk-ZLWQZUGF.js.map +1 -0
  98. package/dist/collapsible-panel.d.ts +4 -2
  99. package/dist/collapsible-panel.js +4 -2
  100. package/dist/collapsible-panel.js.map +1 -1
  101. package/dist/css-values.d.ts +39 -3
  102. package/dist/css-values.js +1 -1
  103. package/dist/disclosure-arrow.d.ts +3 -1
  104. package/dist/disclosure-arrow.js +1 -1
  105. package/dist/empty-state.d.ts +3 -1
  106. package/dist/empty-state.js +1 -1
  107. package/dist/floating-toolbar.d.ts +3 -1
  108. package/dist/floating-toolbar.js +1 -1
  109. package/dist/grid.d.ts +17 -1
  110. package/dist/grid.js +2 -1
  111. package/dist/index.d.ts +4 -3
  112. package/dist/index.js +34 -33
  113. package/dist/list-action-row.d.ts +3 -1
  114. package/dist/list-action-row.js +1 -1
  115. package/dist/list-header.d.ts +6 -1
  116. package/dist/list-header.js +2 -1
  117. package/dist/list-inset-control.d.ts +3 -1
  118. package/dist/list-inset-control.js +1 -1
  119. package/dist/list-inset-text.d.ts +3 -1
  120. package/dist/list-inset-text.js +1 -1
  121. package/dist/list-item.d.ts +3 -1
  122. package/dist/list-item.js +1 -1
  123. package/dist/list.d.ts +23 -2
  124. package/dist/list.js +2 -1
  125. package/dist/loading-spinner.d.ts +3 -1
  126. package/dist/loading-spinner.js +1 -1
  127. package/dist/lucide-icon.d.ts +3 -1
  128. package/dist/lucide-icon.js +1 -1
  129. package/dist/nav-stack.d.ts +3 -1
  130. package/dist/nav-stack.js +1 -1
  131. package/dist/pane.d.ts +19 -2
  132. package/dist/pane.js +1 -1
  133. package/dist/resizable-region.d.ts +5 -2
  134. package/dist/resizable-region.js +1 -1
  135. package/dist/row.d.ts +21 -1
  136. package/dist/row.js +2 -1
  137. package/dist/segmented-control.d.ts +3 -1
  138. package/dist/segmented-control.js +1 -1
  139. package/dist/select.d.ts +16 -4
  140. package/dist/select.js +1 -1
  141. package/dist/skeleton.d.ts +3 -1
  142. package/dist/skeleton.js +1 -1
  143. package/dist/spacer.d.ts +3 -1
  144. package/dist/spacer.js +1 -1
  145. package/dist/split-view.d.ts +3 -1
  146. package/dist/split-view.js +24 -5
  147. package/dist/split-view.js.map +1 -1
  148. package/dist/state-banner.d.ts +3 -1
  149. package/dist/state-banner.js +2 -1
  150. package/dist/styles/badge.css +86 -0
  151. package/dist/styles/catalog/components/catalog-detail.css +35 -0
  152. package/dist/styles/catalog/components/catalog-example-stack.css +9 -0
  153. package/dist/styles/catalog/components/catalog-example.css +180 -0
  154. package/dist/styles/catalog/components/catalog-resource-footer.css +37 -0
  155. package/dist/styles/catalog/components/catalog-secondary-sections.css +38 -0
  156. package/dist/styles/catalog/components/catalog-section-list.css +22 -0
  157. package/dist/styles/catalog/components/catalog-sidebar.css +82 -0
  158. package/dist/styles/catalog/components/catalog-stage.css +60 -0
  159. package/dist/styles/catalog/components/catalog.css +22 -0
  160. package/dist/styles/catalog.css +10 -587
  161. package/dist/styles/collapsible-panel.css +132 -4
  162. package/dist/styles/document.css +23 -0
  163. package/dist/styles/foundation.css +21 -7
  164. package/dist/styles/grid.css +10 -0
  165. package/dist/styles/list-header.css +49 -60
  166. package/dist/styles/list-inset-control.css +8 -1
  167. package/dist/styles/list-item.css +6 -0
  168. package/dist/styles/list.css +11 -0
  169. package/dist/styles/nav-stack.css +89 -2
  170. package/dist/styles/pane.css +86 -1
  171. package/dist/styles/resizable-region.css +117 -5
  172. package/dist/styles/row.css +10 -0
  173. package/dist/styles/select.css +39 -7
  174. package/dist/styles/split-view.css +108 -2
  175. package/dist/styles/state-banner.css +0 -27
  176. package/dist/styles/styles.css +1 -0
  177. package/dist/styles/tab-bar.css +6 -1
  178. package/dist/styles/tab-scaffold.css +64 -1
  179. package/dist/styles/text.css +10 -0
  180. package/dist/styles/token-search-field.css +5 -40
  181. package/dist/styles/toolbar-control-group.css +198 -25
  182. package/dist/styles/toolbar-text.css +8 -1
  183. package/dist/styles/toolbar.css +169 -5
  184. package/dist/styles/webawesome.css +70 -9
  185. package/dist/styles/workbench.css +136 -4
  186. package/dist/sunken-panel.d.ts +3 -1
  187. package/dist/sunken-panel.js +1 -1
  188. package/dist/surface-scaffold.d.ts +6 -2
  189. package/dist/surface-scaffold.js +1 -1
  190. package/dist/tab-bar.d.ts +8 -1
  191. package/dist/tab-bar.js +1 -1
  192. package/dist/tab-scaffold.d.ts +3 -1
  193. package/dist/tab-scaffold.js +3 -1
  194. package/dist/tab-scaffold.js.map +1 -1
  195. package/dist/text.d.ts +9 -5
  196. package/dist/text.js +1 -1
  197. package/dist/token-search-field.d.ts +5 -1
  198. package/dist/token-search-field.js +1 -1
  199. package/dist/toolbar-control-group.d.ts +33 -3
  200. package/dist/toolbar-control-group.js +1 -1
  201. package/dist/toolbar-text.d.ts +3 -1
  202. package/dist/toolbar-text.js +1 -1
  203. package/dist/toolbar.d.ts +30 -1
  204. package/dist/toolbar.js +1 -1
  205. package/dist/types-CEsieBZi.d.ts +69 -0
  206. package/dist/value-table.d.ts +6 -2
  207. package/dist/value-table.js +1 -1
  208. package/dist/wire-resizable-regions.js +1 -1
  209. package/dist/wire-sidebar.d.ts +18 -3
  210. package/dist/wire-sidebar.js +95 -14
  211. package/dist/wire-sidebar.js.map +1 -1
  212. package/dist/wire-token-search-fields.js +1 -1
  213. package/dist/workbench.d.ts +3 -1
  214. package/dist/workbench.js +3 -1
  215. package/dist/workbench.js.map +1 -1
  216. package/docs/accessibility.md +56 -9
  217. package/docs/app-layouts.md +73 -0
  218. package/docs/catalog.md +48 -9
  219. package/docs/collapsible-panel.md +81 -8
  220. package/docs/component-contract.md +96 -28
  221. package/docs/component-integration.md +9 -4
  222. package/docs/component-selection.md +36 -15
  223. package/docs/design/templates/list/stack-dark.svg +1 -1
  224. package/docs/design/templates/list/stack.svg +1 -1
  225. package/docs/design/templates/list-dark.svg +1 -1
  226. package/docs/design/templates/list-header/action-dark.svg +1 -1
  227. package/docs/design/templates/list-header/action.svg +1 -1
  228. package/docs/design/templates/list-header/count-dark.svg +1 -1
  229. package/docs/design/templates/list-header/count.svg +1 -1
  230. package/docs/design/templates/list-header/inline-action-dark.svg +1 -1
  231. package/docs/design/templates/list-header/inline-action.svg +1 -1
  232. package/docs/design/templates/list-header/toggle-expanded-dark.svg +1 -1
  233. package/docs/design/templates/list-header/toggle-expanded.svg +1 -1
  234. package/docs/design/templates/list-header-dark.svg +1 -1
  235. package/docs/design/templates/list-header.svg +1 -1
  236. package/docs/design/templates/list.svg +1 -1
  237. package/docs/design/templates/state-banner/info-badge-dark.svg +1 -1
  238. package/docs/design/templates/state-banner/info-badge.svg +1 -1
  239. package/docs/design/templates/state-banner-dark.svg +1 -1
  240. package/docs/design/templates/state-banner.svg +1 -1
  241. package/docs/design/templates/toolbar/title-and-actions-dark.svg +1 -1
  242. package/docs/design/templates/toolbar/title-and-actions.svg +1 -1
  243. package/docs/design/templates/toolbar-control-group/with-text-dark.svg +1 -1
  244. package/docs/design/templates/toolbar-control-group/with-text.svg +1 -1
  245. package/docs/design/templates/toolbar-control-group-dark.svg +1 -1
  246. package/docs/design/templates/toolbar-control-group.svg +1 -1
  247. package/docs/design/templates/toolbar-dark.svg +1 -1
  248. package/docs/design/templates/toolbar-text/default-dark.svg +1 -1
  249. package/docs/design/templates/toolbar-text/default.svg +1 -1
  250. package/docs/design/templates/toolbar-text/large-dark.svg +1 -1
  251. package/docs/design/templates/toolbar-text/large.svg +1 -1
  252. package/docs/design/templates/toolbar-text/small-dark.svg +1 -1
  253. package/docs/design/templates/toolbar-text/small.svg +1 -1
  254. package/docs/design/templates/toolbar-text-dark.svg +1 -1
  255. package/docs/design/templates/toolbar-text.svg +1 -1
  256. package/docs/design/templates/toolbar.svg +1 -1
  257. package/docs/design-philosophy.md +6 -5
  258. package/docs/document-baseline.md +31 -0
  259. package/docs/layout.md +86 -21
  260. package/docs/nav-stack.md +8 -0
  261. package/docs/recipes.md +78 -43
  262. package/docs/split-view.md +8 -0
  263. package/docs/tab-scaffold.md +4 -2
  264. package/docs/type-contracts.md +21 -16
  265. package/docs/ui-analyzer.md +19 -0
  266. package/docs/ui-evaluator.md +17 -0
  267. package/docs/ux-demo.md +8 -8
  268. package/docs/webawesome-theme.md +25 -6
  269. package/docs/workbench.md +20 -1
  270. package/evaluator/index.mjs +73 -8
  271. package/llms.txt +61 -23
  272. package/package.json +12 -3
  273. package/ux-demo/recipes/app-shell.tsx +244 -184
  274. package/ux-demo/recipes/collapsible-sidebar.tsx +175 -116
  275. package/ux-demo/recipes/compact-toolbar.tsx +119 -102
  276. package/ux-demo/recipes/composer-form.tsx +79 -69
  277. package/ux-demo/recipes/list-detail-dialog.tsx +120 -136
  278. package/ux-demo/recipes/list-workspace-states.tsx +85 -79
  279. package/ux-demo/recipes/loaders.ts +5 -2
  280. package/ux-demo/recipes/loading-inspector.tsx +151 -134
  281. package/ux-demo/recipes/navigation-sidebar.tsx +93 -80
  282. package/ux-demo/recipes/navigation-stack.tsx +33 -22
  283. package/ux-demo/recipes/types.ts +14 -0
  284. package/ux-demo/recipes/workspace-header.tsx +73 -57
  285. package/dist/chunk-2TYUFZUC.js.map +0 -1
  286. package/dist/chunk-6NDBE2OK.js.map +0 -1
  287. package/dist/chunk-6WTETUZ6.js.map +0 -1
  288. package/dist/chunk-AQFWBG23.js.map +0 -1
  289. package/dist/chunk-B6JYRX3P.js.map +0 -1
  290. package/dist/chunk-CAB6NQ2T.js.map +0 -1
  291. package/dist/chunk-CK6P5AUK.js.map +0 -1
  292. package/dist/chunk-DAO2VFTT.js.map +0 -1
  293. package/dist/chunk-DYBPI5O2.js.map +0 -1
  294. package/dist/chunk-E34TE2ZI.js.map +0 -1
  295. package/dist/chunk-EYALJQQD.js.map +0 -1
  296. package/dist/chunk-GYGM363P.js.map +0 -1
  297. package/dist/chunk-I45QO2IZ.js.map +0 -1
  298. package/dist/chunk-I4V3UDSA.js.map +0 -1
  299. package/dist/chunk-IU4QUY5I.js.map +0 -1
  300. package/dist/chunk-OGNE3OFT.js.map +0 -1
  301. package/dist/chunk-OGTJNHRG.js.map +0 -1
  302. package/dist/chunk-OL4TC3U2.js.map +0 -1
  303. package/dist/chunk-OMSRSL3B.js.map +0 -1
  304. package/dist/chunk-SOK5EUF7.js.map +0 -1
  305. package/dist/chunk-T7DOWS6T.js.map +0 -1
  306. package/dist/chunk-TIGSG6BX.js.map +0 -1
  307. package/dist/chunk-UDHHKZWO.js.map +0 -1
  308. package/dist/chunk-V6GQKOX2.js.map +0 -1
  309. package/dist/chunk-V6HCTCVD.js.map +0 -1
  310. package/dist/chunk-VXFGMDA7.js.map +0 -1
  311. package/dist/chunk-W2FK7ZNY.js.map +0 -1
  312. package/dist/chunk-WN52USHV.js +0 -115
  313. package/dist/chunk-WN52USHV.js.map +0 -1
  314. package/dist/chunk-WSXUPSID.js.map +0 -1
  315. package/dist/chunk-WVLMZ5SG.js.map +0 -1
  316. package/dist/chunk-XKFRMGMW.js.map +0 -1
  317. package/dist/chunk-Y6LYKFXY.js.map +0 -1
  318. package/dist/chunk-ZPWZIVI6.js.map +0 -1
  319. package/ux-demo/recipes/recipes.css +0 -453
@@ -1,41 +1,51 @@
1
1
  import '@kerfjs/ui/layout.css';
2
- import './recipes.css';
3
2
 
4
3
  import { EmptyState } from '@kerfjs/ui/empty-state';
4
+ import { ListItem } from '@kerfjs/ui/list-item';
5
5
  import { LoadingSpinner } from '@kerfjs/ui/loading-spinner';
6
+ import { Pane } from '@kerfjs/ui/pane';
7
+ import { Row } from '@kerfjs/ui/row';
6
8
  import { StateBanner } from '@kerfjs/ui/state-banner';
7
- 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';
11
12
  import { signal } from 'kerfjs';
12
13
 
13
- import type { RecipeFactory } from './types.js';
14
+ import type { RecipeFactory, RecipePresentation } from './types.js';
14
15
 
15
16
  type ListState = 'loading' | 'empty' | 'populated' | 'stale' | 'error';
16
17
  const items = [
17
- 'Audit keyboard focus order',
18
- 'Verify 200% zoom layout',
19
- 'Publish package migration notes',
20
- ];
18
+ ['Audit keyboard focus order', 'In review · Mara'],
19
+ ['Verify 200% zoom layout', 'Ready · Sam'],
20
+ ['Publish package migration notes', 'Draft · Inez'],
21
+ ] as const;
22
+
23
+ export const presentation: RecipePresentation = {
24
+ viewport: {
25
+ layout: 'grid',
26
+ width: 'full',
27
+ minHeight: 'medium',
28
+ frame: 'solid',
29
+ surface: 'default',
30
+ overflow: 'hidden',
31
+ shadow: true,
32
+ },
33
+ note: 'The recipe owns feedback placement and stable content. The app owns fetching, cache age, retry policy, and domain rows.',
34
+ };
21
35
 
22
36
  export const createRecipe: RecipeFactory = (announce) => {
23
37
  const state = signal<ListState>('loading');
24
38
  const populated = () => (
25
- <ul class="recipe-list__items" aria-label="Release tasks">
26
- {items.map((item, index) => (
27
- <li>
28
- <strong>{item}</strong>
29
- <span class="kui-recipe__muted">
30
- {index === 0
31
- ? 'In review · Mara'
32
- : index === 1
33
- ? 'Ready · Sam'
34
- : 'Draft · Inez'}
35
- </span>
36
- </li>
39
+ <section aria-label="Release task list">
40
+ {items.map(([title, detail]) => (
41
+ <ListItem
42
+ action="recipe-action"
43
+ label={title}
44
+ description={detail}
45
+ rootAttributes={{ 'data-recipe-command': 'open-task' }}
46
+ />
37
47
  ))}
38
- </ul>
48
+ </section>
39
49
  );
40
50
  const renderBody = () => {
41
51
  if (state.value === 'loading')
@@ -46,7 +56,6 @@ export const createRecipe: RecipeFactory = (announce) => {
46
56
  busy
47
57
  action={
48
58
  <button
49
- class="kui-recipe__button"
50
59
  type="button"
51
60
  data-action="recipe-action"
52
61
  data-recipe-command="load"
@@ -63,8 +72,6 @@ export const createRecipe: RecipeFactory = (announce) => {
63
72
  detail="Create the first task for this milestone."
64
73
  action={
65
74
  <button
66
- class="kui-recipe__button"
67
- data-primary="true"
68
75
  type="button"
69
76
  data-action="recipe-action"
70
77
  data-recipe-command="create"
@@ -83,7 +90,6 @@ export const createRecipe: RecipeFactory = (announce) => {
83
90
  urgency="alert"
84
91
  action={
85
92
  <button
86
- class="kui-recipe__button"
87
93
  type="button"
88
94
  data-action="recipe-action"
89
95
  data-recipe-command="retry"
@@ -101,17 +107,16 @@ export const createRecipe: RecipeFactory = (announce) => {
101
107
  detail="Refreshing in the background."
102
108
  tone="warning"
103
109
  action={
104
- <span class="kui-inline-metadata">
110
+ <Row gap="xs" vAlign="middle">
105
111
  <LoadingSpinner label="Refreshing release tasks" />
106
112
  <button
107
- class="kui-recipe__button"
108
113
  type="button"
109
114
  data-action="recipe-action"
110
115
  data-recipe-command="finish"
111
116
  >
112
117
  Finish refresh
113
118
  </button>
114
- </span>
119
+ </Row>
115
120
  }
116
121
  />
117
122
  )}
@@ -120,59 +125,60 @@ export const createRecipe: RecipeFactory = (announce) => {
120
125
  );
121
126
  };
122
127
  const render = () => (
123
- <section
124
- class="kui-recipe recipe-list kui-recipe__surface kui-pane"
125
- data-recipe="recipe-list-workspace-states"
126
- data-list-state={state.value}
127
- >
128
- <Toolbar
129
- label="Release tasks"
130
- dividerSides=""
131
- leading={
132
- <ToolbarText
133
- text="Release tasks"
134
- size="xlarge"
135
- id="recipe-list-title"
136
- />
137
- }
138
- trailing={
139
- <ToolbarControlGroup appearance="borderless">
140
- <button
141
- class="kui-recipe__button"
142
- type="button"
143
- data-action="recipe-action"
144
- data-recipe-command="empty"
145
- >
146
- Clear
147
- </button>
148
- <button
149
- class="kui-recipe__button"
150
- type="button"
151
- data-action="recipe-action"
152
- data-recipe-command="fail"
153
- >
154
- Simulate failure
155
- </button>
156
- <button
157
- class="kui-recipe__button"
158
- data-primary="true"
159
- type="button"
160
- data-action="recipe-action"
161
- data-recipe-command="refresh"
128
+ <Pane
129
+ element="section"
130
+ label="Release tasks"
131
+ rootAttributes={{
132
+ 'data-recipe': 'recipe-list-workspace-states',
133
+ 'data-list-state': state.value,
134
+ }}
135
+ header={
136
+ <Toolbar
137
+ label="Release tasks"
138
+ dividerSides=""
139
+ responsive="stack"
140
+ responsiveAt="compact"
141
+ leading={
142
+ <ToolbarText
143
+ text="Release tasks"
144
+ size="xlarge"
145
+ id="recipe-list-title"
146
+ />
147
+ }
148
+ trailing={
149
+ <ToolbarControlGroup
150
+ appearance="borderless"
151
+ content="text"
152
+ buttonAppearance="push"
162
153
  >
163
- Refresh
164
- </button>
165
- </ToolbarControlGroup>
166
- }
167
- />
168
- <div class="recipe-list__body kui-pane__content kui-content">
169
- {renderBody()}
170
- <Text class="kui-recipe__ownership kui-content-item">
171
- The recipe owns feedback placement and stable content. The app owns
172
- fetching, cache age, retry policy, and domain rows.
173
- </Text>
174
- </div>
175
- </section>
154
+ <button
155
+ type="button"
156
+ data-action="recipe-action"
157
+ data-recipe-command="empty"
158
+ >
159
+ Clear
160
+ </button>
161
+ <button
162
+ type="button"
163
+ data-action="recipe-action"
164
+ data-recipe-command="fail"
165
+ >
166
+ Simulate failure
167
+ </button>
168
+ <button
169
+ type="button"
170
+ data-action="recipe-action"
171
+ data-recipe-command="refresh"
172
+ >
173
+ Refresh
174
+ </button>
175
+ </ToolbarControlGroup>
176
+ }
177
+ />
178
+ }
179
+ >
180
+ {renderBody()}
181
+ </Pane>
176
182
  );
177
183
  return {
178
184
  render,
@@ -1,4 +1,4 @@
1
- import type { RecipeFactory } from './types.js';
1
+ import type { RecipeFactory, RecipePresentation } from './types.js';
2
2
 
3
3
  export const recipeIds = [
4
4
  'recipe-app-shell',
@@ -17,7 +17,10 @@ export type RecipeId = (typeof recipeIds)[number];
17
17
 
18
18
  export const recipeLoaders: Record<
19
19
  RecipeId,
20
- () => Promise<{ createRecipe: RecipeFactory }>
20
+ () => Promise<{
21
+ createRecipe: RecipeFactory;
22
+ presentation: RecipePresentation;
23
+ }>
21
24
  > = {
22
25
  'recipe-app-shell': () => import('./app-shell.js'),
23
26
  'recipe-navigation-sidebar': () => import('./navigation-sidebar.js'),
@@ -1,10 +1,12 @@
1
1
  import '@kerfjs/ui/layout.css';
2
2
  import '@kerfjs/ui/select/register';
3
- import './recipes.css';
4
3
 
5
4
  import { em } from '@kerfjs/ui/css-values';
5
+ import { List } from '@kerfjs/ui/list';
6
+ import { ListInsetText } from '@kerfjs/ui/list-inset-text';
6
7
  import { ListItem } from '@kerfjs/ui/list-item';
7
8
  import { LucideIcon } from '@kerfjs/ui/lucide-icon';
9
+ import { Pane } from '@kerfjs/ui/pane';
8
10
  import { SegmentedControl } from '@kerfjs/ui/segmented-control';
9
11
  import { Select } from '@kerfjs/ui/select';
10
12
  import { Skeleton } from '@kerfjs/ui/skeleton';
@@ -15,9 +17,20 @@ import { ToolbarControlGroup } from '@kerfjs/ui/toolbar-control-group';
15
17
  import { ToolbarText } from '@kerfjs/ui/toolbar-text';
16
18
  import { ValueTable, ValueTableRow } from '@kerfjs/ui/value-table';
17
19
  import { signal } from 'kerfjs';
18
- import { Columns3, FileText, Inbox, List } from 'lucide';
20
+ import { Columns3, FileText, Inbox, List as ListIcon } from 'lucide';
19
21
 
20
- import type { RecipeFactory } from './types.js';
22
+ import type { RecipeFactory, RecipePresentation } from './types.js';
23
+
24
+ export const presentation: RecipePresentation = {
25
+ viewport: {
26
+ width: 'medium',
27
+ frame: 'solid',
28
+ surface: 'default',
29
+ overflow: 'hidden',
30
+ shadow: true,
31
+ },
32
+ note: "Each value-bearing component's placeholder prop renders skeletons in its value slots while loading, so the recipe composes a faithful loading inspector from real chrome. The app owns the loading lifecycle and which values are still unknown.",
33
+ };
21
34
 
22
35
  const icon = (node: Parameters<typeof LucideIcon>[0]['icon'], name: string) => (
23
36
  <LucideIcon icon={node} name={name} />
@@ -35,144 +48,148 @@ export const createRecipe: RecipeFactory = (announce) => {
35
48
  const render = () => {
36
49
  const p = loading.value;
37
50
  return (
38
- <section
39
- class="kui-recipe recipe-inspector kui-recipe__surface kui-pane"
40
- data-recipe="recipe-loading-inspector"
41
- data-inspector-loading={String(p)}
51
+ <Pane
52
+ element="section"
53
+ label="Ticket inspector"
54
+ rootAttributes={{
55
+ 'data-recipe': 'recipe-loading-inspector',
56
+ 'data-inspector-loading': String(p),
57
+ }}
58
+ header={
59
+ <>
60
+ <Toolbar
61
+ label="Ticket inspector"
62
+ dividerSides=""
63
+ responsive="wrap"
64
+ leading={
65
+ <>
66
+ <ToolbarControlGroup appearance="borderless" single>
67
+ {icon(FileText, 'file-text')}
68
+ </ToolbarControlGroup>
69
+ <ToolbarText
70
+ text="Ticket · KF-2048"
71
+ size="xlarge"
72
+ id="recipe-inspector-title"
73
+ placeholder={p}
74
+ />
75
+ </>
76
+ }
77
+ trailing={
78
+ <ToolbarControlGroup
79
+ appearance="borderless"
80
+ content="text"
81
+ single
82
+ >
83
+ <button
84
+ type="button"
85
+ data-action="recipe-action"
86
+ data-recipe-command="toggle"
87
+ >
88
+ {p ? 'Show loaded' : 'Show loading'}
89
+ </button>
90
+ </ToolbarControlGroup>
91
+ }
92
+ />
93
+ <ListInsetText sides="rl">
94
+ <Text variant="span" tone="quiet" id="recipe-inspector-summary">
95
+ {p ? (
96
+ <Skeleton width={em(18)} />
97
+ ) : (
98
+ 'Restore keyboard focus after a dialog closes'
99
+ )}
100
+ </Text>
101
+ </ListInsetText>
102
+ </>
103
+ }
42
104
  >
43
- <Toolbar
44
- label="Ticket inspector"
45
- dividerSides=""
46
- leading={
47
- <>
48
- <ToolbarControlGroup appearance="borderless" single>
49
- {icon(FileText, 'file-text')}
50
- </ToolbarControlGroup>
51
- <ToolbarText
52
- text="Ticket · KF-2048"
53
- size="xlarge"
54
- id="recipe-inspector-title"
55
- placeholder={p}
56
- />
57
- </>
58
- }
59
- trailing={
60
- <ToolbarControlGroup appearance="borderless" single>
61
- <button
62
- class="kui-recipe__button"
63
- data-primary="true"
64
- type="button"
65
- data-action="recipe-action"
66
- data-recipe-command="toggle"
67
- >
68
- {p ? 'Show loaded' : 'Show loading'}
69
- </button>
70
- </ToolbarControlGroup>
71
- }
72
- />
73
- <Text class="kui-recipe__heading-summary" id="recipe-inspector-summary">
74
- {p ? (
75
- <Skeleton width={em(18)} />
76
- ) : (
77
- 'Restore keyboard focus after a dialog closes'
78
- )}
79
- </Text>
80
- <div class="recipe-inspector__body kui-pane__content kui-content">
81
- <section>
82
- <ValueTable label="Ticket details">
83
- <ValueTableRow
84
- label="Status"
85
- value="In review"
86
- icon={icon(Inbox, 'inbox')}
87
- placeholder={p}
88
- />
89
- <ValueTableRow label="Owner" value="Mara Lopez" placeholder={p} />
90
- <ValueTableRow label="Priority" value="High" placeholder={p} />
91
- <ValueTableRow
92
- label="Updated"
93
- value="2 hours ago"
94
- placeholder={p}
95
- />
96
- </ValueTable>
97
- </section>
98
- <div class="recipe-inspector__controls">
99
- <Select
100
- name="recipe-inspector-status"
101
- value="review"
105
+ <section>
106
+ <ValueTable label="Ticket details">
107
+ <ValueTableRow
102
108
  label="Status"
103
- placeholder={p}
104
- choices={[
105
- { value: 'review', label: 'In review' },
106
- { value: 'ready', label: 'Ready' },
107
- { value: 'done', label: 'Done' },
108
- ]}
109
- />
110
- <SegmentedControl
111
- id="recipe-inspector-view"
112
- label="Inspector view"
113
- value="details"
114
- appearance="toolbar"
115
- shape="pill"
116
- size="small"
117
- placeholder={p}
118
- choices={[
119
- {
120
- value: 'details',
121
- label: 'Details',
122
- content: icon(List, 'list'),
123
- },
124
- {
125
- value: 'activity',
126
- label: 'Activity',
127
- content: icon(Columns3, 'columns-3'),
128
- },
129
- {
130
- value: 'files',
131
- label: 'Files',
132
- content: icon(FileText, 'file-text'),
133
- },
134
- ]}
135
- />
136
- </div>
137
- <section>
138
- <ListItem
139
- action="recipe-action"
140
- itemId="reassign"
141
- label="Reassign ticket"
109
+ value="In review"
142
110
  icon={icon(Inbox, 'inbox')}
143
111
  placeholder={p}
144
112
  />
145
- <ListItem
146
- action="recipe-action"
147
- itemId="watch"
148
- label="Watch for changes"
113
+ <ValueTableRow label="Owner" value="Mara Lopez" placeholder={p} />
114
+ <ValueTableRow label="Priority" value="High" placeholder={p} />
115
+ <ValueTableRow
116
+ label="Updated"
117
+ value="2 hours ago"
149
118
  placeholder={p}
150
119
  />
151
- </section>
152
- {p ? (
153
- <StateBanner
154
- tone="info"
155
- title=""
156
- detail=""
157
- icon={icon(FileText, 'file-text')}
158
- placeholder
159
- />
160
- ) : (
161
- <StateBanner
162
- tone="success"
163
- title="Up to date"
164
- detail="All checks passed on the latest revision."
165
- icon={icon(FileText, 'file-text')}
166
- />
167
- )}
168
- <Text class="kui-recipe__ownership kui-content-item">
169
- Each value-bearing component's <code>placeholder</code> prop renders
170
- skeletons in its value slots while loading, so the recipe composes a
171
- faithful loading inspector from real chrome. The app owns the
172
- loading lifecycle and which values are still unknown.
173
- </Text>
174
- </div>
175
- </section>
120
+ </ValueTable>
121
+ </section>
122
+ <List gap="xs" controlInsets="rl">
123
+ <Select
124
+ name="recipe-inspector-status"
125
+ value="review"
126
+ label="Status"
127
+ placeholder={p}
128
+ choices={[
129
+ { value: 'review', label: 'In review' },
130
+ { value: 'ready', label: 'Ready' },
131
+ { value: 'done', label: 'Done' },
132
+ ]}
133
+ />
134
+ <SegmentedControl
135
+ id="recipe-inspector-view"
136
+ label="Inspector view"
137
+ value="details"
138
+ appearance="toolbar"
139
+ shape="pill"
140
+ size="small"
141
+ placeholder={p}
142
+ choices={[
143
+ {
144
+ value: 'details',
145
+ label: 'Details',
146
+ content: icon(ListIcon, 'list'),
147
+ },
148
+ {
149
+ value: 'activity',
150
+ label: 'Activity',
151
+ content: icon(Columns3, 'columns-3'),
152
+ },
153
+ {
154
+ value: 'files',
155
+ label: 'Files',
156
+ content: icon(FileText, 'file-text'),
157
+ },
158
+ ]}
159
+ />
160
+ </List>
161
+ <section>
162
+ <ListItem
163
+ action="recipe-action"
164
+ itemId="reassign"
165
+ label="Reassign ticket"
166
+ icon={icon(Inbox, 'inbox')}
167
+ placeholder={p}
168
+ />
169
+ <ListItem
170
+ action="recipe-action"
171
+ itemId="watch"
172
+ label="Watch for changes"
173
+ placeholder={p}
174
+ />
175
+ </section>
176
+ {p ? (
177
+ <StateBanner
178
+ tone="info"
179
+ title=""
180
+ detail=""
181
+ icon={icon(FileText, 'file-text')}
182
+ placeholder
183
+ />
184
+ ) : (
185
+ <StateBanner
186
+ tone="success"
187
+ title="Up to date"
188
+ detail="All checks passed on the latest revision."
189
+ icon={icon(FileText, 'file-text')}
190
+ />
191
+ )}
192
+ </Pane>
176
193
  );
177
194
  };
178
195
  return {