@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
@@ -1,15 +1,15 @@
1
1
  import '@kerfjs/ui/layout.css';
2
2
  import '@kerfjs/ui/select/register';
3
- import './recipes.css';
3
+ import './loading-inspector.css';
4
4
 
5
5
  import { em } from '@kerfjs/ui/css-values';
6
6
  import { ListItem } from '@kerfjs/ui/list-item';
7
7
  import { LucideIcon } from '@kerfjs/ui/lucide-icon';
8
+ import { Pane } from '@kerfjs/ui/pane';
8
9
  import { SegmentedControl } from '@kerfjs/ui/segmented-control';
9
10
  import { Select } from '@kerfjs/ui/select';
10
11
  import { Skeleton } from '@kerfjs/ui/skeleton';
11
12
  import { StateBanner } from '@kerfjs/ui/state-banner';
12
- import { Text } from '@kerfjs/ui/text';
13
13
  import { Toolbar } from '@kerfjs/ui/toolbar';
14
14
  import { ToolbarControlGroup } from '@kerfjs/ui/toolbar-control-group';
15
15
  import { ToolbarText } from '@kerfjs/ui/toolbar-text';
@@ -17,6 +17,11 @@ import { ValueTable, ValueTableRow } from '@kerfjs/ui/value-table';
17
17
  import { signal } from 'kerfjs';
18
18
  import { Columns3, FileText, Inbox, List } from 'lucide';
19
19
 
20
+ import {
21
+ RecipeHeadingSummary,
22
+ RecipeOwnershipNote,
23
+ RecipeRoot,
24
+ } from './recipe-root.js';
20
25
  import type { RecipeFactory } from './types.js';
21
26
 
