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

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 (257) hide show
  1. package/README.md +41 -11
  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 +14 -0
  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.json +79 -23
  8. package/ai/component-catalog.json +86 -27
  9. package/ai/public-api-signatures-v1.md +217 -169
  10. package/ai/skill.md +23 -9
  11. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  12. package/dist/app-tab.d.ts +3 -1
  13. package/dist/app-tab.js +1 -1
  14. package/dist/badge.d.ts +24 -0
  15. package/dist/badge.js +3 -0
  16. package/dist/badge.js.map +1 -0
  17. package/dist/browser/badge.js +3 -0
  18. package/dist/browser/list-header.js +1 -0
  19. package/dist/browser/state-banner.js +1 -0
  20. package/dist/catalog-resources.d.ts +2 -2
  21. package/dist/catalog.d.ts +24 -125
  22. package/dist/catalog.js +387 -261
  23. package/dist/catalog.js.map +1 -1
  24. package/dist/{chunk-OGTJNHRG.js → chunk-2WMSE4MK.js} +5 -3
  25. package/dist/chunk-2WMSE4MK.js.map +1 -0
  26. package/dist/{chunk-GYGM363P.js → chunk-2YOUUEWR.js} +16 -6
  27. package/dist/chunk-2YOUUEWR.js.map +1 -0
  28. package/dist/{chunk-UDHHKZWO.js → chunk-3V75EQIP.js} +8 -4
  29. package/dist/chunk-3V75EQIP.js.map +1 -0
  30. package/dist/{chunk-W2FK7ZNY.js → chunk-4R777DUZ.js} +10 -2
  31. package/dist/chunk-4R777DUZ.js.map +1 -0
  32. package/dist/{chunk-T7DOWS6T.js → chunk-54HM36IQ.js} +6 -3
  33. package/dist/chunk-54HM36IQ.js.map +1 -0
  34. package/dist/{chunk-DAO2VFTT.js → chunk-5CE64WGC.js} +6 -4
  35. package/dist/chunk-5CE64WGC.js.map +1 -0
  36. package/dist/{chunk-SOK5EUF7.js → chunk-6ZXOQEAN.js} +4 -2
  37. package/dist/chunk-6ZXOQEAN.js.map +1 -0
  38. package/dist/{chunk-OGNE3OFT.js → chunk-AQSKJ6U6.js} +4 -2
  39. package/dist/chunk-AQSKJ6U6.js.map +1 -0
  40. package/dist/{chunk-VDUJZF5G.js → chunk-CMUIXJZM.js} +2 -2
  41. package/dist/{chunk-VDUJZF5G.js.map → chunk-CMUIXJZM.js.map} +1 -1
  42. package/dist/{chunk-OMSRSL3B.js → chunk-COUPLRZG.js} +5 -3
  43. package/dist/chunk-COUPLRZG.js.map +1 -0
  44. package/dist/{chunk-2TYUFZUC.js → chunk-D7GWXIAS.js} +4 -2
  45. package/dist/chunk-D7GWXIAS.js.map +1 -0
  46. package/dist/{chunk-AQFWBG23.js → chunk-DARTMI5Z.js} +5 -3
  47. package/dist/chunk-DARTMI5Z.js.map +1 -0
  48. package/dist/{chunk-V6GQKOX2.js → chunk-DJKWFYAA.js} +5 -3
  49. package/dist/chunk-DJKWFYAA.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-IU4QUY5I.js → chunk-ELRMBQEC.js} +4 -2
  53. package/dist/chunk-ELRMBQEC.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-WN52USHV.js → chunk-J3EE6XWD.js} +2 -2
  59. package/dist/{chunk-WN52USHV.js.map → chunk-J3EE6XWD.js.map} +1 -1
  60. package/dist/{chunk-CK6P5AUK.js → chunk-KKNK3JUT.js} +7 -4
  61. package/dist/chunk-KKNK3JUT.js.map +1 -0
  62. package/dist/{chunk-ZPWZIVI6.js → chunk-N3GKMPDW.js} +7 -3
  63. package/dist/chunk-N3GKMPDW.js.map +1 -0
  64. package/dist/{chunk-DYBPI5O2.js → chunk-NDUGJ4TU.js} +4 -2
  65. package/dist/chunk-NDUGJ4TU.js.map +1 -0
  66. package/dist/{chunk-WSXUPSID.js → chunk-NN6GYOA2.js} +7 -3
  67. package/dist/chunk-NN6GYOA2.js.map +1 -0
  68. package/dist/{chunk-VXFGMDA7.js → chunk-OQI7RCRP.js} +10 -2
  69. package/dist/chunk-OQI7RCRP.js.map +1 -0
  70. package/dist/{chunk-E34TE2ZI.js → chunk-S6ZTTTV7.js} +5 -3
  71. package/dist/chunk-S6ZTTTV7.js.map +1 -0
  72. package/dist/{chunk-V6HCTCVD.js → chunk-SIU2AC5W.js} +8 -4
  73. package/dist/chunk-SIU2AC5W.js.map +1 -0
  74. package/dist/{chunk-WVLMZ5SG.js → chunk-UMGY5JSP.js} +4 -2
  75. package/dist/chunk-UMGY5JSP.js.map +1 -0
  76. package/dist/{chunk-I4V3UDSA.js → chunk-V6RZWDII.js} +7 -5
  77. package/dist/chunk-V6RZWDII.js.map +1 -0
  78. package/dist/{chunk-CAB6NQ2T.js → chunk-VOCPXGQN.js} +3 -1
  79. package/dist/chunk-VOCPXGQN.js.map +1 -0
  80. package/dist/chunk-XD7DWYXG.js +34 -0
  81. package/dist/chunk-XD7DWYXG.js.map +1 -0
  82. package/dist/{chunk-B6JYRX3P.js → chunk-ZIYOJFZD.js} +43 -4
  83. package/dist/chunk-ZIYOJFZD.js.map +1 -0
  84. package/dist/{chunk-EYALJQQD.js → chunk-ZK5EGVFP.js} +4 -2
  85. package/dist/chunk-ZK5EGVFP.js.map +1 -0
  86. package/dist/{chunk-6WTETUZ6.js → chunk-ZLWQZUGF.js} +8 -2
  87. package/dist/chunk-ZLWQZUGF.js.map +1 -0
  88. package/dist/{chunk-XKFRMGMW.js → chunk-ZNZ2JDBW.js} +3 -1
  89. package/dist/chunk-ZNZ2JDBW.js.map +1 -0
  90. package/dist/{chunk-I45QO2IZ.js → chunk-ZSYLBVWG.js} +6 -4
  91. package/dist/chunk-ZSYLBVWG.js.map +1 -0
  92. package/dist/collapsible-panel.d.ts +3 -1
  93. package/dist/collapsible-panel.js +4 -2
  94. package/dist/collapsible-panel.js.map +1 -1
  95. package/dist/disclosure-arrow.d.ts +3 -1
  96. package/dist/disclosure-arrow.js +1 -1
  97. package/dist/empty-state.d.ts +3 -1
  98. package/dist/empty-state.js +1 -1
  99. package/dist/floating-toolbar.d.ts +3 -1
  100. package/dist/floating-toolbar.js +1 -1
  101. package/dist/grid.d.ts +3 -1
  102. package/dist/grid.js +1 -1
  103. package/dist/index.d.ts +3 -2
  104. package/dist/index.js +33 -32
  105. package/dist/list-action-row.d.ts +3 -1
  106. package/dist/list-action-row.js +1 -1
  107. package/dist/list-header.d.ts +6 -1
  108. package/dist/list-header.js +2 -1
  109. package/dist/list-inset-control.d.ts +3 -1
  110. package/dist/list-inset-control.js +1 -1
  111. package/dist/list-inset-text.d.ts +3 -1
  112. package/dist/list-inset-text.js +1 -1
  113. package/dist/list-item.d.ts +3 -1
  114. package/dist/list-item.js +1 -1
  115. package/dist/list.d.ts +3 -1
  116. package/dist/list.js +1 -1
  117. package/dist/loading-spinner.d.ts +3 -1
  118. package/dist/loading-spinner.js +1 -1
  119. package/dist/lucide-icon.d.ts +3 -1
  120. package/dist/lucide-icon.js +1 -1
  121. package/dist/nav-stack.d.ts +3 -1
  122. package/dist/nav-stack.js +1 -1
  123. package/dist/pane.d.ts +3 -1
  124. package/dist/pane.js +1 -1
  125. package/dist/resizable-region.d.ts +5 -2
  126. package/dist/resizable-region.js +1 -1
  127. package/dist/row.d.ts +3 -1
  128. package/dist/row.js +1 -1
  129. package/dist/segmented-control.d.ts +3 -1
  130. package/dist/segmented-control.js +1 -1
  131. package/dist/select.d.ts +3 -1
  132. package/dist/select.js +1 -1
  133. package/dist/skeleton.d.ts +3 -1
  134. package/dist/skeleton.js +1 -1
  135. package/dist/spacer.d.ts +3 -1
  136. package/dist/spacer.js +1 -1
  137. package/dist/split-view.d.ts +3 -1
  138. package/dist/split-view.js +24 -5
  139. package/dist/split-view.js.map +1 -1
  140. package/dist/state-banner.d.ts +3 -1
  141. package/dist/state-banner.js +2 -1
  142. package/dist/styles/badge.css +86 -0
  143. package/dist/styles/catalog/components/catalog-detail.css +35 -0
  144. package/dist/styles/catalog/components/catalog-example-stack.css +6 -0
  145. package/dist/styles/catalog/components/catalog-example.css +35 -0
  146. package/dist/styles/catalog/components/catalog-resource-footer.css +37 -0
  147. package/dist/styles/catalog/components/catalog-secondary-sections.css +38 -0
  148. package/dist/styles/catalog/components/catalog-section-list.css +22 -0
  149. package/dist/styles/catalog/components/catalog-sidebar.css +82 -0
  150. package/dist/styles/catalog/components/catalog-stage.css +60 -0
  151. package/dist/styles/catalog/components/catalog.css +22 -0
  152. package/dist/styles/catalog.css +10 -587
  153. package/dist/styles/list-header.css +4 -60
  154. package/dist/styles/resizable-region.css +24 -0
  155. package/dist/styles/select.css +0 -3
  156. package/dist/styles/split-view.css +1 -1
  157. package/dist/styles/state-banner.css +0 -27
  158. package/dist/styles/styles.css +1 -0
  159. package/dist/styles/tab-bar.css +6 -1
  160. package/dist/styles/text.css +4 -0
  161. package/dist/styles/token-search-field.css +5 -40
  162. package/dist/styles/toolbar-control-group.css +110 -16
  163. package/dist/styles/toolbar-text.css +4 -0
  164. package/dist/styles/toolbar.css +72 -0
  165. package/dist/styles/webawesome.css +22 -7
  166. package/dist/sunken-panel.d.ts +3 -1
  167. package/dist/sunken-panel.js +1 -1
  168. package/dist/surface-scaffold.d.ts +6 -2
  169. package/dist/surface-scaffold.js +1 -1
  170. package/dist/tab-bar.d.ts +8 -1
  171. package/dist/tab-bar.js +1 -1
  172. package/dist/tab-scaffold.d.ts +3 -1
  173. package/dist/tab-scaffold.js +3 -1
  174. package/dist/tab-scaffold.js.map +1 -1
  175. package/dist/text.d.ts +5 -2
  176. package/dist/text.js +1 -1
  177. package/dist/token-search-field.d.ts +5 -1
  178. package/dist/token-search-field.js +1 -1
  179. package/dist/toolbar-control-group.d.ts +33 -3
  180. package/dist/toolbar-control-group.js +1 -1
  181. package/dist/toolbar-text.d.ts +3 -1
  182. package/dist/toolbar-text.js +1 -1
  183. package/dist/toolbar.d.ts +9 -1
  184. package/dist/toolbar.js +1 -1
  185. package/dist/types-CzgSrFXP.d.ts +64 -0
  186. package/dist/value-table.d.ts +6 -2
  187. package/dist/value-table.js +1 -1
  188. package/dist/wire-resizable-regions.js +1 -1
  189. package/dist/wire-token-search-fields.js +1 -1
  190. package/dist/workbench.d.ts +3 -1
  191. package/dist/workbench.js +3 -1
  192. package/dist/workbench.js.map +1 -1
  193. package/docs/accessibility.md +11 -1
  194. package/docs/catalog.md +25 -7
  195. package/docs/component-contract.md +71 -22
  196. package/docs/component-selection.md +11 -9
  197. package/docs/design-philosophy.md +6 -5
  198. package/docs/recipes.md +5 -5
  199. package/docs/type-contracts.md +1 -0
  200. package/docs/ux-demo.md +4 -4
  201. package/docs/webawesome-theme.md +5 -4
  202. package/llms.txt +30 -10
  203. package/package.json +9 -2
  204. package/ux-demo/recipes/app-shell.css +87 -0
  205. package/ux-demo/recipes/app-shell.tsx +207 -178
  206. package/ux-demo/recipes/collapsible-sidebar.css +83 -0
  207. package/ux-demo/recipes/collapsible-sidebar.tsx +152 -122
  208. package/ux-demo/recipes/compact-toolbar.css +35 -0
  209. package/ux-demo/recipes/compact-toolbar.tsx +104 -100
  210. package/ux-demo/recipes/composer-form.css +19 -0
  211. package/ux-demo/recipes/composer-form.tsx +19 -15
  212. package/ux-demo/recipes/list-detail-dialog.css +42 -0
  213. package/ux-demo/recipes/list-detail-dialog.tsx +127 -125
  214. package/ux-demo/recipes/list-workspace-states.css +30 -0
  215. package/ux-demo/recipes/list-workspace-states.tsx +66 -60
  216. package/ux-demo/recipes/loading-inspector.css +7 -0
  217. package/ux-demo/recipes/loading-inspector.tsx +151 -131
  218. package/ux-demo/recipes/navigation-sidebar.css +12 -0
  219. package/ux-demo/recipes/navigation-sidebar.tsx +116 -105
  220. package/ux-demo/recipes/navigation-stack.css +12 -0
  221. package/ux-demo/recipes/navigation-stack.tsx +47 -37
  222. package/ux-demo/recipes/recipe-root.css +67 -0
  223. package/ux-demo/recipes/recipe-root.tsx +87 -0
  224. package/ux-demo/recipes/workspace-header.css +7 -0
  225. package/ux-demo/recipes/workspace-header.tsx +60 -61
  226. package/dist/chunk-2TYUFZUC.js.map +0 -1
  227. package/dist/chunk-6NDBE2OK.js.map +0 -1
  228. package/dist/chunk-6WTETUZ6.js.map +0 -1
  229. package/dist/chunk-AQFWBG23.js.map +0 -1
  230. package/dist/chunk-B6JYRX3P.js.map +0 -1
  231. package/dist/chunk-CAB6NQ2T.js.map +0 -1
  232. package/dist/chunk-CK6P5AUK.js.map +0 -1
  233. package/dist/chunk-DAO2VFTT.js.map +0 -1
  234. package/dist/chunk-DYBPI5O2.js.map +0 -1
  235. package/dist/chunk-E34TE2ZI.js.map +0 -1
  236. package/dist/chunk-EYALJQQD.js.map +0 -1
  237. package/dist/chunk-GYGM363P.js.map +0 -1
  238. package/dist/chunk-I45QO2IZ.js.map +0 -1
  239. package/dist/chunk-I4V3UDSA.js.map +0 -1
  240. package/dist/chunk-IU4QUY5I.js.map +0 -1
  241. package/dist/chunk-OGNE3OFT.js.map +0 -1
  242. package/dist/chunk-OGTJNHRG.js.map +0 -1
  243. package/dist/chunk-OMSRSL3B.js.map +0 -1
  244. package/dist/chunk-SOK5EUF7.js.map +0 -1
  245. package/dist/chunk-T7DOWS6T.js.map +0 -1
  246. package/dist/chunk-TIGSG6BX.js.map +0 -1
  247. package/dist/chunk-UDHHKZWO.js.map +0 -1
  248. package/dist/chunk-V6GQKOX2.js.map +0 -1
  249. package/dist/chunk-V6HCTCVD.js.map +0 -1
  250. package/dist/chunk-VXFGMDA7.js.map +0 -1
  251. package/dist/chunk-W2FK7ZNY.js.map +0 -1
  252. package/dist/chunk-WSXUPSID.js.map +0 -1
  253. package/dist/chunk-WVLMZ5SG.js.map +0 -1
  254. package/dist/chunk-XKFRMGMW.js.map +0 -1
  255. package/dist/chunk-Y6LYKFXY.js.map +0 -1
  256. package/dist/chunk-ZPWZIVI6.js.map +0 -1
  257. package/ux-demo/recipes/recipes.css +0 -453
