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

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 (212) hide show
  1. package/README.md +29 -5
  2. package/ai/compile-time-contracts-v1.json +5 -2
  3. package/ai/component-catalog-v2.d.ts +19 -1
  4. package/ai/component-catalog-v2.json +842 -127
  5. package/ai/component-catalog-v2.schema.json +33 -1
  6. package/ai/component-catalog.json +603 -126
  7. package/ai/component-catalog.schema.json +21 -1
  8. package/ai/public-api-signatures-v1.md +218 -31
  9. package/ai/skill.md +27 -24
  10. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  11. package/analyzer/index.mjs +105 -35
  12. package/dist/app-tab.d.ts +10 -1
  13. package/dist/app-tab.js +1 -1
  14. package/dist/catalog-resources.d.ts +1 -1
  15. package/dist/catalog.d.ts +28 -5
  16. package/dist/catalog.js +66 -25
  17. package/dist/catalog.js.map +1 -1
  18. package/dist/{chunk-OL4TC3U2.js → chunk-2CE22Q2K.js} +9 -2
  19. package/dist/chunk-2CE22Q2K.js.map +1 -0
  20. package/dist/{chunk-SIU2AC5W.js → chunk-2S7OWAEV.js} +3 -3
  21. package/dist/{chunk-SIU2AC5W.js.map → chunk-2S7OWAEV.js.map} +1 -1
  22. package/dist/{chunk-2YOUUEWR.js → chunk-3S7OUHUN.js} +4 -4
  23. package/dist/{chunk-2YOUUEWR.js.map → chunk-3S7OUHUN.js.map} +1 -1
  24. package/dist/{chunk-2WMSE4MK.js → chunk-4XE2CDYB.js} +2 -2
  25. package/dist/{chunk-2WMSE4MK.js.map → chunk-4XE2CDYB.js.map} +1 -1
  26. package/dist/{chunk-V6RZWDII.js → chunk-7GUQYHKA.js} +19 -2
  27. package/dist/chunk-7GUQYHKA.js.map +1 -0
  28. package/dist/{chunk-ZNZ2JDBW.js → chunk-7IUSV4XG.js} +1 -1
  29. package/dist/chunk-7IUSV4XG.js.map +1 -0
  30. package/dist/{chunk-UMGY5JSP.js → chunk-7XJO4D6A.js} +22 -2
  31. package/dist/chunk-7XJO4D6A.js.map +1 -0
  32. package/dist/{chunk-KKNK3JUT.js → chunk-ABAXNUXU.js} +5 -5
  33. package/dist/chunk-ABAXNUXU.js.map +1 -0
  34. package/dist/{chunk-AQSKJ6U6.js → chunk-DNCOFEUL.js} +21 -2
  35. package/dist/chunk-DNCOFEUL.js.map +1 -0
  36. package/dist/chunk-EKYZCRCX.js +256 -0
  37. package/dist/chunk-EKYZCRCX.js.map +1 -0
  38. package/dist/{chunk-COUPLRZG.js → chunk-IR53BQUJ.js} +16 -12
  39. package/dist/chunk-IR53BQUJ.js.map +1 -0
  40. package/dist/{chunk-3V75EQIP.js → chunk-JGFZ42ZF.js} +3 -3
  41. package/dist/{chunk-3V75EQIP.js.map → chunk-JGFZ42ZF.js.map} +1 -1
  42. package/dist/{chunk-54HM36IQ.js → chunk-KAQUUTZR.js} +4 -2
  43. package/dist/chunk-KAQUUTZR.js.map +1 -0
  44. package/dist/{chunk-ZSYLBVWG.js → chunk-LIOXPQ7N.js} +4 -4
  45. package/dist/chunk-LIOXPQ7N.js.map +1 -0
  46. package/dist/{chunk-S6ZTTTV7.js → chunk-M6GLI6A6.js} +3 -3
  47. package/dist/{chunk-S6ZTTTV7.js.map → chunk-M6GLI6A6.js.map} +1 -1
  48. package/dist/{chunk-OQI7RCRP.js → chunk-MTM43SJO.js} +7 -1
  49. package/dist/chunk-MTM43SJO.js.map +1 -0
  50. package/dist/{chunk-5CE64WGC.js → chunk-OSCL5TKR.js} +3 -3
  51. package/dist/{chunk-5CE64WGC.js.map → chunk-OSCL5TKR.js.map} +1 -1
  52. package/dist/{chunk-DARTMI5Z.js → chunk-SV22UIW4.js} +2 -2
  53. package/dist/{chunk-DARTMI5Z.js.map → chunk-SV22UIW4.js.map} +1 -1
  54. package/dist/{chunk-ELRMBQEC.js → chunk-T7C2VZUB.js} +17 -2
  55. package/dist/chunk-T7C2VZUB.js.map +1 -0
  56. package/dist/{chunk-DJKWFYAA.js → chunk-YZV2PTY4.js} +3 -3
  57. package/dist/{chunk-DJKWFYAA.js.map → chunk-YZV2PTY4.js.map} +1 -1
  58. package/dist/collapsible-panel.d.ts +1 -1
  59. package/dist/collapsible-panel.js.map +1 -1
  60. package/dist/css-values.d.ts +41 -3
  61. package/dist/css-values.js +1 -1
  62. package/dist/grid.d.ts +15 -1
  63. package/dist/grid.js +2 -1
  64. package/dist/index.d.ts +1 -1
  65. package/dist/index.js +19 -19
  66. package/dist/list-action-row.js +1 -1
  67. package/dist/list-header.js +1 -1
  68. package/dist/list-item.js +1 -1
  69. package/dist/list.d.ts +21 -2
  70. package/dist/list.js +2 -1
  71. package/dist/nav-stack.js +1 -1
  72. package/dist/pane.d.ts +17 -2
  73. package/dist/pane.js +1 -1
  74. package/dist/row.d.ts +19 -1
  75. package/dist/row.js +2 -1
  76. package/dist/segmented-control.js +1 -1
  77. package/dist/select.d.ts +13 -3
  78. package/dist/select.js +1 -1
  79. package/dist/skeleton.d.ts +5 -1
  80. package/dist/skeleton.js +1 -1
  81. package/dist/spacer.js +1 -1
  82. package/dist/split-view.js +1 -1
  83. package/dist/state-banner.js +1 -1
  84. package/dist/styles/app-tab.css +9 -0
  85. package/dist/styles/catalog/components/catalog-example-stack.css +4 -1
  86. package/dist/styles/catalog/components/catalog-example.css +145 -0
  87. package/dist/styles/collapsible-panel.css +132 -4
  88. package/dist/styles/document.css +23 -0
  89. package/dist/styles/foundation.css +21 -7
  90. package/dist/styles/grid.css +10 -0
  91. package/dist/styles/list-header.css +45 -0
  92. package/dist/styles/list-inset-control.css +8 -1
  93. package/dist/styles/list-item.css +6 -0
  94. package/dist/styles/list.css +11 -0
  95. package/dist/styles/nav-stack.css +89 -2
  96. package/dist/styles/pane.css +86 -1
  97. package/dist/styles/resizable-region.css +93 -5
  98. package/dist/styles/row.css +10 -0
  99. package/dist/styles/select.css +39 -4
  100. package/dist/styles/skeleton.css +4 -1
  101. package/dist/styles/split-view.css +107 -1
  102. package/dist/styles/tab-scaffold.css +64 -1
  103. package/dist/styles/text.css +6 -0
  104. package/dist/styles/toolbar-control-group.css +90 -11
  105. package/dist/styles/toolbar-text.css +4 -1
  106. package/dist/styles/toolbar.css +130 -38
  107. package/dist/styles/webawesome.css +48 -2
  108. package/dist/styles/workbench.css +136 -4
  109. package/dist/text.d.ts +4 -3
  110. package/dist/text.js +1 -1
  111. package/dist/toolbar-text.js +1 -1
  112. package/dist/toolbar.d.ts +24 -3
  113. package/dist/toolbar.js +1 -1
  114. package/dist/{types-CzgSrFXP.d.ts → types-CEsieBZi.d.ts} +6 -1
  115. package/dist/value-table.js +1 -1
  116. package/dist/wire-resizable-regions.js +1 -1
  117. package/dist/wire-sidebar.d.ts +18 -3
  118. package/dist/wire-sidebar.js +96 -15
  119. package/dist/wire-sidebar.js.map +1 -1
  120. package/docs/accessibility.md +49 -9
  121. package/docs/app-layouts.md +73 -0
  122. package/docs/catalog.md +23 -2
  123. package/docs/collapsible-panel.md +83 -9
  124. package/docs/component-contract.md +36 -12
  125. package/docs/component-integration.md +9 -4
  126. package/docs/component-selection.md +25 -6
  127. package/docs/design/templates/list/stack-dark.svg +1 -1
  128. package/docs/design/templates/list/stack.svg +1 -1
  129. package/docs/design/templates/list-dark.svg +1 -1
  130. package/docs/design/templates/list-header/action-dark.svg +1 -1
  131. package/docs/design/templates/list-header/action.svg +1 -1
  132. package/docs/design/templates/list-header/count-dark.svg +1 -1
  133. package/docs/design/templates/list-header/count.svg +1 -1
  134. package/docs/design/templates/list-header/inline-action-dark.svg +1 -1
  135. package/docs/design/templates/list-header/inline-action.svg +1 -1
  136. package/docs/design/templates/list-header/toggle-expanded-dark.svg +1 -1
  137. package/docs/design/templates/list-header/toggle-expanded.svg +1 -1
  138. package/docs/design/templates/list-header-dark.svg +1 -1
  139. package/docs/design/templates/list-header.svg +1 -1
  140. package/docs/design/templates/list.svg +1 -1
  141. package/docs/design/templates/state-banner/info-badge-dark.svg +1 -1
  142. package/docs/design/templates/state-banner/info-badge.svg +1 -1
  143. package/docs/design/templates/state-banner-dark.svg +1 -1
  144. package/docs/design/templates/state-banner.svg +1 -1
  145. package/docs/design/templates/toolbar/title-and-actions-dark.svg +1 -1
  146. package/docs/design/templates/toolbar/title-and-actions.svg +1 -1
  147. package/docs/design/templates/toolbar-control-group/with-text-dark.svg +1 -1
  148. package/docs/design/templates/toolbar-control-group/with-text.svg +1 -1
  149. package/docs/design/templates/toolbar-control-group-dark.svg +1 -1
  150. package/docs/design/templates/toolbar-control-group.svg +1 -1
  151. package/docs/design/templates/toolbar-dark.svg +1 -1
  152. package/docs/design/templates/toolbar-text/default-dark.svg +1 -1
  153. package/docs/design/templates/toolbar-text/default.svg +1 -1
  154. package/docs/design/templates/toolbar-text/large-dark.svg +1 -1
  155. package/docs/design/templates/toolbar-text/large.svg +1 -1
  156. package/docs/design/templates/toolbar-text/small-dark.svg +1 -1
  157. package/docs/design/templates/toolbar-text/small.svg +1 -1
  158. package/docs/design/templates/toolbar-text-dark.svg +1 -1
  159. package/docs/design/templates/toolbar-text.svg +1 -1
  160. package/docs/design/templates/toolbar.svg +1 -1
  161. package/docs/document-baseline.md +31 -0
  162. package/docs/layout.md +86 -21
  163. package/docs/nav-stack.md +8 -0
  164. package/docs/recipes.md +81 -44
  165. package/docs/split-view.md +8 -0
  166. package/docs/tab-scaffold.md +4 -2
  167. package/docs/type-contracts.md +21 -17
  168. package/docs/ui-analyzer.md +19 -0
  169. package/docs/ui-evaluator.md +17 -0
  170. package/docs/ux-demo.md +5 -5
  171. package/docs/webawesome-theme.md +20 -2
  172. package/docs/workbench.md +20 -1
  173. package/evaluator/index.mjs +73 -8
  174. package/llms.txt +32 -14
  175. package/package.json +4 -2
  176. package/ux-demo/recipes/app-shell.tsx +209 -178
  177. package/ux-demo/recipes/collapsible-sidebar.tsx +189 -159
  178. package/ux-demo/recipes/compact-toolbar.tsx +48 -35
  179. package/ux-demo/recipes/composer-form.tsx +87 -79
  180. package/ux-demo/recipes/list-detail-dialog.tsx +124 -142
  181. package/ux-demo/recipes/list-workspace-states.tsx +83 -83
  182. package/ux-demo/recipes/loaders.ts +5 -2
  183. package/ux-demo/recipes/loading-inspector.tsx +157 -160
  184. package/ux-demo/recipes/navigation-sidebar.tsx +111 -109
  185. package/ux-demo/recipes/navigation-stack.tsx +50 -49
  186. package/ux-demo/recipes/types.ts +14 -0
  187. package/ux-demo/recipes/workspace-header.tsx +73 -56
  188. package/dist/chunk-54HM36IQ.js.map +0 -1
  189. package/dist/chunk-AQSKJ6U6.js.map +0 -1
  190. package/dist/chunk-COUPLRZG.js.map +0 -1
  191. package/dist/chunk-ELRMBQEC.js.map +0 -1
  192. package/dist/chunk-J3EE6XWD.js +0 -115
  193. package/dist/chunk-J3EE6XWD.js.map +0 -1
  194. package/dist/chunk-KKNK3JUT.js.map +0 -1
  195. package/dist/chunk-OL4TC3U2.js.map +0 -1
  196. package/dist/chunk-OQI7RCRP.js.map +0 -1
  197. package/dist/chunk-UMGY5JSP.js.map +0 -1
  198. package/dist/chunk-V6RZWDII.js.map +0 -1
  199. package/dist/chunk-ZNZ2JDBW.js.map +0 -1
  200. package/dist/chunk-ZSYLBVWG.js.map +0 -1
  201. package/ux-demo/recipes/app-shell.css +0 -87
  202. package/ux-demo/recipes/collapsible-sidebar.css +0 -83
  203. package/ux-demo/recipes/compact-toolbar.css +0 -35
  204. package/ux-demo/recipes/composer-form.css +0 -19
  205. package/ux-demo/recipes/list-detail-dialog.css +0 -42
  206. package/ux-demo/recipes/list-workspace-states.css +0 -30
  207. package/ux-demo/recipes/loading-inspector.css +0 -7
  208. package/ux-demo/recipes/navigation-sidebar.css +0 -12
  209. package/ux-demo/recipes/navigation-stack.css +0 -12
  210. package/ux-demo/recipes/recipe-root.css +0 -67
  211. package/ux-demo/recipes/recipe-root.tsx +0 -87
  212. package/ux-demo/recipes/workspace-header.css +0 -7