22
27
  const icon = (node: Parameters<typeof LucideIcon>[0]['icon'], name: string) => (
@@ -35,144 +40,159 @@ export const createRecipe: RecipeFactory = (announce) => {
35
40
  const render = () => {
36
41
  const p = loading.value;
37
42
  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)}
43
+ <RecipeRoot
44
+ recipe="recipe-loading-inspector"
45
+ measure="inspector"
46
+ dataAttributes={{ 'data-inspector-loading': String(p) }}
42
47
  >
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"
48
+ <div class="recipe-inspector">
49
+ <Pane
50
+ element="section"
51
+ contentClassName="recipe-inspector__body"
52
+ header={
53
+ <>
54
+ <Toolbar
55
+ label="Ticket inspector"
56
+ dividerSides=""
57
+ leading={
58
+ <>
59
+ <ToolbarControlGroup appearance="borderless" single>
60
+ {icon(FileText, 'file-text')}
61
+ </ToolbarControlGroup>
62
+ <ToolbarText
63
+ text="Ticket · KF-2048"
64
+ size="xlarge"
65
+ id="recipe-inspector-title"
66
+ placeholder={p}
67
+ />
68
+ </>
69
+ }
70
+ trailing={
71
+ <ToolbarControlGroup
72
+ appearance="borderless"
73
+ content="text"
74
+ single
75
+ >
76
+ <button
77
+ type="button"
78
+ data-action="recipe-action"
79
+ data-recipe-command="toggle"
80
+ >
81
+ {p ? 'Show loaded' : 'Show loading'}
82
+ </button>
83
+ </ToolbarControlGroup>
84
+ }
85
+ />
86
+ <RecipeHeadingSummary id="recipe-inspector-summary">
87
+ {p ? (
88
+ <Skeleton width={em(18)} />
89
+ ) : (
90
+ 'Restore keyboard focus after a dialog closes'
91
+ )}
92
+ </RecipeHeadingSummary>
93
+ </>
94
+ }
95
+ >
96
+ <section>
97
+ <ValueTable label="Ticket details">
98
+ <ValueTableRow
99
+ label="Status"
100
+ value="In review"
101
+ icon={icon(Inbox, 'inbox')}
102
+ placeholder={p}
103
+ />
104
+ <ValueTableRow
105
+ label="Owner"
106
+ value="Mara Lopez"
107
+ placeholder={p}
108
+ />
109
+ <ValueTableRow label="Priority" value="High" placeholder={p} />
110
+ <ValueTableRow
111
+ label="Updated"
112
+ value="2 hours ago"
113
+ placeholder={p}
114
+ />
115
+ </ValueTable>
116
+ </section>
117
+ <div class="recipe-inspector__controls">
118
+ <Select
119
+ name="recipe-inspector-status"
120
+ value="review"
121
+ label="Status"
55
122
  placeholder={p}
123
+ choices={[
124
+ { value: 'review', label: 'In review' },
125
+ { value: 'ready', label: 'Ready' },
126
+ { value: 'done', label: 'Done' },
127
+ ]}
56
128
  />
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"
129
+ <SegmentedControl
130
+ id="recipe-inspector-view"
131
+ label="Inspector view"
132
+ value="details"
133
+ appearance="toolbar"
134
+ shape="pill"
135
+ size="small"
136
+ placeholder={p}
137
+ choices={[
138
+ {
139
+ value: 'details',
140
+ label: 'Details',
141
+ content: icon(List, 'list'),
142
+ },
143
+ {
144
+ value: 'activity',
145
+ label: 'Activity',
146
+ content: icon(Columns3, 'columns-3'),
147
+ },
148
+ {
149
+ value: 'files',
150
+ label: 'Files',
151
+ content: icon(FileText, 'file-text'),
152
+ },
153
+ ]}
154
+ />
155
+ </div>
156
+ <section>
157
+ <ListItem
158
+ action="recipe-action"
159
+ itemId="reassign"
160
+ label="Reassign ticket"
86
161
  icon={icon(Inbox, 'inbox')}
87
162
  placeholder={p}
88
163
  />
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"
164
+ <ListItem
165
+ action="recipe-action"
166
+ itemId="watch"
167
+ label="Watch for changes"
94
168
  placeholder={p}
95
169
  />
96
- </ValueTable>
97
- </section>
98
- <div class="recipe-inspector__controls">
99
- <Select
100
- name="recipe-inspector-status"
101
- value="review"
102
- 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"
142
- icon={icon(Inbox, 'inbox')}
143
- placeholder={p}
144
- />
145
- <ListItem
146
- action="recipe-action"
147
- itemId="watch"
148
- label="Watch for changes"
149
- placeholder={p}
150
- />
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>
170
+ </section>
171
+ {p ? (
172
+ <StateBanner
173
+ tone="info"
174
+ title=""
175
+ detail=""
176
+ icon={icon(FileText, 'file-text')}
177
+ placeholder
178
+ />
179
+ ) : (
180
+ <StateBanner
181
+ tone="success"
182
+ title="Up to date"
183
+ detail="All checks passed on the latest revision."
184
+ icon={icon(FileText, 'file-text')}
185
+ />
186
+ )}
187
+ <RecipeOwnershipNote>
188
+ Each value-bearing component's <code>placeholder</code> prop
189
+ renders skeletons in its value slots while loading, so the recipe
190
+ composes a faithful loading inspector from real chrome. The app
191
+ owns the loading lifecycle and which values are still unknown.
192
+ </RecipeOwnershipNote>
193
+ </Pane>
174
194
  </div>
175
- </section>
195
+ </RecipeRoot>
176
196
  );
177
197
  };