@@ -0,0 +1,42 @@
1
+ .recipe-list-detail {
2
+ display: grid;
3
+ width: 100%;
4
+ min-height: 25rem;
5
+ grid-template-columns: minmax(13rem, 0.8fr) minmax(18rem, 1.4fr);
6
+ }
7
+
8
+ .recipe-list-detail__list {
9
+ display: grid;
10
+ min-height: 0;
11
+ border-inline-end: 1px solid var(--kui-color-border);
12
+ }
13
+
14
+ .recipe-list-detail__detail {
15
+ display: grid;
16
+ min-width: 0;
17
+ min-height: 0;
18
+ }
19
+
20
+ .recipe-list-detail__body {
21
+ padding-block: var(--kui-layout-item-gap);
22
+ }
23
+
24
+ .recipe-list-detail__title {
25
+ margin: 0 var(--kui-layout-inline-margin, remify(8px));
26
+ font-size: var(--kui-font-s);
27
+ }
28
+
29
+ .recipe-list-detail__actions {
30
+ margin-inline: var(--kui-layout-inline-margin, remify(8px));
31
+ }
32
+
33
+ @container (max-width: 44rem) {
34
+ .recipe-list-detail {
35
+ grid-template-columns: 1fr;
36
+ }
37
+
38
+ .recipe-list-detail__list {
39
+ border-inline-end: 0;
40
+ border-block-end: 1px solid var(--kui-color-border);
41
+ }
42
+ }
@@ -2,12 +2,12 @@ import '@kerfjs/ui/layout.css';
2
2
  import '@kerfjs/ui/webawesome.css';