@@ -1,46 +1,51 @@
1
1
  import '@kerfjs/ui/layout.css';
2
- import './list-workspace-states.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
6
  import { Pane } from '@kerfjs/ui/pane';
7
+ import { Row } from '@kerfjs/ui/row';
7
8
  import { StateBanner } from '@kerfjs/ui/state-banner';
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 {
14
- RecipeMutedText,
15
- RecipeOwnershipNote,
16
- RecipeRoot,
17
- } from './recipe-root.js';
18
- import type { RecipeFactory } from './types.js';
14
+ import type { RecipeFactory, RecipePresentation } from './types.js';
19
15
 
20
16
  type ListState = 'loading' | 'empty' | 'populated' | 'stale' | 'error';
21
17
  const items = [
22
- 'Audit keyboard focus order',
23
- 'Verify 200% zoom layout',
24
- 'Publish package migration notes',
25
- ];
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
+ };
26
35
 
27
36
  export const createRecipe: RecipeFactory = (announce) => {
28
37
  const state = signal<ListState>('loading');
29
38
  const populated = () => (
30
- <ul class="recipe-list__items" aria-label="Release tasks">
31
- {items.map((item, index) => (
32
- <li>
33
- <strong>{item}</strong>
34
- <RecipeMutedText>
35
- {index === 0
36
- ? 'In review · Mara'
37
- : index === 1
38
- ? 'Ready · Sam'
39
- : 'Draft · Inez'}
40
- </RecipeMutedText>
41
- </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
+ />
42
47
  ))}
43
- </ul>
48
+ </section>
44
49
  );
45
50
  const renderBody = () => {
46
51
  if (state.value === 'loading')
@@ -102,7 +107,7 @@ export const createRecipe: RecipeFactory = (announce) => {
102
107
  detail="Refreshing in the background."
103
108
  tone="warning"
104
109
  action={
105
- <span class="kui-inline-metadata">
110
+ <Row gap="xs" vAlign="middle">
106
111
  <LoadingSpinner label="Refreshing release tasks" />
107
112
  <button
108
113
  type="button"
@@ -111,7 +116,7 @@ export const createRecipe: RecipeFactory = (announce) => {
111
116
  >
112
117
  Finish refresh
113
118
  </button>
114
- </span>
119
+ </Row>
115
120
  }
116
121
  />
117
122
  )}
@@ -120,65 +125,60 @@ export const createRecipe: RecipeFactory = (announce) => {
120
125
  );
121
126
  };
122
127
  const render = () => (
123
- <RecipeRoot
124
- recipe="recipe-list-workspace-states"
125
- dataAttributes={{ 'data-list-state': state.value }}
126
- >
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
- }
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"
171
146
  />
172
147
  }
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>
180
- </div>
181
- </RecipeRoot>
148
+ trailing={
149
+ <ToolbarControlGroup
150
+ appearance="borderless"
151
+ content="text"
152
+ buttonAppearance="push"
153
+ >
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>
182
182
  );
