@kerfjs/ui 5.0.0-beta.17 → 5.0.0-beta.21

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 (274) hide show
  1. package/README.md +221 -81
  2. package/ai/application-ui-diagnostic-ids-v1.json +92 -0
  3. package/ai/application-ui-profile-sync.cjs +529 -0
  4. package/ai/application-ui-profile.d.mts +1 -0
  5. package/ai/application-ui-profile.d.ts +102 -0
  6. package/ai/application-ui-profile.defaults.json +41 -0
  7. package/ai/application-ui-profile.mjs +626 -0
  8. package/ai/application-ui-profile.schema.json +130 -0
  9. package/ai/catalog-authoring.json +25 -0
  10. package/ai/catalog-authoring.schema.json +61 -0
  11. package/ai/compile-time-contracts-v1.json +101 -0
  12. package/ai/compile-time-contracts-v1.schema.json +49 -0
  13. package/ai/component-catalog-extension-v2.d.ts +7 -0
  14. package/ai/component-catalog-extension-v2.schema.json +7 -0
  15. package/ai/component-catalog-extension.schema.json +79 -0
  16. package/ai/component-catalog-v2-overrides.json +326 -0
  17. package/ai/component-catalog-v2.d.ts +67 -0
  18. package/ai/component-catalog-v2.json +4441 -0
  19. package/ai/component-catalog-v2.schema.json +246 -0
  20. package/ai/component-catalog.json +649 -6
  21. package/ai/component-catalog.schema.json +15 -0
  22. package/ai/public-api-signatures-v1.md +357 -91
  23. package/ai/skill.md +95 -50
  24. package/ai/webawesome-jsx-signatures-v1.md +1 -1
  25. package/analyzer/cli.mjs +46 -0
  26. package/analyzer/index.d.mts +45 -0
  27. package/analyzer/index.mjs +743 -0
  28. package/analyzer/report.schema.json +66 -0
  29. package/dist/app-tab.d.ts +1 -1
  30. package/dist/app-tab.js +1 -1
  31. package/dist/browser/pane.js +3 -0
  32. package/dist/browser/sunken-panel.js +3 -0
  33. package/dist/catalog-resources.d.ts +34 -0
  34. package/dist/catalog-resources.js +22 -0
  35. package/dist/catalog-resources.js.map +1 -0
  36. package/dist/catalog.d.ts +29 -4
  37. package/dist/catalog.js +302 -84
  38. package/dist/catalog.js.map +1 -1
  39. package/dist/chunk-5VTB2BKP.js +35 -0
  40. package/dist/chunk-5VTB2BKP.js.map +1 -0
  41. package/dist/chunk-6WTETUZ6.js +21 -0
  42. package/dist/chunk-6WTETUZ6.js.map +1 -0
  43. package/dist/chunk-7KEUJIIC.js +218 -0
  44. package/dist/chunk-7KEUJIIC.js.map +1 -0
  45. package/dist/chunk-7L6EHUMV.js +31 -0
  46. package/dist/chunk-7L6EHUMV.js.map +1 -0
  47. package/dist/{chunk-XXMOARTH.js → chunk-AASLYRGE.js} +57 -16
  48. package/dist/chunk-AASLYRGE.js.map +1 -0
  49. package/dist/chunk-BBRXX6PF.js +108 -0
  50. package/dist/chunk-BBRXX6PF.js.map +1 -0
  51. package/dist/{chunk-6NLRBSVX.js → chunk-CN2XNTAM.js} +129 -72
  52. package/dist/chunk-CN2XNTAM.js.map +1 -0
  53. package/dist/chunk-DPDBVKNA.js +113 -0
  54. package/dist/chunk-DPDBVKNA.js.map +1 -0
  55. package/dist/chunk-DSNIYOZ3.js +114 -0
  56. package/dist/chunk-DSNIYOZ3.js.map +1 -0
  57. package/dist/chunk-ELSJX4W7.js +68 -0
  58. package/dist/chunk-ELSJX4W7.js.map +1 -0
  59. package/dist/{chunk-AHQI52QO.js → chunk-FEY65TBV.js} +6 -2
  60. package/dist/chunk-FEY65TBV.js.map +1 -0
  61. package/dist/chunk-JRKSK2HX.js +79 -0
  62. package/dist/chunk-JRKSK2HX.js.map +1 -0
  63. package/dist/chunk-K57KRAOV.js +117 -0
  64. package/dist/chunk-K57KRAOV.js.map +1 -0
  65. package/dist/chunk-LPOMRC4C.js +25 -0
  66. package/dist/chunk-LPOMRC4C.js.map +1 -0
  67. package/dist/chunk-M7JBER5U.js +41 -0
  68. package/dist/chunk-M7JBER5U.js.map +1 -0
  69. package/dist/chunk-NENBUYX5.js +79 -0
  70. package/dist/chunk-NENBUYX5.js.map +1 -0
  71. package/dist/chunk-OHU6CI22.js +83 -0
  72. package/dist/chunk-OHU6CI22.js.map +1 -0
  73. package/dist/{chunk-YGN7OMLT.js → chunk-OZWU5ZPZ.js} +2 -2
  74. package/dist/chunk-OZWU5ZPZ.js.map +1 -0
  75. package/dist/chunk-PIDTEQ3U.js +105 -0
  76. package/dist/chunk-PIDTEQ3U.js.map +1 -0
  77. package/dist/chunk-PX3YSS5C.js +32 -0
  78. package/dist/chunk-PX3YSS5C.js.map +1 -0
  79. package/dist/chunk-PZQVSDLH.js +61 -0
  80. package/dist/chunk-PZQVSDLH.js.map +1 -0
  81. package/dist/chunk-QO55FN2Y.js +20 -0
  82. package/dist/chunk-QO55FN2Y.js.map +1 -0
  83. package/dist/chunk-QQFJMRIB.js +45 -0
  84. package/dist/chunk-QQFJMRIB.js.map +1 -0
  85. package/dist/chunk-RYRIFZCT.js +58 -0
  86. package/dist/chunk-RYRIFZCT.js.map +1 -0
  87. package/dist/{chunk-7BR3DO2A.js → chunk-SRSJO5QE.js} +13 -4
  88. package/dist/chunk-SRSJO5QE.js.map +1 -0
  89. package/dist/chunk-VLYV65LK.js +38 -0
  90. package/dist/chunk-VLYV65LK.js.map +1 -0
  91. package/dist/chunk-W4CXQYSG.js +23 -0
  92. package/dist/chunk-W4CXQYSG.js.map +1 -0
  93. package/dist/{chunk-WXMGNX2Y.js → chunk-W7YD6E4N.js} +2 -2
  94. package/dist/chunk-W7YD6E4N.js.map +1 -0
  95. package/dist/{chunk-56RJXPHG.js → chunk-Y6LYKFXY.js} +1 -1
  96. package/dist/{chunk-56RJXPHG.js.map → chunk-Y6LYKFXY.js.map} +1 -1
  97. package/dist/collapsible-panel.d.ts +2 -2
  98. package/dist/collapsible-panel.js +47 -6
  99. package/dist/collapsible-panel.js.map +1 -1
  100. package/dist/device-class.js +33 -5
  101. package/dist/device-class.js.map +1 -1
  102. package/dist/disclosure-arrow.js +1 -1
  103. package/dist/empty-state.d.ts +1 -1
  104. package/dist/empty-state.js +1 -1
  105. package/dist/floating-toolbar.d.ts +1 -1
  106. package/dist/floating-toolbar.js +1 -1
  107. package/dist/index.d.ts +6 -4
  108. package/dist/index.js +27 -25
  109. package/dist/list-action-row.d.ts +1 -1
  110. package/dist/list-action-row.js +1 -1
  111. package/dist/list-header.d.ts +30 -9
  112. package/dist/list-header.js +1 -1
  113. package/dist/list-inset-control.d.ts +1 -1
  114. package/dist/list-inset-control.js +1 -1
  115. package/dist/list-inset-text.d.ts +1 -1
  116. package/dist/list-inset-text.js +1 -1
  117. package/dist/list-item.d.ts +1 -1
  118. package/dist/list-item.js +1 -1
  119. package/dist/loading-spinner.js +1 -1
  120. package/dist/nav-stack.d.ts +1 -1
  121. package/dist/nav-stack.js +1 -1
  122. package/dist/pane.d.ts +49 -0
  123. package/dist/pane.js +4 -0
  124. package/dist/pane.js.map +1 -0
  125. package/dist/panel-header.d.ts +10 -4
  126. package/dist/panel-header.js +1 -1
  127. package/dist/resizable-region.d.ts +1 -1
  128. package/dist/resizable-region.js +1 -1
  129. package/dist/segmented-control.d.ts +6 -6
  130. package/dist/segmented-control.js +1 -1
  131. package/dist/select.d.ts +11 -5
  132. package/dist/select.js +1 -1
  133. package/dist/skeleton.d.ts +1 -1
  134. package/dist/skeleton.js +1 -1
  135. package/dist/split-view.d.ts +1 -1
  136. package/dist/split-view.js +70 -10
  137. package/dist/split-view.js.map +1 -1
  138. package/dist/state-banner.d.ts +4 -3
  139. package/dist/state-banner.js +1 -1
  140. package/dist/styles/catalog.css +32 -6
  141. package/dist/styles/layout.css +2 -20
  142. package/dist/styles/pane.css +62 -0
  143. package/dist/styles/segmented-control.css +3 -7
  144. package/dist/styles/sunken-panel.css +18 -0
  145. package/dist/sunken-panel.d.ts +16 -0
  146. package/dist/sunken-panel.js +3 -0
  147. package/dist/sunken-panel.js.map +1 -0
  148. package/dist/tab-bar.d.ts +4 -3
  149. package/dist/tab-bar.js +1 -1
  150. package/dist/tab-scaffold.d.ts +6 -6
  151. package/dist/tab-scaffold.js +43 -8
  152. package/dist/tab-scaffold.js.map +1 -1
  153. package/dist/token-search-field.d.ts +25 -9
  154. package/dist/token-search-field.js +1 -1
  155. package/dist/toolbar-control-group.d.ts +10 -6
  156. package/dist/toolbar-control-group.js +1 -1
  157. package/dist/toolbar-text.d.ts +10 -11
  158. package/dist/toolbar-text.js +1 -1
  159. package/dist/toolbar.d.ts +1 -1
  160. package/dist/toolbar.js +1 -1
  161. package/dist/value-table.d.ts +2 -2
  162. package/dist/value-table.js +1 -1
  163. package/dist/wire-catalog.d.ts +31 -2
  164. package/dist/wire-catalog.js +203 -8
  165. package/dist/wire-catalog.js.map +1 -1
  166. package/dist/wire-nav-stack.js +22 -7
  167. package/dist/wire-nav-stack.js.map +1 -1
  168. package/dist/wire-resizable-regions.d.ts +1 -1
  169. package/dist/wire-resizable-regions.js +1 -1
  170. package/dist/wire-sidebar.js +52 -41
  171. package/dist/wire-sidebar.js.map +1 -1
  172. package/dist/wire-tab-bars.d.ts +5 -2
  173. package/dist/wire-tab-bars.js +1 -1
  174. package/dist/wire-tab-scaffold.js +9 -4
  175. package/dist/wire-tab-scaffold.js.map +1 -1
  176. package/dist/wire-token-search-fields.d.ts +12 -7
  177. package/dist/wire-token-search-fields.js +1 -1
  178. package/dist/workbench.d.ts +1 -1
  179. package/dist/workbench.js +56 -9
  180. package/dist/workbench.js.map +1 -1
  181. package/docs/app-layouts.md +7 -7
  182. package/docs/catalog.md +249 -46
  183. package/docs/collapsible-panel.md +38 -11
  184. package/docs/component-contract.md +132 -7
  185. package/docs/component-selection.md +79 -67
  186. package/docs/design/templates.md +1 -1
  187. package/docs/design-philosophy.md +7 -9
  188. package/docs/device-class.md +8 -8
  189. package/docs/examples/application-ui-profile.json +60 -0
  190. package/docs/examples/command-palette-adapter.tsx +67 -17
  191. package/docs/examples/component-catalog-extension-v2.json +81 -0
  192. package/docs/examples/component-catalog-extension.json +45 -0
  193. package/docs/layout.md +51 -32
  194. package/docs/nav-stack.md +15 -6
  195. package/docs/recipes.md +4 -4
  196. package/docs/split-view.md +3 -3
  197. package/docs/sunken-panel.md +43 -0
  198. package/docs/tab-scaffold.md +16 -7
  199. package/docs/type-contracts.md +99 -0
  200. package/docs/ui-analyzer.md +81 -0
  201. package/docs/ui-doctor.md +77 -0
  202. package/docs/ui-evaluator.md +122 -0
  203. package/docs/webawesome-theme.md +8 -8
  204. package/docs/workbench.md +18 -5
  205. package/doctor/cli.mjs +115 -0
  206. package/doctor/config.schema.json +68 -0
  207. package/doctor/index.d.mts +116 -0
  208. package/doctor/index.mjs +1256 -0
  209. package/doctor/report.schema.json +118 -0
  210. package/evaluator/cli.mjs +89 -0
  211. package/evaluator/index.d.mts +90 -0
  212. package/evaluator/index.mjs +1138 -0
  213. package/evaluator/report.schema.json +152 -0
  214. package/llms.txt +58 -15
  215. package/package.json +70 -10
  216. package/ux-demo/recipes/app-shell.tsx +206 -10
  217. package/ux-demo/recipes/collapsible-sidebar.tsx +167 -44
  218. package/ux-demo/recipes/compact-toolbar.tsx +114 -12
  219. package/ux-demo/recipes/composer-form.tsx +106 -18
  220. package/ux-demo/recipes/list-detail-dialog.tsx +144 -8
  221. package/ux-demo/recipes/list-workspace-states.tsx +165 -8
  222. package/ux-demo/recipes/loaders.ts +5 -2
  223. package/ux-demo/recipes/loading-inspector.tsx +124 -41
  224. package/ux-demo/recipes/mount-recipe.ts +27 -6
  225. package/ux-demo/recipes/navigation-sidebar.tsx +120 -9
  226. package/ux-demo/recipes/navigation-stack.tsx +61 -19
  227. package/ux-demo/recipes/types.ts +3 -1
  228. package/ux-demo/recipes/workspace-header.tsx +57 -2
  229. package/dist/chunk-2Z5TWHKQ.js +0 -34
  230. package/dist/chunk-2Z5TWHKQ.js.map +0 -1
  231. package/dist/chunk-37T3VNIZ.js +0 -19
  232. package/dist/chunk-37T3VNIZ.js.map +0 -1
  233. package/dist/chunk-55DATV3A.js +0 -10
  234. package/dist/chunk-55DATV3A.js.map +0 -1
  235. package/dist/chunk-5ATCDSQS.js +0 -42
  236. package/dist/chunk-5ATCDSQS.js.map +0 -1
  237. package/dist/chunk-5E2HVJ33.js +0 -10
  238. package/dist/chunk-5E2HVJ33.js.map +0 -1
  239. package/dist/chunk-6NLRBSVX.js.map +0 -1
  240. package/dist/chunk-7BR3DO2A.js.map +0 -1
  241. package/dist/chunk-7JB7VPRI.js +0 -34
  242. package/dist/chunk-7JB7VPRI.js.map +0 -1
  243. package/dist/chunk-7LDCTU7D.js +0 -134
  244. package/dist/chunk-7LDCTU7D.js.map +0 -1
  245. package/dist/chunk-AHQI52QO.js.map +0 -1
  246. package/dist/chunk-AQNKJRFH.js +0 -79
  247. package/dist/chunk-AQNKJRFH.js.map +0 -1
  248. package/dist/chunk-AVZHJN6C.js +0 -14
  249. package/dist/chunk-AVZHJN6C.js.map +0 -1
  250. package/dist/chunk-B24C4A6T.js +0 -22
  251. package/dist/chunk-B24C4A6T.js.map +0 -1
  252. package/dist/chunk-CH4SQ6H5.js +0 -39
  253. package/dist/chunk-CH4SQ6H5.js.map +0 -1
  254. package/dist/chunk-DAFFDO33.js +0 -14
  255. package/dist/chunk-DAFFDO33.js.map +0 -1
  256. package/dist/chunk-I7INRJO4.js +0 -17
  257. package/dist/chunk-I7INRJO4.js.map +0 -1
  258. package/dist/chunk-L4OKFDJY.js +0 -24
  259. package/dist/chunk-L4OKFDJY.js.map +0 -1
  260. package/dist/chunk-M5JRI6MN.js +0 -27
  261. package/dist/chunk-M5JRI6MN.js.map +0 -1
  262. package/dist/chunk-RNPGFQ33.js +0 -10
  263. package/dist/chunk-RNPGFQ33.js.map +0 -1
  264. package/dist/chunk-VPCTCUED.js +0 -10
  265. package/dist/chunk-VPCTCUED.js.map +0 -1
  266. package/dist/chunk-WRTAQ7BZ.js +0 -23
  267. package/dist/chunk-WRTAQ7BZ.js.map +0 -1
  268. package/dist/chunk-WVPYVDXY.js +0 -15
  269. package/dist/chunk-WVPYVDXY.js.map +0 -1
  270. package/dist/chunk-WXMGNX2Y.js.map +0 -1
  271. package/dist/chunk-XXMOARTH.js.map +0 -1
  272. package/dist/chunk-YGN7OMLT.js.map +0 -1
  273. package/dist/chunk-ZQQ6P4SV.js +0 -20
  274. package/dist/chunk-ZQQ6P4SV.js.map +0 -1