3
3
  import '@awesome.me/webawesome/dist/components/button/button.js';
4
4
  import '@awesome.me/webawesome/dist/components/dialog/dialog.js';
5
- import './recipes.css';
5
+ import './list-detail-dialog.css';
6
6
 
7
7
  import { ListHeader } from '@kerfjs/ui/list-header';
8
8
  import { ListItem } from '@kerfjs/ui/list-item';
9
9
  import { LucideIcon } from '@kerfjs/ui/lucide-icon';
10
- import { Text } from '@kerfjs/ui/text';
10
+ import { Pane } from '@kerfjs/ui/pane';
11
11
  import { Toolbar } from '@kerfjs/ui/toolbar';
12
12
  import { ToolbarControlGroup } from '@kerfjs/ui/toolbar-control-group';
13
13
  import { ToolbarText } from '@kerfjs/ui/toolbar-text';
@@ -15,6 +15,11 @@ import { ValueTable, ValueTableRow } from '@kerfjs/ui/value-table';
15
15
  import { signal } from 'kerfjs';
16
16
  import { FileText } from 'lucide';
17
17
 
18
+ import {
19
+ RecipeHeadingSummary,
20
+ RecipeOwnershipNote,
21
+ RecipeRoot,
22
+ } from './recipe-root.js';
18
23
  import type { RecipeFactory } from './types.js';