183
183
  return {
184
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,8 +1,9 @@
1
1
  import '@kerfjs/ui/layout.css';
2
2
  import '@kerfjs/ui/select/register';
3
- import './loading-inspector.css';
4
3
 
4
+ import { Row } from '@kerfjs/ui';
5
5
  import { em } from '@kerfjs/ui/css-values';
6
+ import { List } from '@kerfjs/ui/list';
6
7
  import { ListItem } from '@kerfjs/ui/list-item';
7
8
  import { LucideIcon } from '@kerfjs/ui/lucide-icon';
8
9
  import { Pane } from '@kerfjs/ui/pane';
@@ -10,19 +11,26 @@ import { SegmentedControl } from '@kerfjs/ui/segmented-control';
10
11
  import { Select } from '@kerfjs/ui/select';
11
12
  import { Skeleton } from '@kerfjs/ui/skeleton';
12
13
  import { StateBanner } from '@kerfjs/ui/state-banner';
14
+ import { Text } from '@kerfjs/ui/text';
13
15
  import { Toolbar } from '@kerfjs/ui/toolbar';
14
16
  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 {
21
- RecipeHeadingSummary,
22
- RecipeOwnershipNote,
23
- RecipeRoot,
24
- } from './recipe-root.js';
25
- 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
+ };
26
34
 