@@ -14,7 +14,9 @@ import { Columns3, FileText, Inbox, List } from 'lucide';
14
14
 
15
15
  import type { RecipeFactory } from './types.js';
16
16
 
17
- const icon = (node: Parameters<typeof LucideIcon>[0]['icon'], name: string) => <LucideIcon icon={node} name={name} />;
17
+ const icon = (node: Parameters<typeof LucideIcon>[0]['icon'], name: string) => (
18
+ <LucideIcon icon={node} name={name} />
19
+ );
18
20
 
19
21
  /**
20
22
  * A record inspector whose per-record values load asynchronously. Every
@@ -27,47 +29,128 @@ export const createRecipe: RecipeFactory = (announce) => {
27
29
  const loading = signal(true);
28
30
  const render = () => {
29
31
  const p = loading.value;
30
- return <section class="kui-recipe recipe-inspector kui-recipe__surface kui-pane" data-recipe="recipe-loading-inspector" data-inspector-loading={String(p)}>
31
- <PanelHeader
32
- title="Ticket · KF-2048"
33
- titleId="recipe-inspector-title"
34
- summary="Restore keyboard focus after a dialog closes"
35
- summaryId="recipe-inspector-summary"
36
- icon={icon(FileText, 'file-text')}
37
- placeholder={p}
38
- actions={<button class="kui-recipe__button" data-primary="true" type="button" data-action="recipe-action" data-recipe-command="toggle">{p ? 'Show loaded' : 'Show loading'}</button>}
39
- />
40
- <div class="recipe-inspector__body kui-pane__content kui-content">
41
- <section>
42
- <ValueTable label="Ticket details">
43
- <ValueTableRow label="Status" value="In review" icon={icon(Inbox, 'inbox')} placeholder={p} />
44
- <ValueTableRow label="Owner" value="Mara Lopez" placeholder={p} />
45
- <ValueTableRow label="Priority" value="High" placeholder={p} />
46
- <ValueTableRow label="Updated" value="2 hours ago" placeholder={p} />
47
- </ValueTable>
48
- </section>
49
- <div class="recipe-inspector__controls">
50
- <Select name="recipe-inspector-status" value="review" label="Status" placeholder={p} choices={[
51
- { value: 'review', label: 'In review' },
52
- { value: 'ready', label: 'Ready' },
53
- { value: 'done', label: 'Done' },
54
- ]} />
55
- <SegmentedControl id="recipe-inspector-view" label="Inspector view" value="details" appearance="toolbar" shape="pill" size="small" placeholder={p} choices={[
56
- { value: 'details', label: 'Details', content: icon(List, 'list') },
57
- { value: 'activity', label: 'Activity', content: icon(Columns3, 'columns-3') },
58
- { value: 'files', label: 'Files', content: icon(FileText, 'file-text') },
59
- ]} />
32
+ return (
33
+ <section
34
+ class="kui-recipe recipe-inspector kui-recipe__surface kui-pane"
35
+ data-recipe="recipe-loading-inspector"
36
+ data-inspector-loading={String(p)}
37
+ >
38
+ <PanelHeader
39
+ title="Ticket · KF-2048"
40
+ titleId="recipe-inspector-title"
41
+ summary="Restore keyboard focus after a dialog closes"
42
+ summaryId="recipe-inspector-summary"
43
+ icon={icon(FileText, 'file-text')}
44
+ placeholder={p}
45
+ actions={
46
+ <button
47
+ class="kui-recipe__button"
48
+ data-primary="true"
49
+ type="button"
50
+ data-action="recipe-action"
51
+ data-recipe-command="toggle"
52
+ >
53
+ {p ? 'Show loaded' : 'Show loading'}
54
+ </button>
55
+ }
56
+ />
57
+ <div class="recipe-inspector__body kui-pane__content kui-content">
58
+ <section>
59
+ <ValueTable label="Ticket details">
60
+ <ValueTableRow
61
+ label="Status"
62
+ value="In review"
63
+ icon={icon(Inbox, 'inbox')}
64
+ placeholder={p}
65
+ />
66
+ <ValueTableRow label="Owner" value="Mara Lopez" placeholder={p} />
67
+ <ValueTableRow label="Priority" value="High" placeholder={p} />
68
+ <ValueTableRow
69
+ label="Updated"
70
+ value="2 hours ago"
71
+ placeholder={p}
72
+ />
73
+ </ValueTable>
74
+ </section>
75
+ <div class="recipe-inspector__controls">
76
+ <Select
77
+ name="recipe-inspector-status"
78
+ value="review"
79
+ label="Status"
80
+ placeholder={p}
81
+ choices={[
82
+ { value: 'review', label: 'In review' },
83
+ { value: 'ready', label: 'Ready' },
84
+ { value: 'done', label: 'Done' },
85
+ ]}
86
+ />
87
+ <SegmentedControl
88
+ id="recipe-inspector-view"
89
+ label="Inspector view"
90
+ value="details"
91
+ appearance="toolbar"
92
+ shape="pill"
93
+ size="small"
94
+ placeholder={p}
95
+ choices={[
96
+ {
97
+ value: 'details',
98
+ label: 'Details',
99
+ content: icon(List, 'list'),
100
+ },
101
+ {
102
+ value: 'activity',
103
+ label: 'Activity',
104
+ content: icon(Columns3, 'columns-3'),
105
+ },
106
+ {
107
+ value: 'files',
108
+ label: 'Files',
109
+ content: icon(FileText, 'file-text'),
110
+ },
111
+ ]}
112
+ />
113
+ </div>
114
+ <section>
115
+ <ListItem
116
+ action="recipe-action"
117
+ itemId="reassign"
118
+ label="Reassign ticket"
119
+ icon={icon(Inbox, 'inbox')}
120
+ placeholder={p}
121
+ />
122
+ <ListItem
123
+ action="recipe-action"
124
+ itemId="watch"
125
+ label="Watch for changes"
126
+ placeholder={p}
127
+ />
128
+ </section>
129
+ {p ? (
130
+ <StateBanner
131
+ tone="info"
132
+ title=""
133
+ detail=""
134
+ icon={icon(FileText, 'file-text')}
135
+ placeholder
136
+ />
137
+ ) : (
138
+ <StateBanner
139
+ tone="success"
140
+ title="Up to date"
141
+ detail="All checks passed on the latest revision."
142
+ icon={icon(FileText, 'file-text')}
143
+ />
144
+ )}
145
+ <p class="kui-recipe__ownership kui-content-item">
146
+ Each value-bearing component's <code>placeholder</code> prop renders
147
+ skeletons in its value slots while loading, so the recipe composes a
148
+ faithful loading inspector from real chrome. The app owns the
149
+ loading lifecycle and which values are still unknown.
150
+ </p>
60
151
  </div>
61
- <section>
62
- <ListItem action="recipe-action" itemId="reassign" label="Reassign ticket" icon={icon(Inbox, 'inbox')} placeholder={p} />
63
- <ListItem action="recipe-action" itemId="watch" label="Watch for changes" placeholder={p} />
64
- </section>
65
- {p
66
- ? <StateBanner tone="info" title="" detail="" icon={icon(FileText, 'file-text')} placeholder />
67
- : <StateBanner tone="success" title="Up to date" detail="All checks passed on the latest revision." icon={icon(FileText, 'file-text')} />}
68
- <p class="kui-recipe__ownership kui-content-item">Each value-bearing component's <code>placeholder</code> 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.</p>
69
- </div>
70
- </section>;
152
+ </section>
153
+ );
71
154
  };
72
155
  return {
73
156
  render,
@@ -9,7 +9,10 @@ import type { RecipeController } from './types.js';
9
9
  * Copyable application boundary for a recipe. The caller owns one stable root
10
10
  * and retains the returned disposer for that root's lifetime.
11
11
  */