19
24
 
20
25
  const records = {
@@ -46,132 +51,129 @@ export const createRecipe: RecipeFactory = (announce) => {
46
51
  const selected = signal<keyof typeof records>('alpha');
47
52
  const open = { value: false };
48
53
  const render = () => (
49
- <section
50
- class="kui-recipe kui-content"
51
- data-recipe="recipe-list-detail-dialog"
52
- >
53
- <button
54
- class="kui-recipe__button kui-content-item"
55
- data-primary="true"
56
- type="button"
57
- data-action="recipe-action"
58
- data-recipe-command="open"
59
- >
60
- Open project details
61
- </button>
62
- <Text class="kui-recipe__ownership kui-content-item">
63
- Web Awesome owns modal focus and dismissal. The recipe owns
64
- header/body/list-detail anatomy; the app owns open state, selection, and
65
- policy.
66
- </Text>
67
- <wa-dialog
68
- class="recipe-dialog"
69
- label="Project details"
70
- without-header
71
- open={open.value}
72
- >
73
- <div class="recipe-dialog__pane kui-pane">
74
- <div class="recipe-list-detail kui-pane__content">
75
- <nav
76
- class="recipe-list-detail__list kui-pane"
77
- aria-label="Projects"
78
- >
79
- <ListHeader label="Recent projects" />
80
- <div class="kui-pane__content kui-content">
81
- <section>
82
- {Object.entries(records).map(([id, record]) => (
83
- <ListItem
84
- action="recipe-action"
85
- itemId={id}
86
- label={record.name}
87
- selected={selected.value === id}
88
- multiline
89
- />
90
- ))}
91
- </section>
54
+ <RecipeRoot recipe="recipe-list-detail-dialog" surface={false}>
55
+ <div class="recipe-list-detail-dialog kui-content">
56
+ <wa-button
57
+ variant="brand"
58
+ appearance="accent"
59
+ data-action="recipe-action"
60
+ data-recipe-command="open"
61
+ >
62
+ Open project details
63
+ </wa-button>
64
+ <RecipeOwnershipNote>
65
+ Web Awesome owns modal focus and dismissal. The recipe owns
66
+ header/body/list-detail anatomy; the app owns open state, selection,
67
+ and policy.
68
+ </RecipeOwnershipNote>
69
+ <wa-dialog
70
+ class="recipe-dialog"
71
+ label="Project details"
72
+ without-header
73
+ open={open.value}
74
+ style="--spacing:0;--width:min(62rem, calc(100vw - 2rem))"
75
+ >
76
+ <Pane>
77
+ <div class="recipe-list-detail">
78
+ <div class="recipe-list-detail__list">
79
+ <Pane contentElement="nav" contentLabel="Projects">
80
+ <ListHeader label="Recent projects" />
81
+ <section>
82
+ {Object.entries(records).map(([id, record]) => (
83
+ <ListItem
84
+ action="recipe-action"
85
+ itemId={id}
86
+ label={record.name}
87
+ selected={selected.value === id}
88
+ multiline
89
+ />
90
+ ))}
91
+ </section>
92
+ </Pane>
92
93
  </div>
93
- </nav>
94
- <section class="recipe-list-detail__detail kui-pane">
95
- <Toolbar
96
- label="Project details"
97
- dividerSides=""
98
- leading={
99
- <>
100
- <ToolbarControlGroup appearance="borderless" single>
101
- <LucideIcon icon={FileText} name="file-text" />
102
- </ToolbarControlGroup>
103
- <ToolbarText
104
- text="Project details"
105
- size="xlarge"
106
- id="recipe-dialog-title"
107
- />
108
- </>
109
- }
110
- trailing={
111
- <ToolbarControlGroup appearance="borderless" single>
112
- <wa-button
113
- appearance="plain"
114
- data-action="recipe-action"
115
- data-recipe-command="close"
116
- >
117
- Close
118
- </wa-button>
119
- </ToolbarControlGroup>
120
- }
121
- />
122
- <Text
123
- class="kui-recipe__heading-summary"
124
- id="recipe-dialog-summary"
125
- >
126
- Compare delivery state without leaving the workspace.
127
- </Text>
128
- <div
129
- class="recipe-list-detail__body kui-pane__content kui-content"
130
- aria-live="polite"
131
- >
132
- <Text
133
- variant="h3"
134
- class="recipe-list-detail__title kui-recipe__pane-title kui-content-item"
94
+ <div class="recipe-list-detail__detail">
95
+ <Pane
96
+ element="section"
97
+ header={
98
+ <>
99
+ <Toolbar
100
+ label="Project details"
101
+ dividerSides=""
102
+ leading={
103
+ <>
104
+ <ToolbarControlGroup appearance="borderless" single>
105
+ <LucideIcon icon={FileText} name="file-text" />
106
+ </ToolbarControlGroup>
107
+ <ToolbarText
108
+ text="Project details"
109
+ size="xlarge"
110
+ id="recipe-dialog-title"
111
+ />
112
+ </>
113
+ }
114
+ trailing={
115
+ <ToolbarControlGroup appearance="borderless" single>
116
+ <wa-button
117
+ appearance="plain"
118
+ data-action="recipe-action"
119
+ data-recipe-command="close"
120
+ >
121
+ Close
122
+ </wa-button>
123
+ </ToolbarControlGroup>
124
+ }
125
+ />
126
+ <RecipeHeadingSummary id="recipe-dialog-summary">
127
+ Compare delivery state without leaving the workspace.
128
+ </RecipeHeadingSummary>
129
+ </>
130
+ }
135
131
  >
136
- {records[selected.value].name}
137
- </Text>
138
- <ValueTable label="Project details">
139
- <ValueTableRow
140
- label="Owner"
141
- value={records[selected.value].owner}
142
- />
143
- <ValueTableRow
144
- label="Status"
145
- value={records[selected.value].state}
146
- />
147
- <ValueTableRow
148
- label="Updated"
149
- value={records[selected.value].updated}
150
- />
151
- </ValueTable>
152
- <div class="recipe-list-detail__actions kui-control-cluster">
153
- <wa-button
154
- appearance="outlined"
155
- data-action="recipe-action"
156
- data-recipe-command="archive"
157
- >
158
- Archive
159
- </wa-button>
160
- <wa-button
161
- variant="brand"
162
- appearance="accent"
163
- data-action="recipe-action"
164
- data-recipe-command="open-record"
165
- >
166
- Open project
167
- </wa-button>
168
- </div>
132
+ <div class="recipe-list-detail__body">
133
+ <div aria-live="polite">
134
+ <h3 class="recipe-list-detail__title kui-content-item">
135
+ {records[selected.value].name}
136
+ </h3>
137
+ <ValueTable label="Project details">
138
+ <ValueTableRow
139
+ label="Owner"
140
+ value={records[selected.value].owner}
141
+ />
142
+ <ValueTableRow
143
+ label="Status"
144
+ value={records[selected.value].state}
145
+ />
146
+ <ValueTableRow
147
+ label="Updated"
148
+ value={records[selected.value].updated}
149
+ />
150
+ </ValueTable>
151
+ <div class="recipe-list-detail__actions kui-control-cluster">
152
+ <wa-button
153
+ appearance="outlined"
154
+ data-action="recipe-action"
155
+ data-recipe-command="archive"
156
+ >
157
+ Archive
158
+ </wa-button>
159
+ <wa-button
160
+ variant="brand"
161
+ appearance="accent"
162
+ data-action="recipe-action"
163
+ data-recipe-command="open-record"
164
+ >
165
+ Open project
166
+ </wa-button>
167
+ </div>
168
+ </div>
169
+ </div>
170
+ </Pane>
169
171
  </div>
170
- </section>
171
- </div>
172
- </div>
173
- </wa-dialog>
174
- </section>
172
+ </div>
173
+ </Pane>
174
+ </wa-dialog>
175
+ </div>
176
+ </RecipeRoot>
175
177
  );
176
178
  return {
177
179
  render,
@@ -0,0 +1,30 @@
1
+ .recipe-list {
2
+ display: grid;
3
+ min-height: 27rem;
4
+ }
5
+
6
+ .recipe-list__body {
7
+ min-height: 0;
8
+ }
9
+
10
+ .recipe-list__items {
11
+ display: grid;
12
+ margin: 0 var(--kui-layout-inline-margin);
13
+ padding: var(--kui-layout-item-padding);
14
+ border: var(--kui-layout-item-border-width) solid
15
+ var(--kui-color-border-quiet);
16
+ border-radius: var(--kui-layout-rounded-radius);
17
+ background: var(--kui-color-surface);
18
+ list-style: none;
19
+ }
20
+
21
+ .recipe-list__items li {
22
+ display: grid;
23
+ padding: var(--kui-layout-item-padding);
24
+ border-block-end: 1px solid var(--kui-color-border-quiet);
25
+ gap: var(--kui-layout-metadata-gap);
26
+ }
27
+
28
+ .recipe-list__items li:last-child {
29
+ border-block-end: 0;
30
+ }
@@ -1,15 +1,20 @@
1
1
  import '@kerfjs/ui/layout.css';
2
- import './recipes.css';
2
+ import './list-workspace-states.css';
3
3
 
4
4
  import { EmptyState } from '@kerfjs/ui/empty-state';
5
5
  import { LoadingSpinner } from '@kerfjs/ui/loading-spinner';
6
+ import { Pane } from '@kerfjs/ui/pane';
6
7
  import { StateBanner } from '@kerfjs/ui/state-banner';
7
- import { Text } from '@kerfjs/ui/text';
8
8
  import { Toolbar } from '@kerfjs/ui/toolbar';
9
9
  import { ToolbarControlGroup } from '@kerfjs/ui/toolbar-control-group';
10
10
  import { ToolbarText } from '@kerfjs/ui/toolbar-text';
11
11
  import { signal } from 'kerfjs';
12
12
 
13
+ import {
14
+ RecipeMutedText,
15
+ RecipeOwnershipNote,
16
+ RecipeRoot,
17
+ } from './recipe-root.js';
13
18
  import type { RecipeFactory } from './types.js';
14
19
 
15
20
  type ListState = 'loading' | 'empty' | 'populated' | 'stale' | 'error';
@@ -26,13 +31,13 @@ export const createRecipe: RecipeFactory = (announce) => {
26
31
  {items.map((item, index) => (
27
32
  <li>
28
33
  <strong>{item}</strong>
29
- <span class="kui-recipe__muted">
34
+ <RecipeMutedText>
30
35
  {index === 0
31
36
  ? 'In review · Mara'
32
37
  : index === 1
33
38
  ? 'Ready · Sam'
34
39
  : 'Draft · Inez'}
35
- </span>
40
+ </RecipeMutedText>
36
41
  </li>
37
42
  ))}
38
43
  </ul>
@@ -46,7 +51,6 @@ export const createRecipe: RecipeFactory = (announce) => {
46
51
  busy
47
52
  action={
48
53
  <button
49
- class="kui-recipe__button"
50
54
  type="button"
51
55
  data-action="recipe-action"
52
56
  data-recipe-command="load"
@@ -63,8 +67,6 @@ export const createRecipe: RecipeFactory = (announce) => {
63
67
  detail="Create the first task for this milestone."
64
68
  action={
65
69
  <button
66
- class="kui-recipe__button"
67
- data-primary="true"
68
70
  type="button"
69
71
  data-action="recipe-action"
70
72
  data-recipe-command="create"
@@ -83,7 +85,6 @@ export const createRecipe: RecipeFactory = (announce) => {
83
85
  urgency="alert"
84
86
  action={
85
87
  <button
86
- class="kui-recipe__button"
87
88
  type="button"
88
89
  data-action="recipe-action"
89
90
  data-recipe-command="retry"
@@ -104,7 +105,6 @@ export const createRecipe: RecipeFactory = (announce) => {
104
105
  <span class="kui-inline-metadata">
105
106
  <LoadingSpinner label="Refreshing release tasks" />
106
107
  <button
107
- class="kui-recipe__button"
108
108
  type="button"
109
109
  data-action="recipe-action"
110
110
  data-recipe-command="finish"
@@ -120,59 +120,65 @@ export const createRecipe: RecipeFactory = (announce) => {
120
120
  );
121
121
  };
122
122
  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}
123
+ <RecipeRoot
124
+ recipe="recipe-list-workspace-states"
125
+ dataAttributes={{ 'data-list-state': state.value }}
127
126
  >
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"
162
- >
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>
127
+ <div class="recipe-list">
128
+ <Pane
129
+ element="section"
130
+ contentClassName="recipe-list__body"
131
+ header={
132
+ <Toolbar
133
+ label="Release tasks"
134
+ dividerSides=""
135
+ leading={
136
+ <ToolbarText
137
+ text="Release tasks"
138
+ size="xlarge"
139
+ id="recipe-list-title"
140
+ />
141
+ }
142
+ trailing={
143
+ <ToolbarControlGroup
144
+ appearance="borderless"
145
+ content="text"
146
+ buttonAppearance="push"
147
+ >
148
+ <button
149
+ type="button"
150
+ data-action="recipe-action"
151
+ data-recipe-command="empty"
152
+ >
153
+ Clear
154
+ </button>
155
+ <button
156
+ type="button"
157
+ data-action="recipe-action"
158
+ data-recipe-command="fail"
159
+ >
160
+ Simulate failure
161
+ </button>
162
+ <button
163
+ type="button"
164
+ data-action="recipe-action"
165
+ data-recipe-command="refresh"
166
+ >
167
+ Refresh
168
+ </button>
169
+ </ToolbarControlGroup>
170
+ }
171
+ />
172
+ }
173
+ >
174
+ {renderBody()}
175
+ <RecipeOwnershipNote>
176
+ The recipe owns feedback placement and stable content. The app owns
177
+ fetching, cache age, retry policy, and domain rows.
178
+ </RecipeOwnershipNote>
179
+ </Pane>
174
180
  </div>
175
- </section>
181
+ </RecipeRoot>
176
182
  );
177
183
  return {
178
184
  render,
@@ -0,0 +1,7 @@
1
+ .recipe-inspector__controls {
2
+ display: flex;
3
+ min-width: 0;
4
+ flex-direction: column;
5
+ margin-inline: var(--kui-layout-inline-margin, remify(8px));
6
+ gap: var(--kui-space-s);
7
+ }