27
35
  const icon = (node: Parameters<typeof LucideIcon>[0]['icon'], name: string) => (
28
36
  <LucideIcon icon={node} name={name} />
@@ -40,159 +48,148 @@ export const createRecipe: RecipeFactory = (announce) => {
40
48
  const render = () => {
41
49
  const p = loading.value;
42
50
  return (
43
- <RecipeRoot
44
- recipe="recipe-loading-inspector"
45
- measure="inspector"
46
- dataAttributes={{ '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
+ <Row controlInsets="trbl">
94
+ <Text 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
+ </Row>
102
+ </>
103
+ }
47
104
  >
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"
122
- placeholder={p}
123
- choices={[
124
- { value: 'review', label: 'In review' },
125
- { value: 'ready', label: 'Ready' },
126
- { value: 'done', label: 'Done' },
127
- ]}
128
- />
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"
161
- icon={icon(Inbox, 'inbox')}
162
- placeholder={p}
163
- />
164
- <ListItem
165
- action="recipe-action"
166
- itemId="watch"
167
- label="Watch for changes"
168
- placeholder={p}
169
- />
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>
194
- </div>
195
- </RecipeRoot>
105
+ <section>
106
+ <ValueTable label="Ticket details">
107
+ <ValueTableRow
108
+ label="Status"
109
+ value="In review"
110
+ icon={icon(Inbox, 'inbox')}
111
+ placeholder={p}
112
+ />
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"
118
+ placeholder={p}
119
+ />
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>
196
193
  );
197
194
  };
198
195
  return {