178
198
  return {
@@ -0,0 +1,12 @@
1
+ .recipe-sidebar {
2
+ display: grid;
3
+ min-height: 32rem;
4
+ }
5
+
6
+ .recipe-sidebar__body {
7
+ min-height: 0;
8
+ }
9
+
10
+ .recipe-sidebar__footer {
11
+ border-block-start: 1px solid var(--kui-color-border);
12
+ }
@@ -1,126 +1,137 @@
1
1
  import '@kerfjs/ui/layout.css';
2
- import './recipes.css';
2
+ import './navigation-sidebar.css';
3
3
 
4
4
  import { ListHeader } from '@kerfjs/ui/list-header';
5
5
  import { ListItem } from '@kerfjs/ui/list-item';
6
6
  import { LucideIcon } from '@kerfjs/ui/lucide-icon';
7
- import { Text } from '@kerfjs/ui/text';
7
+ import { Pane } from '@kerfjs/ui/pane';
8
8
  import { Toolbar } from '@kerfjs/ui/toolbar';
9
9
  import { ToolbarControlGroup } from '@kerfjs/ui/toolbar-control-group';
10
10
  import { signal } from 'kerfjs';
11
11
  import { Folder, Inbox, Plus, Settings, Users } from 'lucide';
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
  export const createRecipe: RecipeFactory = (announce) => {
16
21
  const selected = signal('inbox');
17
22
  const expanded = signal(true);
18
23
  const render = () => (
19
- <aside
20
- class="kui-recipe recipe-sidebar kui-recipe__surface kui-pane"
21
- data-recipe="recipe-navigation-sidebar"
24
+ <RecipeRoot
25
+ element="aside"
26
+ recipe="recipe-navigation-sidebar"
27
+ measure="sidebar"
22
28
  >
23
- <div class="recipe-sidebar__body kui-pane__content kui-content">
24
- <section>
25
- <ListHeader
26
- label="Workspace"
27
- count={3}
28
- countLabel="3 workspaces"
29
- action="recipe-action"
30
- actionLabel="Add workspace item"
31
- actionIcon={<LucideIcon icon={Plus} name="plus" />}
32
- />
33
- <ListItem
34
- action="recipe-action"
35
- itemId="inbox"
36
- label="Inbox"
37
- icon={<LucideIcon icon={Inbox} name="inbox" />}
38
- trailing={<span>12</span>}
39
- selected={selected.value === 'inbox'}
40
- />
41
- <ListItem
42
- action="recipe-action"
43
- itemId="shared"
44
- label="Shared with me"
45
- icon={<LucideIcon icon={Users} name="users" />}
46
- selected={selected.value === 'shared'}
47
- />
48
- <ListItem
49
- action="recipe-action"
50
- itemId="drafts"
51
- label="Drafts without an icon"
52
- selected={selected.value === 'drafts'}
53
- />
54
- </section>
55
- <section>
56
- <ListHeader
57
- label="Projects"
58
- toggle
59
- action="recipe-action"
60
- expanded={expanded.value}
61
- />
62
- {expanded.value && (
63
- <>
64
- <ListItem
65
- action="recipe-action"
66
- itemId="design"
67
- label="Design system rollout across desktop and tablet"
68
- icon={<LucideIcon icon={Folder} name="folder" />}
69
- selected={selected.value === 'design'}
70
- multiline
71
- />
72
- <ListItem
73
- action="recipe-action"
74
- itemId="archive"
75
- label="Archived"
76
- disabled
77
- title="Available to administrators"
78
- />
79
- <div class="kui-content-item">
80
- <strong>Quarterly goal</strong>
81
- <Text class="kui-recipe__muted">
82
- Ship accessible navigation patterns to every workspace.
83
- </Text>
84
- </div>
85
- </>
86
- )}
87
- </section>
88
- <Text class="kui-recipe__ownership kui-content-item">
89
- The recipe owns pane, content-item, and toolbar geometry. The app owns
90
- routes, permissions, labels, and disclosure state.
91
- </Text>
92
- </div>
93
- <footer class="recipe-sidebar__footer kui-pane__footer">
94
- <Toolbar
95
- label="Sidebar actions"
96
- dividerSides=""
97
- leading={
98
- <ToolbarControlGroup appearance="borderless" single>
99
- <button
100
- type="button"
101
- aria-label="Add project"
102
- data-action="recipe-action"
103
- data-recipe-command="add"
104
- >
105
- <LucideIcon icon={Plus} name="plus" />
106
- </button>
107
- </ToolbarControlGroup>
108
- }
109
- trailing={
110
- <ToolbarControlGroup appearance="borderless" single>
111
- <button
112
- type="button"
113
- aria-label="Workspace settings"
114
- data-action="recipe-action"
115
- data-recipe-command="settings"
116
- >
117
- <LucideIcon icon={Settings} name="settings" />
118
- </button>
119
- </ToolbarControlGroup>
29
+ <div class="recipe-sidebar">
30
+ <Pane
31
+ element="div"
32
+ contentClassName="recipe-sidebar__body"
33
+ footer={
34
+ <Toolbar
35
+ label="Sidebar actions"
36
+ dividerSides=""
37
+ leading={
38
+ <ToolbarControlGroup appearance="borderless" single>
39
+ <button
40
+ type="button"
41
+ aria-label="Add project"
42
+ data-action="recipe-action"
43
+ data-recipe-command="add"
44
+ >
45
+ <LucideIcon icon={Plus} name="plus" />
46
+ </button>
47
+ </ToolbarControlGroup>
48
+ }
49
+ trailing={
50
+ <ToolbarControlGroup appearance="borderless" single>
51
+ <button
52
+ type="button"
53
+ aria-label="Workspace settings"
54
+ data-action="recipe-action"
55
+ data-recipe-command="settings"
56
+ >
57
+ <LucideIcon icon={Settings} name="settings" />
58
+ </button>
59
+ </ToolbarControlGroup>
60
+ }
61
+ />
120
62
  }
121
- />
122
- </footer>
123
- </aside>
63
+ >
64
+ <section>
65
+ <ListHeader
66
+ label="Workspace"
67
+ count={3}
68
+ countLabel="3 workspaces"
69
+ action="recipe-action"
70
+ actionLabel="Add workspace item"
71
+ actionIcon={<LucideIcon icon={Plus} name="plus" />}
72
+ />
73
+ <ListItem
74
+ action="recipe-action"
75
+ itemId="inbox"
76
+ label="Inbox"
77
+ icon={<LucideIcon icon={Inbox} name="inbox" />}
78
+ trailing={<span>12</span>}
79
+ selected={selected.value === 'inbox'}
80
+ />
81
+ <ListItem
82
+ action="recipe-action"
83
+ itemId="shared"
84
+ label="Shared with me"
85
+ icon={<LucideIcon icon={Users} name="users" />}
86
+ selected={selected.value === 'shared'}
87
+ />
88
+ <ListItem
89
+ action="recipe-action"
90
+ itemId="drafts"
91
+ label="Drafts without an icon"
92
+ selected={selected.value === 'drafts'}
93
+ />
94
+ </section>
95
+ <section>
96
+ <ListHeader
97
+ label="Projects"
98
+ toggle
99
+ action="recipe-action"
100
+ expanded={expanded.value}
101
+ />
102
+ {expanded.value && (
103
+ <>
104
+ <ListItem
105
+ action="recipe-action"
106
+ itemId="design"
107
+ label="Design system rollout across desktop and tablet"
108
+ icon={<LucideIcon icon={Folder} name="folder" />}
109
+ selected={selected.value === 'design'}
110
+ multiline
111
+ />
112
+ <ListItem
113
+ action="recipe-action"
114
+ itemId="archive"
115
+ label="Archived"
116
+ disabled
117
+ title="Available to administrators"
118
+ />
119
+ <div class="kui-content-item">
120
+ <strong>Quarterly goal</strong>
121
+ <RecipeMutedText>
122
+ Ship accessible navigation patterns to every workspace.
123
+ </RecipeMutedText>
124
+ </div>
125
+ </>
126
+ )}
127
+ </section>
128
+ <RecipeOwnershipNote>
129
+ The recipe owns pane, content-item, and toolbar geometry. The app
130
+ owns routes, permissions, labels, and disclosure state.
131
+ </RecipeOwnershipNote>
132
+ </Pane>
133
+ </div>
134
+ </RecipeRoot>
124
135
  );
125
136
  return {
126
137
  render,
@@ -0,0 +1,12 @@
1
+ .recipe-navstack {
2
+ display: flex;
3
+ flex-direction: column;
4
+ }
5
+
6
+ .recipe-navstack__stage {
7
+ height: 24rem;
8
+ }
9
+
10
+ .recipe-navstack__view {
11
+ padding-block: var(--kui-space-2xs);
12
+ }