12
- export function mountRecipe(root: HTMLElement, controller: RecipeController): () => void {
12
+ export function mountRecipe(
13
+ root: HTMLElement,
14
+ controller: RecipeController,
15
+ ): () => void {
13
16
  const stopMount = mount(root, controller.render);
14
17
  const stopActions = delegateActions(root, 'click', {
15
18
  'recipe-action': (_event, element) => {
@@ -17,14 +20,32 @@ export function mountRecipe(root: HTMLElement, controller: RecipeController): ()
17
20
  controller.action(target.dataset.recipeCommand ?? '', target);
18
21
  },
19
22
  });
20
- const dispatchChange = (_event: Event, element: Element) => controller.change?.(element as HTMLElement);
21
- const stopChanges = delegate(root, 'change', 'wa-select, wa-input, wa-textarea', dispatchChange);
22
- const stopInputs = delegate(root, 'input', 'wa-input, wa-textarea', dispatchChange);
23
- const stopDialogs = delegate(root, 'wa-after-hide', 'wa-dialog', (_event, element) => controller.afterHide?.(element as HTMLElement));
23
+ const dispatchChange = (_event: Event, element: Element) =>
24
+ controller.change?.(element as HTMLElement);
25
+ const stopChanges = delegate(
26
+ root,
27
+ 'change',
28
+ 'wa-select, wa-input, wa-textarea',
29
+ dispatchChange,
30
+ );
31
+ const stopInputs = delegate(
32
+ root,
33
+ 'input',
34
+ 'wa-input, wa-textarea',
35
+ dispatchChange,
36
+ );
37
+ const stopDialogs = delegate(
38
+ root,
39
+ 'wa-after-hide',
40
+ 'wa-dialog',
41
+ (_event, element) => controller.afterHide?.(element as HTMLElement),
42
+ );
24
43
  const stopResize = wireResizableRegions(root, {
25
44
  onCommit: ({ id, size }) => controller.resize?.(id, size),
26
45
  });
27
- const stopNav = wireNavStack(root, { onBack: () => controller.action('nav-back', root) });
46
+ const stopNav = wireNavStack(root, {
47
+ onBack: () => controller.action('nav-back', root),
48
+ });
28
49
  const stopWire = controller.wire?.(root);
29
50
 
30
51
  let disposed = false;
@@ -14,13 +14,124 @@ import type { RecipeFactory } from './types.js';
14
14
  export const createRecipe: RecipeFactory = (announce) => {
15
15
  const selected = signal('inbox');
16
16
  const expanded = signal(true);
17
- const render = () => <aside class="kui-recipe recipe-sidebar kui-recipe__surface kui-pane" data-recipe="recipe-navigation-sidebar">
18
- <div class="recipe-sidebar__body kui-pane__content kui-content">
19
- <section><ListHeader label="Workspace" count={3} countLabel="3 workspaces" action="recipe-action" actionLabel="Add workspace item" actionIcon={<LucideIcon icon={Plus} name="plus" />} /><ListItem action="recipe-action" itemId="inbox" label="Inbox" icon={<LucideIcon icon={Inbox} name="inbox" />} trailing={<span>12</span>} selected={selected.value === 'inbox'} /><ListItem action="recipe-action" itemId="shared" label="Shared with me" icon={<LucideIcon icon={Users} name="users" />} selected={selected.value === 'shared'} /><ListItem action="recipe-action" itemId="drafts" label="Drafts without an icon" selected={selected.value === 'drafts'} /></section>
20
- <section><ListHeader label="Projects" toggle action="recipe-action" expanded={expanded.value} />{expanded.value && <><ListItem action="recipe-action" itemId="design" label="Design system rollout across desktop and tablet" icon={<LucideIcon icon={Folder} name="folder" />} selected={selected.value === 'design'} multiline /><ListItem action="recipe-action" itemId="archive" label="Archived" disabled title="Available to administrators" /><div class="kui-content-item"><strong>Quarterly goal</strong><p class="kui-recipe__muted">Ship accessible navigation patterns to every workspace.</p></div></>}</section>
21
- <p class="kui-recipe__ownership kui-content-item">The recipe owns pane, content-item, and toolbar geometry. The app owns routes, permissions, labels, and disclosure state.</p>
22
- </div>
23
- <footer class="recipe-sidebar__footer kui-pane__footer"><Toolbar label="Sidebar actions" divider={false} leading={<ToolbarControlGroup appearance="borderless" single><button type="button" aria-label="Add project" data-action="recipe-action" data-recipe-command="add"><LucideIcon icon={Plus} name="plus" /></button></ToolbarControlGroup>} trailing={<ToolbarControlGroup appearance="borderless" single><button type="button" aria-label="Workspace settings" data-action="recipe-action" data-recipe-command="settings"><LucideIcon icon={Settings} name="settings" /></button></ToolbarControlGroup>} /></footer>
24
- </aside>;
25
- return { render, action(command, element) { if (element.matches('.kui-list-header__toggle')) { expanded.value = !expanded.value; announce(expanded.value ? 'Projects expanded' : 'Projects collapsed'); return; } const id = element.dataset.itemId; if (id) selected.value = id; announce(id ? `Selected ${id}` : `${command} requested`); } };
17
+ const render = () => (
18
+ <aside
19
+ class="kui-recipe recipe-sidebar kui-recipe__surface kui-pane"
20
+ data-recipe="recipe-navigation-sidebar"
21
+ >
22
+ <div class="recipe-sidebar__body kui-pane__content kui-content">
23
+ <section>
24
+ <ListHeader
25
+ label="Workspace"
26
+ count={3}
27
+ countLabel="3 workspaces"
28
+ action="recipe-action"
29
+ actionLabel="Add workspace item"
30
+ actionIcon={<LucideIcon icon={Plus} name="plus" />}
31
+ />
32
+ <ListItem
33
+ action="recipe-action"
34
+ itemId="inbox"
35
+ label="Inbox"
36
+ icon={<LucideIcon icon={Inbox} name="inbox" />}
37
+ trailing={<span>12</span>}
38
+ selected={selected.value === 'inbox'}
39
+ />
40
+ <ListItem
41
+ action="recipe-action"
42
+ itemId="shared"
43
+ label="Shared with me"
44
+ icon={<LucideIcon icon={Users} name="users" />}
45
+ selected={selected.value === 'shared'}
46
+ />
47
+ <ListItem
48
+ action="recipe-action"
49
+ itemId="drafts"
50
+ label="Drafts without an icon"
51
+ selected={selected.value === 'drafts'}
52
+ />
53
+ </section>
54
+ <section>
55
+ <ListHeader
56
+ label="Projects"
57
+ toggle
58
+ action="recipe-action"
59
+ expanded={expanded.value}
60
+ />
61
+ {expanded.value && (
62
+ <>
63
+ <ListItem
64
+ action="recipe-action"
65
+ itemId="design"
66
+ label="Design system rollout across desktop and tablet"
67
+ icon={<LucideIcon icon={Folder} name="folder" />}
68
+ selected={selected.value === 'design'}
69
+ multiline
70
+ />
71
+ <ListItem
72
+ action="recipe-action"
73
+ itemId="archive"
74
+ label="Archived"
75
+ disabled
76
+ title="Available to administrators"
77
+ />
78
+ <div class="kui-content-item">
79
+ <strong>Quarterly goal</strong>
80
+ <p class="kui-recipe__muted">
81
+ Ship accessible navigation patterns to every workspace.
82
+ </p>
83
+ </div>
84
+ </>
85
+ )}
86
+ </section>
87
+ <p class="kui-recipe__ownership kui-content-item">
88
+ The recipe owns pane, content-item, and toolbar geometry. The app owns
89
+ routes, permissions, labels, and disclosure state.
90
+ </p>
91
+ </div>
92
+ <footer class="recipe-sidebar__footer kui-pane__footer">
93
+ <Toolbar
94
+ label="Sidebar actions"
95
+ divider={false}
96
+ leading={
97
+ <ToolbarControlGroup appearance="borderless" single>
98
+ <button
99
+ type="button"
100
+ aria-label="Add project"
101
+ data-action="recipe-action"
102
+ data-recipe-command="add"
103
+ >
104
+ <LucideIcon icon={Plus} name="plus" />
105
+ </button>
106
+ </ToolbarControlGroup>
107
+ }
108
+ trailing={
109
+ <ToolbarControlGroup appearance="borderless" single>
110
+ <button
111
+ type="button"
112
+ aria-label="Workspace settings"
113
+ data-action="recipe-action"
114
+ data-recipe-command="settings"
115
+ >
116
+ <LucideIcon icon={Settings} name="settings" />
117
+ </button>
118
+ </ToolbarControlGroup>
119
+ }
120
+ />
121
+ </footer>
122
+ </aside>
123
+ );
124
+ return {
125
+ render,
126
+ action(command, element) {
127
+ if (element.matches('.kui-list-header__toggle')) {
128
+ expanded.value = !expanded.value;
129
+ announce(expanded.value ? 'Projects expanded' : 'Projects collapsed');
130
+ return;
131
+ }
132
+ const id = element.dataset.itemId;
133
+ if (id) selected.value = id;
134
+ announce(id ? `Selected ${id}` : `${command} requested`);
135
+ },
136
+ };
26
137
  };
@@ -19,41 +19,83 @@ interface LibraryItem {
19
19
  }
20
20
 
21
21
  const ITEMS: LibraryItem[] = [
22
- { id: 'tokens', label: 'Design tokens', detail: 'Semantic color, spacing, and radius scales shared across every surface.' },
23
- { id: 'controls', label: 'Toolbar controls', detail: 'Control groups and segmented controls with their hover and pressed contracts.' },
24
- { id: 'layouts', label: 'App layouts', detail: 'Navigation stacks, split views, workbench, and bottom-tab scaffolds.' },
22
+ {
23
+ id: 'tokens',
24
+ label: 'Design tokens',
25
+ detail:
26
+ 'Semantic color, spacing, and radius scales shared across every surface.',
27
+ },
28
+ {
29
+ id: 'controls',
30
+ label: 'Toolbar controls',
31
+ detail:
32
+ 'Control groups and segmented controls with their hover and pressed contracts.',
33
+ },
34
+ {
35
+ id: 'layouts',
36
+ label: 'App layouts',
37
+ detail:
38
+ 'Navigation stacks, split views, workbench, and bottom-tab scaffolds.',
39
+ },
25
40
  ];
26
41
 
27
42
  export const createRecipe: RecipeFactory = (announce) => {
28
43
  const listView = (): NavStackView => ({
29
44
  key: 'library',
30
45
  title: 'Library',
31
- content: <div class="recipe-navstack__view kui-pane__content kui-content">
32
- <section>
33
- <ListHeader label="Components" />
34
- {ITEMS.map((item) => <ListItem action="recipe-action" itemId={item.id} label={item.label} icon={<LucideIcon icon={Folder} name="folder" />} trailing={<LucideIcon icon={ChevronRight} name="chevron-right" />} />)}
35
- </section>
36
- <p class="kui-recipe__ownership kui-content-item">The recipe owns the stack as a signal of views and pushes/pops it; `NavStack` renders the stack and `wireNavStack` slides the content and settles the chrome. The app owns selection, data, and routing.</p>
37
- </div>,
46
+ content: (
47
+ <div class="recipe-navstack__view kui-pane__content kui-content">
48
+ <section>
49
+ <ListHeader label="Components" />
50
+ {ITEMS.map((item) => (
51
+ <ListItem
52
+ action="recipe-action"
53
+ itemId={item.id}
54
+ label={item.label}
55
+ icon={<LucideIcon icon={Folder} name="folder" />}
56
+ trailing={<LucideIcon icon={ChevronRight} name="chevron-right" />}
57
+ />
58
+ ))}
59
+ </section>
60
+ <p class="kui-recipe__ownership kui-content-item">
61
+ The recipe owns the stack as a signal of views and pushes/pops it;
62
+ `NavStack` renders the stack and `wireNavStack` slides the content and
63
+ settles the chrome. The app owns selection, data, and routing.
64
+ </p>
65
+ </div>
66
+ ),
38
67
  });
39
68
 
40
69
  const detailView = (item: LibraryItem): NavStackView => ({
41
70
  key: item.id,
42
71
  title: item.label,
43
- content: <div class="recipe-navstack__view kui-pane__content kui-content">
44
- <div class="kui-content-item">
45
- <LucideIcon icon={FileText} name="file-text" />
46
- <strong>{item.label}</strong>
47
- <p class="kui-recipe__muted">{item.detail}</p>
72
+ content: (
73
+ <div class="recipe-navstack__view kui-pane__content kui-content">
74
+ <div class="kui-content-item">
75
+ <LucideIcon icon={FileText} name="file-text" />
76
+ <strong>{item.label}</strong>
77
+ <p class="kui-recipe__muted">{item.detail}</p>
78
+ </div>
48
79
  </div>
49
- </div>,
80
+ ),
50
81
  });
51
82
 
52
83
  const views = signal<NavStackView[]>([listView()]);
53
84
 
54
- const render = () => <section class="kui-recipe recipe-navstack kui-recipe__surface" data-recipe="recipe-navigation-stack">
55
- <div class="recipe-navstack__stage"><NavStack id="recipe-nav" label="Component library" views={views.value} /></div>
56
- </section>;
85
+ const render = () => (
86
+ <section
87
+ class="kui-recipe recipe-navstack kui-recipe__surface"
88
+ data-recipe="recipe-navigation-stack"
89
+ >
90
+ <div class="recipe-navstack__stage">
91
+ <NavStack
92
+ id="recipe-nav"
93
+ label="Component library"
94
+ views={views.value}
95
+ />
96
+ </div>
97
+ </section>
98
+ );
57
99
 
58
100
  return {
59
101
  render,
@@ -14,4 +14,6 @@ export interface RecipeController {
14
14
  wire?(root: HTMLElement): () => void;
15
15
  }
16
16
 
17
- export type RecipeFactory = (announce: (message: string) => void) => RecipeController;
17
+ export type RecipeFactory = (
18
+ announce: (message: string) => void,
19
+ ) => RecipeController;
@@ -7,6 +7,61 @@ import { StateBanner } from '@kerfjs/ui/state-banner';
7
7
  import type { RecipeFactory } from './types.js';
8
8
 
9
9
  export const createRecipe: RecipeFactory = (announce) => ({
10
- render: () => <section class="kui-recipe recipe-header kui-recipe__surface kui-content" data-recipe="recipe-workspace-header"><p class="recipe-header__context kui-inline-metadata kui-content-item"><span>Northstar workspace</span><span>·</span><span>Product planning</span></p><PanelHeader title="Accessibility readiness and responsive navigation rollout" titleId="recipe-workspace-title" actions={<div class="kui-control-cluster"><button class="kui-recipe__button" type="button" data-action="recipe-action" data-recipe-command="share">Share</button><button class="kui-recipe__button" type="button" data-action="recipe-action" data-recipe-command="more">More actions</button><button class="kui-recipe__button" data-primary="true" type="button" data-action="recipe-action" data-recipe-command="publish">Publish update</button></div>} /><StateBanner title="Ready for review" detail="All required checks passed 18 minutes ago." tone="success" /><p class="kui-recipe__ownership kui-content-item">The recipe owns page hierarchy and action relocation. The app owns authorization, command behavior, breadcrumbs, and product copy.</p></section>,
11
- action(command) { announce(`${command} requested`); },
10
+ render: () => (
11
+ <section
12
+ class="kui-recipe recipe-header kui-recipe__surface kui-content"
13
+ data-recipe="recipe-workspace-header"
14
+ >
15
+ <p class="recipe-header__context kui-inline-metadata kui-content-item">
16
+ <span>Northstar workspace</span>
17
+ <span>·</span>
18
+ <span>Product planning</span>
19
+ </p>
20
+ <PanelHeader
21
+ title="Accessibility readiness and responsive navigation rollout"
22
+ titleId="recipe-workspace-title"
23
+ actions={
24
+ <div class="kui-control-cluster">
25
+ <button
26
+ class="kui-recipe__button"
27
+ type="button"
28
+ data-action="recipe-action"
29
+ data-recipe-command="share"
30
+ >
31
+ Share
32
+ </button>
33
+ <button
34
+ class="kui-recipe__button"
35
+ type="button"
36
+ data-action="recipe-action"
37
+ data-recipe-command="more"
38
+ >
39
+ More actions
40
+ </button>
41
+ <button
42
+ class="kui-recipe__button"
43
+ data-primary="true"
44
+ type="button"
45
+ data-action="recipe-action"
46
+ data-recipe-command="publish"
47
+ >
48
+ Publish update
49
+ </button>
50
+ </div>
51
+ }
52
+ />
53
+ <StateBanner
54
+ title="Ready for review"
55
+ detail="All required checks passed 18 minutes ago."
56
+ tone="success"
57
+ />
58
+ <p class="kui-recipe__ownership kui-content-item">
59
+ The recipe owns page hierarchy and action relocation. The app owns
60
+ authorization, command behavior, breadcrumbs, and product copy.
61
+ </p>
62
+ </section>
63
+ ),
64
+ action(command) {
65
+ announce(`${command} requested`);
66
+ },
12
67
  });
@@ -1,34 +0,0 @@
1
- import { filterDataAttributes } from './chunk-7BR3DO2A.js';
2
- import { Skeleton } from './chunk-B24C4A6T.js';
3
- import { jsxs, jsx } from 'kerfjs/jsx-runtime';
4
-
5
- var PROTECTED_ROOT_DATA_ATTRIBUTES = /* @__PURE__ */ new Set([
6
- "data-component",
7
- "data-action",
8
- "data-tab-id",
9
- "data-selected",
10
- "data-tab-dragging",
11
- "data-tab-drop-position"
12
- ]);
13
- function CloseIcon() {
14
- return /* @__PURE__ */ jsxs("svg", { "aria-hidden": "true", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2.25", "stroke-linecap": "round", children: [
15
- /* @__PURE__ */ jsx("path", { d: "m7 7 10 10" }),
16
- /* @__PURE__ */ jsx("path", { d: "M17 7 7 17" })
17
- ] });
18
- }
19
- function AppTab({ id, name, selected = false, closable = true, draggable = false, leading, trailing, closeIcon, selectAction = "select-tab", closeAction = "close-tab", className = "", placeholder = false, rootAttributes = {} }) {
20
- const keyshortcuts = [closable ? "Delete Backspace" : "", draggable ? "Alt+Shift+ArrowLeft Alt+Shift+ArrowRight" : ""].filter(Boolean).join(" ");
21
- const extensionAttributes = filterDataAttributes(rootAttributes, PROTECTED_ROOT_DATA_ATTRIBUTES);
22
- return /* @__PURE__ */ jsxs("div", { ...extensionAttributes, class: `kui-app-tab ${className}`.trim(), "data-component": "app-tab", "data-tab-id": id, "data-selected": String(selected), "data-placeholder": placeholder ? "true" : void 0, draggable: placeholder ? "false" : draggable ? "true" : "false", "aria-busy": placeholder ? "true" : void 0, children: [
23
- closable && /* @__PURE__ */ jsx("button", { type: "button", tabindex: "-1", class: "kui-app-tab__close", "data-action": placeholder ? void 0 : closeAction, "data-tab-id": id, disabled: placeholder || void 0, "aria-label": `Close ${name}`, title: `Close ${name}`, children: /* @__PURE__ */ jsx("span", { class: "kui-app-tab__close-icon", "aria-hidden": "true", children: closeIcon ?? /* @__PURE__ */ jsx(CloseIcon, {}) }) }),
24
- /* @__PURE__ */ jsxs("button", { type: "button", class: "kui-app-tab__select", role: "tab", "aria-selected": String(selected), "aria-keyshortcuts": placeholder ? void 0 : keyshortcuts || void 0, "data-action": placeholder ? void 0 : selectAction, "data-tab-id": id, disabled: placeholder || void 0, tabindex: placeholder ? "-1" : selected ? "0" : "-1", children: [
25
- leading,
26
- /* @__PURE__ */ jsx("span", { class: "kui-app-tab__name", children: placeholder ? /* @__PURE__ */ jsx(Skeleton, { width: "7em" }) : name }),
27
- closable || trailing ? /* @__PURE__ */ jsx("span", { class: "kui-app-tab__trailing", children: trailing }) : void 0
28
- ] })
29
- ] });
30
- }
31
-
32
- export { AppTab };
33
-
34
- //# sourceMappingURL=chunk-2Z5TWHKQ.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/app-tab.tsx"],"names":[],"mappings":";;;;AAKA,IAAM,8BAAA,uBAAqC,GAAA,CAAI;AAAA,EAC7C,gBAAA;AAAA,EACA,aAAA;AAAA,EACA,aAAA;AAAA,EACA,eAAA;AAAA,EACA,mBAAA;AAAA,EACA;AACF,CAAC,CAAA;AA+BD,SAAS,SAAA,GAAY;AACnB,EAAA,uBAAO,IAAA,CAAC,KAAA,EAAA,EAAI,aAAA,EAAY,MAAA,EAAO,OAAA,EAAQ,WAAA,EAAY,IAAA,EAAK,MAAA,EAAO,MAAA,EAAO,cAAA,EAAe,cAAA,EAAa,MAAA,EAAO,kBAAe,OAAA,EAAQ,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,GAAE,YAAA,EAAa,CAAA;AAAA,oBAAO,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,YAAA,EAAa;AAAA,GAAA,EAAO,CAAA;AAC1L;AAEO,SAAS,MAAA,CAAO,EAAE,EAAA,EAAI,IAAA,EAAM,QAAA,GAAW,OAAO,QAAA,GAAW,IAAA,EAAM,SAAA,GAAY,KAAA,EAAO,OAAA,EAAS,QAAA,EAAU,WAAW,YAAA,GAAe,YAAA,EAAc,WAAA,GAAc,WAAA,EAAa,SAAA,GAAY,EAAA,EAAI,cAAc,KAAA,EAAO,cAAA,GAAiB,EAAC,EAAE,EAAgB;AACtP,EAAA,MAAM,YAAA,GAAe,CAAC,QAAA,GAAW,kBAAA,GAAqB,EAAA,EAAI,SAAA,GAAY,0CAAA,GAA6C,EAAE,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA,CAAE,KAAK,GAAG,CAAA;AAC/I,EAAA,MAAM,mBAAA,GAAsB,oBAAA,CAAqB,cAAA,EAAgB,8BAA8B,CAAA;AAC/F,EAAA,uBAAO,IAAA,CAAC,KAAA,EAAA,EAAK,GAAG,mBAAA,EAAqB,KAAA,EAAO,CAAA,YAAA,EAAe,SAAS,CAAA,CAAA,CAAG,IAAA,EAAK,EAAG,gBAAA,EAAe,SAAA,EAAU,eAAa,EAAA,EAAI,eAAA,EAAe,MAAA,CAAO,QAAQ,CAAA,EAAG,kBAAA,EAAkB,WAAA,GAAc,MAAA,GAAS,QAAW,SAAA,EAAW,WAAA,GAAc,OAAA,GAAU,SAAA,GAAY,MAAA,GAAS,OAAA,EAAS,WAAA,EAAW,WAAA,GAAc,SAAS,MAAA,EAC9S,QAAA,EAAA;AAAA,IAAA,QAAA,oBAAY,GAAA,CAAC,QAAA,EAAA,EAAO,IAAA,EAAK,QAAA,EAAS,UAAS,IAAA,EAAK,KAAA,EAAM,oBAAA,EAAqB,aAAA,EAAa,cAAc,MAAA,GAAY,WAAA,EAAa,aAAA,EAAa,EAAA,EAAI,UAAU,WAAA,IAAe,MAAA,EAAW,YAAA,EAAY,CAAA,MAAA,EAAS,IAAI,CAAA,CAAA,EAAI,KAAA,EAAO,CAAA,MAAA,EAAS,IAAI,IAAI,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,KAAA,EAAM,yBAAA,EAA0B,eAAY,MAAA,EAAQ,QAAA,EAAA,SAAA,oBAAa,GAAA,CAAC,SAAA,EAAA,EAAU,GAAG,CAAA,EAAO,CAAA;AAAA,oBACtU,IAAA,CAAC,QAAA,EAAA,EAAO,IAAA,EAAK,QAAA,EAAS,KAAA,EAAM,qBAAA,EAAsB,IAAA,EAAK,KAAA,EAAM,eAAA,EAAe,MAAA,CAAO,QAAQ,CAAA,EAAG,qBAAmB,WAAA,GAAc,MAAA,GAAY,YAAA,IAAgB,MAAA,EAAW,aAAA,EAAa,WAAA,GAAc,MAAA,GAAY,YAAA,EAAc,eAAa,EAAA,EAAI,QAAA,EAAU,WAAA,IAAe,MAAA,EAAW,QAAA,EAAU,WAAA,GAAc,IAAA,GAAO,QAAA,GAAW,MAAM,IAAA,EAC7T,QAAA,EAAA;AAAA,MAAA,OAAA;AAAA,sBAAQ,GAAA,CAAC,MAAA,EAAA,EAAK,KAAA,EAAM,mBAAA,EAAqB,QAAA,EAAA,WAAA,uBAAe,QAAA,EAAA,EAAS,KAAA,EAAM,KAAA,EAAM,CAAA,GAAK,IAAA,EAAK,CAAA;AAAA,MAAQ,YAAY,QAAA,mBAAW,GAAA,CAAC,UAAK,KAAA,EAAM,uBAAA,EAAyB,oBAAS,CAAA,GAAU;AAAA,KAAA,EACjL;AAAA,GAAA,EACF,CAAA;AACF","file":"chunk-2Z5TWHKQ.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport { filterDataAttributes } from './extension-attributes.js';\nimport { Skeleton } from './skeleton.js';\n\nconst PROTECTED_ROOT_DATA_ATTRIBUTES = new Set([\n 'data-component',\n 'data-action',\n 'data-tab-id',\n 'data-selected',\n 'data-tab-dragging',\n 'data-tab-drop-position',\n]);\n\ntype AppTabRootAttributes = Readonly<\n Record<`data-${string}`, string | undefined> & {\n 'data-component'?: never;\n 'data-action'?: never;\n 'data-tab-id'?: never;\n 'data-selected'?: never;\n 'data-tab-dragging'?: never;\n 'data-tab-drop-position'?: never;\n }\n>;\n\nexport interface AppTabProps {\n id: string;\n name: string;\n selected?: boolean;\n closable?: boolean;\n draggable?: boolean;\n leading?: SafeHtml;\n trailing?: SafeHtml;\n /** Decorative dormant content for the close button. Must not contain interactive descendants. */\n closeIcon?: SafeHtml;\n selectAction?: string;\n closeAction?: string;\n className?: string;\n /** Render as an unanimated loading skeleton, disabling select/close and dragging. */\n placeholder?: boolean;\n rootAttributes?: AppTabRootAttributes;\n}\n\nfunction CloseIcon() {\n return <svg aria-hidden=\"true\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.25\" stroke-linecap=\"round\"><path d=\"m7 7 10 10\"></path><path d=\"M17 7 7 17\"></path></svg>;\n}\n\nexport function AppTab({ id, name, selected = false, closable = true, draggable = false, leading, trailing, closeIcon, selectAction = 'select-tab', closeAction = 'close-tab', className = '', placeholder = false, rootAttributes = {} }: AppTabProps) {\n const keyshortcuts = [closable ? 'Delete Backspace' : '', draggable ? 'Alt+Shift+ArrowLeft Alt+Shift+ArrowRight' : ''].filter(Boolean).join(' ');\n const extensionAttributes = filterDataAttributes(rootAttributes, PROTECTED_ROOT_DATA_ATTRIBUTES);\n return <div {...extensionAttributes} class={`kui-app-tab ${className}`.trim()} data-component=\"app-tab\" data-tab-id={id} data-selected={String(selected)} data-placeholder={placeholder ? 'true' : undefined} draggable={placeholder ? 'false' : draggable ? 'true' : 'false'} aria-busy={placeholder ? 'true' : undefined}>\n {closable && <button type=\"button\" tabindex=\"-1\" class=\"kui-app-tab__close\" data-action={placeholder ? undefined : closeAction} data-tab-id={id} disabled={placeholder || undefined} aria-label={`Close ${name}`} title={`Close ${name}`}><span class=\"kui-app-tab__close-icon\" aria-hidden=\"true\">{closeIcon ?? <CloseIcon />}</span></button>}\n <button type=\"button\" class=\"kui-app-tab__select\" role=\"tab\" aria-selected={String(selected)} aria-keyshortcuts={placeholder ? undefined : keyshortcuts || undefined} data-action={placeholder ? undefined : selectAction} data-tab-id={id} disabled={placeholder || undefined} tabindex={placeholder ? '-1' : selected ? '0' : '-1'}>\n {leading}<span class=\"kui-app-tab__name\">{placeholder ? <Skeleton width=\"7em\" /> : name}</span>{closable || trailing ? <span class=\"kui-app-tab__trailing\">{trailing}</span> : undefined}\n </button>\n </div>;\n}\n"]}
@@ -1,19 +0,0 @@
1
- import { Skeleton } from './chunk-B24C4A6T.js';
2
- import { jsxs, jsx } from 'kerfjs/jsx-runtime';
3
-
4
- function ValueTableRow({ label, value, icon, className = "", placeholder = false }) {
5
- return /* @__PURE__ */ jsxs("div", { class: `kui-value-table__row ${className}`.trim(), "data-has-icon": String(Boolean(icon)), "data-placeholder": placeholder ? "true" : void 0, children: [
6
- /* @__PURE__ */ jsxs("dt", { children: [
7
- icon && /* @__PURE__ */ jsx("span", { class: "kui-value-table__icon", children: icon }),
8
- /* @__PURE__ */ jsx("span", { class: "kui-value-table__label", children: label })
9
- ] }),
10
- /* @__PURE__ */ jsx("dd", { children: placeholder ? /* @__PURE__ */ jsx(Skeleton, { width: "10em" }) : value })
11
- ] });
12
- }
13
- function ValueTable({ label, className = "", children }) {
14
- return /* @__PURE__ */ jsx("dl", { class: `kui-value-table ${className}`.trim(), "data-component": "value-table", "aria-label": label, children });
15
- }
16
-
17
- export { ValueTable, ValueTableRow };
18
-
19
- //# sourceMappingURL=chunk-37T3VNIZ.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/value-table-row.tsx","../src/value-table.tsx"],"names":["jsx"],"mappings":";;;AAaO,SAAS,aAAA,CAAc,EAAE,KAAA,EAAO,KAAA,EAAO,MAAM,SAAA,GAAY,EAAA,EAAI,WAAA,GAAc,KAAA,EAAM,EAAuB;AAC7G,EAAA,4BAAQ,KAAA,EAAA,EAAI,KAAA,EAAO,CAAA,qBAAA,EAAwB,SAAS,GAAG,IAAA,EAAK,EAAG,eAAA,EAAe,MAAA,CAAO,QAAQ,IAAI,CAAC,GAAG,kBAAA,EAAkB,WAAA,GAAc,SAAS,MAAA,EAC5I,QAAA,EAAA;AAAA,oBAAA,IAAA,CAAC,IAAA,EAAA,EACE,QAAA,EAAA;AAAA,MAAA,IAAA,oBAAQ,GAAA,CAAC,MAAA,EAAA,EAAK,KAAA,EAAM,uBAAA,EAAyB,QAAA,EAAA,IAAA,EAAK,CAAA;AAAA,sBACnD,GAAA,CAAC,MAAA,EAAA,EAAK,KAAA,EAAM,wBAAA,EAA0B,QAAA,EAAA,KAAA,EAAM;AAAA,KAAA,EAC9C,CAAA;AAAA,oBACA,GAAA,CAAC,QAAI,QAAA,EAAA,WAAA,mBAAc,GAAA,CAAC,YAAS,KAAA,EAAM,MAAA,EAAO,IAAK,KAAA,EAAM;AAAA,GAAA,EACvD,CAAA;AACF;ACXO,SAAS,WAAW,EAAE,KAAA,EAAO,SAAA,GAAY,EAAA,EAAI,UAAS,EAAoB;AAC/E,EAAA,uBAAOA,GAAAA,CAAC,IAAA,EAAA,EAAG,KAAA,EAAO,CAAA,gBAAA,EAAmB,SAAS,CAAA,CAAA,CAAG,IAAA,EAAK,EAAG,gBAAA,EAAe,aAAA,EAAc,YAAA,EAAY,OAAQ,QAAA,EAAS,CAAA;AACrH","file":"chunk-37T3VNIZ.js","sourcesContent":["import type { SafeHtml } from 'kerfjs';\n\nimport { Skeleton } from './skeleton.js';\n\nexport interface ValueTableRowProps {\n label: string | SafeHtml;\n value: string | SafeHtml;\n icon?: SafeHtml;\n className?: string;\n /** Render the value as an unanimated loading skeleton, keeping the field label. */\n placeholder?: boolean;\n}\n\nexport function ValueTableRow({ label, value, icon, className = '', placeholder = false }: ValueTableRowProps) {\n return <div class={`kui-value-table__row ${className}`.trim()} data-has-icon={String(Boolean(icon))} data-placeholder={placeholder ? 'true' : undefined}>\n <dt>\n {icon && <span class=\"kui-value-table__icon\">{icon}</span>}\n <span class=\"kui-value-table__label\">{label}</span>\n </dt>\n <dd>{placeholder ? <Skeleton width=\"10em\" /> : value}</dd>\n </div>;\n}\n","import type { SafeHtml } from 'kerfjs';\n\nexport { ValueTableRow, type ValueTableRowProps } from './value-table-row.js';\n\nexport interface ValueTableProps {\n label: string;\n className?: string;\n children: SafeHtml | readonly SafeHtml[];\n}\n\nexport function ValueTable({ label, className = '', children }: ValueTableProps) {\n return <dl class={`kui-value-table ${className}`.trim()} data-component=\"value-table\" aria-label={label}>{children}</dl>;\n}\n"]}
@@ -1,10 +0,0 @@
1
- import { jsx } from 'kerfjs/jsx-runtime';
2
-
3
- // src/loading-spinner.tsx
4
- function LoadingSpinner({ className = "", label }) {
5
- return /* @__PURE__ */ jsx("svg", { class: `kui-loading-spinner ${className}`.trim(), "data-component": "loading-spinner", viewBox: "0 0 24 24", role: label ? "img" : void 0, "aria-label": label, "aria-hidden": label ? void 0 : "true", children: /* @__PURE__ */ jsx("path", { d: "M12,4a8,8,0,0,1,7.89,6.7A1.53,1.53,0,0,0,21.38,12h0a1.5,1.5,0,0,0,1.48-1.75,11,11,0,0,0-21.72,0A1.5,1.5,0,0,0,2.62,12h0a1.53,1.53,0,0,0,1.49-1.3A8,8,0,0,1,12,4Z" }) });
6
- }
7
-
8
- export { LoadingSpinner };
9
-
10
- //# sourceMappingURL=chunk-55DATV3A.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/loading-spinner.tsx"],"names":[],"mappings":";;;AAMO,SAAS,cAAA,CAAe,EAAE,SAAA,GAAY,EAAA,EAAI,OAAM,EAAwB;AAC7E,EAAA,uBAAO,GAAA,CAAC,KAAA,EAAA,EAAI,KAAA,EAAO,CAAA,oBAAA,EAAuB,SAAS,CAAA,CAAA,CAAG,IAAA,EAAK,EAAG,gBAAA,EAAe,iBAAA,EAAkB,OAAA,EAAQ,WAAA,EAAY,IAAA,EAAM,QAAQ,KAAA,GAAQ,MAAA,EAAW,YAAA,EAAY,KAAA,EAAO,aAAA,EAAa,KAAA,GAAQ,MAAA,GAAY,MAAA,EAAQ,QAAA,kBAAA,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,kKAAA,EAAmK,CAAA,EAAO,CAAA;AACpY","file":"chunk-55DATV3A.js","sourcesContent":["export interface LoadingSpinnerProps {\n className?: string;\n label?: string;\n}\n\n/** Stable viewBox-centered progress ring based on svg-spinners' MIT-licensed 180-ring. */\nexport function LoadingSpinner({ className = '', label }: LoadingSpinnerProps) {\n return <svg class={`kui-loading-spinner ${className}`.trim()} data-component=\"loading-spinner\" viewBox=\"0 0 24 24\" role={label ? 'img' : undefined} aria-label={label} aria-hidden={label ? undefined : 'true'}><path d=\"M12,4a8,8,0,0,1,7.89,6.7A1.53,1.53,0,0,0,21.38,12h0a1.5,1.5,0,0,0,1.48-1.75,11,11,0,0,0-21.72,0A1.5,1.5,0,0,0,2.62,12h0a1.53,1.53,0,0,0,1.49-1.3A8,8,0,0,1,12,4Z\"></path></svg>;\n}\n"]}