@kerfjs/ui 5.0.0-beta.23 → 5.0.0-beta.25

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 (288) hide show
  1. package/README.md +45 -23
  2. package/ai/application-ui-diagnostic-ids-v1.json +3 -0
  3. package/ai/application-ui-profile.defaults.json +1 -1
  4. package/ai/compile-time-contracts-v1.json +5 -12
  5. package/ai/component-catalog-v2-overrides.json +12 -49
  6. package/ai/component-catalog-v2.d.ts +1 -0
  7. package/ai/component-catalog-v2.json +458 -123
  8. package/ai/component-catalog-v2.schema.json +2 -1
  9. package/ai/component-catalog.json +658 -195
  10. package/ai/public-api-signatures-v1.md +160 -80
  11. package/ai/skill.md +22 -22
  12. package/ai/webawesome-jsx-signatures-v1.md +2 -1
  13. package/analyzer/cli.mjs +5 -2
  14. package/analyzer/index.d.mts +1 -0
  15. package/analyzer/index.mjs +117 -10
  16. package/dist/app-tab.d.ts +10 -2
  17. package/dist/app-tab.js +1 -1
  18. package/dist/browser/list-action-row.js +1 -0
  19. package/dist/browser/list-item.js +1 -0
  20. package/dist/browser/list.js +3 -0
  21. package/dist/browser/surface-scaffold.js +3 -0
  22. package/dist/catalog.d.ts +8 -4
  23. package/dist/catalog.js +21 -11
  24. package/dist/catalog.js.map +1 -1
  25. package/dist/{chunk-ELSJX4W7.js → chunk-4EF2CMYS.js} +25 -6
  26. package/dist/chunk-4EF2CMYS.js.map +1 -0
  27. package/dist/{chunk-OHU6CI22.js → chunk-B3A3IVO5.js} +2 -2
  28. package/dist/{chunk-OHU6CI22.js.map → chunk-B3A3IVO5.js.map} +1 -1
  29. package/dist/{chunk-K57KRAOV.js → chunk-FRVS5RFM.js} +24 -6
  30. package/dist/chunk-FRVS5RFM.js.map +1 -0
  31. package/dist/{chunk-DSNIYOZ3.js → chunk-GWEAPEZI.js} +16 -3
  32. package/dist/chunk-GWEAPEZI.js.map +1 -0
  33. package/dist/chunk-HP2B2L26.js +102 -0
  34. package/dist/chunk-HP2B2L26.js.map +1 -0
  35. package/dist/{chunk-OZWU5ZPZ.js → chunk-IJBSZ4NX.js} +2 -2
  36. package/dist/{chunk-OZWU5ZPZ.js.map → chunk-IJBSZ4NX.js.map} +1 -1
  37. package/dist/chunk-J5BFYY7Q.js +35 -0
  38. package/dist/chunk-J5BFYY7Q.js.map +1 -0
  39. package/dist/{chunk-GP5DP5DL.js → chunk-JFGXQBIP.js} +85 -24
  40. package/dist/chunk-JFGXQBIP.js.map +1 -0
  41. package/dist/{chunk-QQFJMRIB.js → chunk-KWWR5VMS.js} +2 -2
  42. package/dist/{chunk-QQFJMRIB.js.map → chunk-KWWR5VMS.js.map} +1 -1
  43. package/dist/chunk-OBLTAKSX.js +43 -0
  44. package/dist/chunk-OBLTAKSX.js.map +1 -0
  45. package/dist/{chunk-PIDTEQ3U.js → chunk-OT6RPYAP.js} +17 -3
  46. package/dist/chunk-OT6RPYAP.js.map +1 -0
  47. package/dist/{chunk-W7YD6E4N.js → chunk-R7ZWUN64.js} +2 -2
  48. package/dist/{chunk-W7YD6E4N.js.map → chunk-R7ZWUN64.js.map} +1 -1
  49. package/dist/{chunk-PZQVSDLH.js → chunk-RKVQEH4J.js} +1 -1
  50. package/dist/chunk-RKVQEH4J.js.map +1 -0
  51. package/dist/{chunk-7L6EHUMV.js → chunk-SYDMYBPG.js} +3 -3
  52. package/dist/chunk-SYDMYBPG.js.map +1 -0
  53. package/dist/{chunk-W4CXQYSG.js → chunk-TB6DY7H5.js} +3 -1
  54. package/dist/chunk-TB6DY7H5.js.map +1 -0
  55. package/dist/{chunk-AASLYRGE.js → chunk-UKKSMZYT.js} +18 -7
  56. package/dist/chunk-UKKSMZYT.js.map +1 -0
  57. package/dist/{chunk-BBRXX6PF.js → chunk-VCE4MPVE.js} +26 -4
  58. package/dist/chunk-VCE4MPVE.js.map +1 -0
  59. package/dist/{chunk-VLYV65LK.js → chunk-W5L2JSBY.js} +5 -3
  60. package/dist/chunk-W5L2JSBY.js.map +1 -0
  61. package/dist/{chunk-5VTB2BKP.js → chunk-WNWD54GR.js} +16 -2
  62. package/dist/chunk-WNWD54GR.js.map +1 -0
  63. package/dist/{chunk-M7JBER5U.js → chunk-X2U3QJCJ.js} +8 -2
  64. package/dist/chunk-X2U3QJCJ.js.map +1 -0
  65. package/dist/{chunk-DPDBVKNA.js → chunk-YMKH5XTF.js} +5 -3
  66. package/dist/chunk-YMKH5XTF.js.map +1 -0
  67. package/dist/collapsible-panel.d.ts +9 -1
  68. package/dist/collapsible-panel.js +36 -15
  69. package/dist/collapsible-panel.js.map +1 -1
  70. package/dist/divider-sides-267FA7sY.d.ts +4 -0
  71. package/dist/index.d.ts +5 -3
  72. package/dist/index.js +20 -19
  73. package/dist/list-action-row.d.ts +11 -1
  74. package/dist/list-action-row.js +2 -1
  75. package/dist/list-header.d.ts +15 -2
  76. package/dist/list-header.js +1 -1
  77. package/dist/list-item.d.ts +12 -1
  78. package/dist/list-item.js +2 -1
  79. package/dist/list.d.ts +19 -0
  80. package/dist/list.js +3 -0
  81. package/dist/list.js.map +1 -0
  82. package/dist/nav-stack.js +1 -1
  83. package/dist/resizable-region.d.ts +19 -2
  84. package/dist/resizable-region.js +1 -1
  85. package/dist/segmented-control.js +1 -1
  86. package/dist/select.d.ts +12 -1
  87. package/dist/select.js +1 -1
  88. package/dist/skeleton.d.ts +1 -1
  89. package/dist/skeleton.js +1 -1
  90. package/dist/split-view.js +2 -2
  91. package/dist/state-banner.d.ts +4 -2
  92. package/dist/state-banner.js +1 -1
  93. package/dist/styles/app-tab.css +26 -0
  94. package/dist/styles/catalog.css +8 -2
  95. package/dist/styles/collapsible-panel.css +66 -4
  96. package/dist/styles/list-action-row.css +64 -0
  97. package/dist/styles/list-header.css +32 -0
  98. package/dist/styles/list-item.css +45 -6
  99. package/dist/styles/list.css +43 -0
  100. package/dist/styles/resizable-region.css +132 -0
  101. package/dist/styles/select.css +68 -0
  102. package/dist/styles/state-banner.css +32 -1
  103. package/dist/styles/styles.css +2 -1
  104. package/dist/styles/sunken-panel.css +4 -0
  105. package/dist/styles/surface-scaffold.css +51 -0
  106. package/dist/styles/tab-bar.css +24 -0
  107. package/dist/styles/toolbar-control-group.css +73 -1
  108. package/dist/styles/toolbar-text.css +1 -1
  109. package/dist/styles/toolbar.css +38 -2
  110. package/dist/styles/webawesome.css +12 -0
  111. package/dist/styles/workbench.css +89 -0
  112. package/dist/sunken-panel.d.ts +5 -2
  113. package/dist/sunken-panel.js +1 -1
  114. package/dist/surface-scaffold.d.ts +25 -0
  115. package/dist/surface-scaffold.js +3 -0
  116. package/dist/surface-scaffold.js.map +1 -0
  117. package/dist/tab-bar.d.ts +11 -2
  118. package/dist/tab-bar.js +1 -1
  119. package/dist/toolbar-control-group.d.ts +16 -2
  120. package/dist/toolbar-control-group.js +1 -1
  121. package/dist/toolbar-text.js +1 -1
  122. package/dist/toolbar.d.ts +5 -3
  123. package/dist/toolbar.js +1 -1
  124. package/dist/value-table.js +1 -1
  125. package/dist/webawesome.d.ts +1 -0
  126. package/dist/wire-catalog.d.ts +4 -2
  127. package/dist/wire-catalog.js +95 -36
  128. package/dist/wire-catalog.js.map +1 -1
  129. package/dist/wire-resizable-regions.js +1 -1
  130. package/dist/wire-sidebar.d.ts +6 -1
  131. package/dist/wire-sidebar.js +27 -8
  132. package/dist/wire-sidebar.js.map +1 -1
  133. package/dist/wire-tab-bars.js +1 -1
  134. package/dist/wire-token-search-fields.d.ts +1 -1
  135. package/dist/wire-token-search-fields.js +1 -1
  136. package/dist/workbench.d.ts +8 -0
  137. package/dist/workbench.js +42 -0
  138. package/dist/workbench.js.map +1 -1
  139. package/docs/accessibility.md +67 -15
  140. package/docs/catalog.md +17 -12
  141. package/docs/collapsible-panel.md +7 -0
  142. package/docs/component-contract.md +19 -9
  143. package/docs/component-selection.md +65 -31
  144. package/docs/design/templates/empty-state/filtered-dark.svg +1 -1
  145. package/docs/design/templates/empty-state/filtered.svg +1 -1
  146. package/docs/design/templates/empty-state/with-action-dark.svg +1 -1
  147. package/docs/design/templates/empty-state/with-action.svg +1 -1
  148. package/docs/design/templates/empty-state-dark.svg +1 -7
  149. package/docs/design/templates/empty-state.svg +1 -7
  150. package/docs/design/templates/list/compact-dark.svg +1 -0
  151. package/docs/design/templates/list/compact.svg +1 -0
  152. package/docs/design/templates/list/stack-dark.svg +1 -0
  153. package/docs/design/templates/list/stack.svg +1 -0
  154. package/docs/design/templates/list-action-row/default-dark.svg +1 -1
  155. package/docs/design/templates/list-action-row/default.svg +1 -1
  156. package/docs/design/templates/list-action-row/selected-dark.svg +1 -1
  157. package/docs/design/templates/list-action-row/selected.svg +1 -1
  158. package/docs/design/templates/list-action-row-dark.svg +1 -7
  159. package/docs/design/templates/list-action-row.svg +1 -7
  160. package/docs/design/templates/list-dark.svg +1 -0
  161. package/docs/design/templates/list-header/action-dark.svg +1 -1
  162. package/docs/design/templates/list-header/action.svg +1 -1
  163. package/docs/design/templates/list-header/toggle-collapsed-dark.svg +1 -1
  164. package/docs/design/templates/list-header/toggle-collapsed.svg +1 -1
  165. package/docs/design/templates/list-header/toggle-expanded-dark.svg +1 -1
  166. package/docs/design/templates/list-header/toggle-expanded.svg +1 -1
  167. package/docs/design/templates/list-header-dark.svg +1 -11
  168. package/docs/design/templates/list-header.svg +1 -11
  169. package/docs/design/templates/list-item/default-dark.svg +1 -1
  170. package/docs/design/templates/list-item/default.svg +1 -1
  171. package/docs/design/templates/list-item/multiline-dark.svg +1 -1
  172. package/docs/design/templates/list-item/multiline.svg +1 -1
  173. package/docs/design/templates/list-item/selected-dark.svg +1 -1
  174. package/docs/design/templates/list-item/selected.svg +1 -1
  175. package/docs/design/templates/list-item/trailing-dark.svg +1 -1
  176. package/docs/design/templates/list-item/trailing.svg +1 -1
  177. package/docs/design/templates/list-item-dark.svg +1 -11
  178. package/docs/design/templates/list-item.svg +1 -11
  179. package/docs/design/templates/list.svg +1 -0
  180. package/docs/design/templates/segmented-control-dark.svg +1 -7
  181. package/docs/design/templates/segmented-control.svg +1 -7
  182. package/docs/design/templates/skeleton-dark.svg +1 -9
  183. package/docs/design/templates/skeleton.svg +1 -9
  184. package/docs/design/templates/state-banner/danger-dark.svg +1 -1
  185. package/docs/design/templates/state-banner/danger.svg +1 -1
  186. package/docs/design/templates/state-banner/info-badge-dark.svg +1 -0
  187. package/docs/design/templates/state-banner/info-badge.svg +1 -0
  188. package/docs/design/templates/state-banner/info-dark.svg +1 -1
  189. package/docs/design/templates/state-banner/info.svg +1 -1
  190. package/docs/design/templates/state-banner/success-dark.svg +1 -1
  191. package/docs/design/templates/state-banner/success.svg +1 -1
  192. package/docs/design/templates/state-banner/warning-dark.svg +1 -1
  193. package/docs/design/templates/state-banner/warning.svg +1 -1
  194. package/docs/design/templates/state-banner-dark.svg +1 -11
  195. package/docs/design/templates/state-banner.svg +1 -11
  196. package/docs/design/templates/tab-bar/workspace-tabs-dark.svg +1 -1
  197. package/docs/design/templates/tab-bar/workspace-tabs.svg +1 -1
  198. package/docs/design/templates/tab-bar-dark.svg +1 -5
  199. package/docs/design/templates/tab-bar.svg +1 -5
  200. package/docs/design/templates/token-search-field/empty-dark.svg +1 -1
  201. package/docs/design/templates/token-search-field/empty.svg +1 -1
  202. package/docs/design/templates/token-search-field/tokens-dark.svg +1 -1
  203. package/docs/design/templates/token-search-field/tokens.svg +1 -1
  204. package/docs/design/templates/token-search-field-dark.svg +1 -7
  205. package/docs/design/templates/token-search-field.svg +1 -7
  206. package/docs/design/templates/toolbar/title-and-actions-dark.svg +1 -1
  207. package/docs/design/templates/toolbar/title-and-actions.svg +1 -1
  208. package/docs/design/templates/toolbar-control-group/borderless-single-dark.svg +1 -1
  209. package/docs/design/templates/toolbar-control-group/borderless-single.svg +1 -1
  210. package/docs/design/templates/toolbar-control-group/icon-buttons-dark.svg +1 -1
  211. package/docs/design/templates/toolbar-control-group/icon-buttons.svg +1 -1
  212. package/docs/design/templates/toolbar-control-group/push-buttons-dark.svg +1 -1
  213. package/docs/design/templates/toolbar-control-group/push-buttons.svg +1 -1
  214. package/docs/design/templates/toolbar-control-group/with-text-dark.svg +1 -1
  215. package/docs/design/templates/toolbar-control-group/with-text.svg +1 -1
  216. package/docs/design/templates/toolbar-control-group-dark.svg +1 -11
  217. package/docs/design/templates/toolbar-control-group.svg +1 -11
  218. package/docs/design/templates/toolbar-dark.svg +1 -5
  219. package/docs/design/templates/toolbar-text-dark.svg +1 -9
  220. package/docs/design/templates/toolbar-text.svg +1 -9
  221. package/docs/design/templates/toolbar.svg +1 -5
  222. package/docs/design/templates/value-table/details-dark.svg +1 -1
  223. package/docs/design/templates/value-table/details.svg +1 -1
  224. package/docs/design/templates/value-table-dark.svg +1 -5
  225. package/docs/design/templates/value-table.svg +1 -5
  226. package/docs/design/templates.md +29 -20
  227. package/docs/examples/component-catalog-extension-v2.json +3 -6
  228. package/docs/examples/component-catalog-extension.json +1 -1
  229. package/docs/layout.md +7 -9
  230. package/docs/recipes.md +8 -7
  231. package/docs/sunken-panel.md +11 -1
  232. package/docs/surface-scaffold.md +17 -0
  233. package/docs/type-contracts.md +11 -10
  234. package/docs/ui-analyzer.md +19 -1
  235. package/docs/ui-doctor.md +7 -5
  236. package/docs/ux-demo.md +6 -3
  237. package/docs/webawesome-theme.md +4 -1
  238. package/docs/workbench.md +49 -2
  239. package/doctor/eslint-diagnostics.d.mts +16 -0
  240. package/doctor/eslint-diagnostics.mjs +17 -0
  241. package/doctor/index.mjs +21 -3
  242. package/llms.txt +33 -11
  243. package/package.json +14 -8
  244. package/traversal-exclusions.mjs +7 -1
  245. package/ux-demo/recipes/app-shell.tsx +36 -23
  246. package/ux-demo/recipes/collapsible-sidebar.tsx +23 -17
  247. package/ux-demo/recipes/composer-form.tsx +15 -6
  248. package/ux-demo/recipes/list-detail-dialog.tsx +31 -15
  249. package/ux-demo/recipes/list-workspace-states.tsx +16 -7
  250. package/ux-demo/recipes/loading-inspector.tsx +39 -18
  251. package/ux-demo/recipes/navigation-sidebar.tsx +1 -1
  252. package/ux-demo/recipes/recipes.css +7 -2
  253. package/ux-demo/recipes/workspace-header.tsx +17 -7
  254. package/dist/browser/panel-header.js +0 -7
  255. package/dist/chunk-5VTB2BKP.js.map +0 -1
  256. package/dist/chunk-7L6EHUMV.js.map +0 -1
  257. package/dist/chunk-AASLYRGE.js.map +0 -1
  258. package/dist/chunk-BBRXX6PF.js.map +0 -1
  259. package/dist/chunk-DPDBVKNA.js.map +0 -1
  260. package/dist/chunk-DSNIYOZ3.js.map +0 -1
  261. package/dist/chunk-ELSJX4W7.js.map +0 -1
  262. package/dist/chunk-GP5DP5DL.js.map +0 -1
  263. package/dist/chunk-K57KRAOV.js.map +0 -1
  264. package/dist/chunk-M7JBER5U.js.map +0 -1
  265. package/dist/chunk-NENBUYX5.js +0 -79
  266. package/dist/chunk-NENBUYX5.js.map +0 -1
  267. package/dist/chunk-PIDTEQ3U.js.map +0 -1
  268. package/dist/chunk-PZQVSDLH.js.map +0 -1
  269. package/dist/chunk-RYRIFZCT.js +0 -58
  270. package/dist/chunk-RYRIFZCT.js.map +0 -1
  271. package/dist/chunk-VLYV65LK.js.map +0 -1
  272. package/dist/chunk-W4CXQYSG.js.map +0 -1
  273. package/dist/panel-header.d.ts +0 -42
  274. package/dist/panel-header.js +0 -7
  275. package/dist/panel-header.js.map +0 -1
  276. package/dist/styles/panel-header.css +0 -64
  277. package/docs/design/templates/panel-header/icon-actions-dark.svg +0 -1
  278. package/docs/design/templates/panel-header/icon-actions.svg +0 -1
  279. package/docs/design/templates/panel-header/icon-summary-actions-dark.svg +0 -1
  280. package/docs/design/templates/panel-header/icon-summary-actions.svg +0 -1
  281. package/docs/design/templates/panel-header/no-icon-dark.svg +0 -1
  282. package/docs/design/templates/panel-header/no-icon.svg +0 -1
  283. package/docs/design/templates/panel-header/page-heading-dark.svg +0 -1
  284. package/docs/design/templates/panel-header/page-heading.svg +0 -1
  285. package/docs/design/templates/panel-header/title-only-dark.svg +0 -1
  286. package/docs/design/templates/panel-header/title-only.svg +0 -1
  287. package/docs/design/templates/panel-header-dark.svg +0 -13
  288. package/docs/design/templates/panel-header.svg +0 -13
@@ -5,3 +5,20 @@ export function isForeignRuleDefinitionDiagnostic(item) {
5
5
  item.message === `Definition for rule '${item.ruleId}' was not found.`
6
6
  );
7
7
  }
8
+
9
+ export function projectConsumerCoreConfig(config, file) {
10
+ const rules = Object.fromEntries(
11
+ Object.entries(config?.rules ?? {}).filter(
12
+ ([ruleId]) => !ruleId.includes('/'),
13
+ ),
14
+ );
15
+ const linterOptions = config?.linterOptions
16
+ ? { ...config.linterOptions }
17
+ : undefined;
18
+ if (Object.keys(rules).length === 0 && !linterOptions) return undefined;
19
+ return {
20
+ files: [file],
21
+ ...(Object.keys(rules).length > 0 ? { rules } : {}),
22
+ ...(linterOptions ? { linterOptions } : {}),
23
+ };
24
+ }
package/doctor/index.mjs CHANGED
@@ -23,8 +23,14 @@ import { createRequire } from 'node:module';
23
23
  import { loadApplicationUiProfile } from '../ai/application-ui-profile.mjs';
24
24
  import { analyzeUiProject, UI_ANALYSIS_RULES } from '../analyzer/index.mjs';
25
25
  import { evaluateUi, UI_EVALUATION_RULES } from '../evaluator/index.mjs';
26
- import { isForeignRuleDefinitionDiagnostic } from './eslint-diagnostics.mjs';
27
- import { isUiTraversalExcluded } from '../traversal-exclusions.mjs';
26
+ import {
27
+ isForeignRuleDefinitionDiagnostic,
28
+ projectConsumerCoreConfig,
29
+ } from './eslint-diagnostics.mjs';
30
+ import {
31
+ isUiTraversalExcluded,
32
+ UI_TRAVERSAL_ESLINT_IGNORES,
33
+ } from '../traversal-exclusions.mjs';
28
34
 
29
35
  export const UI_DOCTOR_SCHEMA_VERSION = 1;
30
36
  export const UI_DOCTOR_EXIT = Object.freeze({
@@ -847,7 +853,7 @@ async function runEslint({
847
853
  },
848
854
  },
849
855
  };
850
- const configs = [{ ignores: ['**/.claude/worktrees/**'] }, base];
856
+ const configs = [{ ignores: UI_TRAVERSAL_ESLINT_IGNORES }, base];
851
857
  if (usesTypeScript) {
852
858
  const parserModule = await importFrom(
853
859
  packageRoot,
@@ -866,6 +872,18 @@ async function runEslint({
866
872
  });
867
873
  }
868
874
  configs.push(preset);
875
+ const consumerEslint = new ESLint({ cwd: packageRoot });
876
+ if (await consumerEslint.findConfigFile()) {
877
+ const consumerCoreConfigs = await Promise.all(
878
+ inputs.map(async (file) =>
879
+ projectConsumerCoreConfig(
880
+ await consumerEslint.calculateConfigForFile(file),
881
+ portablePath(packageRoot, file),
882
+ ),
883
+ ),
884
+ );
885
+ configs.push(...consumerCoreConfigs.filter(Boolean));
886
+ }
869
887
  const eslint = new ESLint({
870
888
  cwd: packageRoot,
871
889
  overrideConfigFile: true,
package/llms.txt CHANGED
@@ -52,7 +52,9 @@ maintain a central style list. Configure JSX with `"jsxImportSource": "kerfjs"`.
52
52
  6. **Before calling an integration complete**, run
53
53
  [`kerf-ui-doctor`](./docs/ui-doctor.md). Its portable JSON report merges
54
54
  profile/catalog, TypeScript, Kerf ESLint, and static analyzer diagnostics;
55
- repair source-located errors until exit 0. Use full mode for release gates.
55
+ repair source-located errors until exit 0. Use full mode for release gates;
56
+ generated `dist`/`coverage`, dependency, cache, evidence, and nested-worktree
57
+ directories are excluded consistently from every static stage.
56
58
  [`kerf-ui-analyze`](./docs/ui-analyzer.md) remains available when only static
57
59
  layout diagnostics are wanted; its review findings are a bounded human/AI
58
60
  review queue rather than an objective aesthetic score.
@@ -76,12 +78,18 @@ maintain a central style list. Configure JSX with `"jsxImportSource": "kerfjs"`.
76
78
  own the geometry (8px inline margin + 1px border + 8px padding). Do not add a
77
79
  container padding on top of a content-item's own margin — pick one owner. Use
78
80
  `.kui-content` for 24px major vertical rhythm.
81
+ - **Use `List` for vertical layout.** It supplies a stretch-aligned column plus
82
+ optional standard/custom `gap`, `flex`, vertical scrolling, and canonical
83
+ `dividerSides` (`t`/`r`/`b`/`l` order). It adds no list semantics; children own
84
+ those, and only one bounded region should own scrolling.
79
85
  - **Keep Web Awesome on the shared inset tiers.** `webawesome.css` uses
80
86
  `--kui-wa-control-inset` (8px controls/items) and
81
87
  `--kui-wa-surface-margin` / `--kui-wa-surface-inset` (8px around/inside
82
88
  Accordion, Card, Details, Callout, and Include), while
83
- `--kui-wa-container-inset` keeps Tab Panel at 16px. Override the tier at the
84
- narrowest useful scope instead of restyling individual shadow parts.
89
+ `--kui-wa-container-inset` keeps Tab Panel at 16px. Dialog body and footer use
90
+ the surface (8px) and container (16px) tiers respectively, independent of the
91
+ dialog's shared `--spacing`. Override the tier at the narrowest useful scope
92
+ instead of restyling individual shadow parts.
85
93
  Checkbox and Radio Group option regions also receive the shared 8px inline
86
94
  outer inset because those groups have no bordered field shell. The Color
87
95
  Picker trigger receives the same inset for the same unbordered geometry.
@@ -91,6 +99,11 @@ maintain a central style list. Configure JSX with `"jsxImportSource": "kerfjs"`.
91
99
  with field values at the shared 9px border-plus-padding inset. OTP Input's
92
100
  label uses the same uppercase xs/650 treatment and its label and hint share
93
101
  that 9px alignment.
102
+ - `Select` requires a visible `label` or an `ariaLabel` for a visually hidden
103
+ accessible name. The package names the internal combobox, including custom
104
+ selected content; consumers do not need shadow-DOM naming workarounds.
105
+ Use `hint` for supporting text below the control and `placeholderText` only
106
+ for the empty value inside it; loading placeholders retain the visible hint.
94
107
  - **Trust the defaults.** Render a control at its natural size and color (a
95
108
  `LucideIcon` is 24px); if it looks wrong, fix the surrounding layout, not the
96
109
  control. Never force a component's width/height to size it — that leaves a halo
@@ -105,10 +118,11 @@ maintain a central style list. Configure JSX with `"jsxImportSource": "kerfjs"`.
105
118
  popup menu. A toolbar popup menu is a `single` `ToolbarControlGroup` around a
106
119
  `wa-dropdown` (its `slot="trigger"` `wa-button` is the toolbar button, kept under
107
120
  `data-morph-skip-children`).
108
- - **`PanelHeader` is _the_ panel/dialog/page heading.** A plain toolbar with an
109
- optional bordered icon group, an extra-large `ToolbarText` title, the trailing
110
- controls you pass, and an optional subtitle below — do not hand-build a heading
111
- row or restyle a toolbar into one.
121
+ - **Use one direct toolbar composition for panel/dialog/page headings.** Put an
122
+ optional icon in a `ToolbarControlGroup`, an extra-large `ToolbarText` directly
123
+ in the leading zone, and actions in a trailing group. Supporting copy is
124
+ app-owned content below. Do not create a private heading wrapper or restyle the
125
+ toolbar.
112
126
  - **Space by the five-step scale, by relationship not by eye.** `0`
113
127
  `--kui-space-none`, `4px` `--kui-space-2xs`, `8px` `--kui-space-xs` (inside a
114
128
  group), `16px` `--kui-space-m`, `24px` `--kui-space-l` (between major differing
@@ -127,9 +141,13 @@ maintain a central style list. Configure JSX with `"jsxImportSource": "kerfjs"`.
127
141
  navigation stacks, tab selection and order, pane sizes, and `collapsed`/`expanded`
128
142
  disclosure flags in the app — they are data or persisted layout, and the app reads
129
143
  them to render. The `wire…` helpers own the _ephemeral_ parts: `wireNavStack` the
130
- push/pop animation, `wireTabBars` the overflow autoscroll and drag preview,
144
+ push/pop animation, `wireTabBars` the overflow autoscroll, drag preview, and
145
+ replacement focus after controlled automatic tab activation,
131
146
  `wireResizableRegions` the live drag preview; they report committed changes via
132
- callbacks. The one richer case is `wireTokenSearchFields`, which manages the
147
+ callbacks. Managed TokenSearchField clear also preserves open state and replacement
148
+ editor focus for continued typing. Select All deletion does the same; deletion
149
+ restoration finishes before the next keystroke rather than on a delayed frame.
150
+ Persist both query and remaining tokens read from an edited field. The one richer case is `wireTokenSearchFields`, which manages the
133
151
  collapsible field's expand/collapse/focus by default (on, per-behavior opt-out) and
134
152
  exposes the `expanded` signal on its handle — bind it in render or hand in your own
135
153
  via `collapsible.signals`. Do not hand-roll open/collapse/focus that helper
@@ -143,18 +161,22 @@ maintain a central style list. Configure JSX with `"jsxImportSource": "kerfjs"`.
143
161
  boilerplate while still owning parsing and controlled token state.
144
162
  - **Placeholder loading state, don't rebuild it.** For a value or component that is
145
163
  still loading, set `placeholder` on the component (`Select`, `ListHeader`,
146
- `ListItem`, `ValueTableRow`, `PanelHeader`, `SegmentedControl`, `StateBanner`,
164
+ `ListItem`, `ValueTableRow`, `SegmentedControl`, `StateBanner`,
147
165
  `AppTab`, `ToolbarText`, `ListActionRow`): it renders its real chrome with value
148
166
  slots as subtle **unanimated** skeleton blocks and interactivity disabled, so a
149
167
  parent composes a faithful loading view (e.g. an inspector) without hand-rebuilding
150
168
  markup. Use the standalone `Skeleton` for a custom slot. Prefer it over `wa-skeleton`
151
169
  (the pure-Kerf primitives avoid Web Awesome), and never animate it — use
152
170
  `LoadingSpinner` for known busy activity instead.
171
+ - **Use a StateBanner badge only for compact supporting status.** Pass the
172
+ optional string `badge` for a terse count or status beside the title. It
173
+ inherits the banner tone and is announced with the banner, so keep its text
174
+ meaningful and never rely on color alone.
153
175
 
154
176
  ## Public exports
155
177
 
156
178
  `LucideIcon`, `DisclosureArrow`, `Toolbar`, `ToolbarControlGroup`, `FloatingToolbar`, `ToolbarText`,
157
- `PanelHeader`, `ListItem`, `ListActionRow`, `ListHeader`, `ListInsetControl`,
179
+ `ListItem`, `ListActionRow`, `ListHeader`, `ListInsetControl`,
158
180
  `ListInsetText`, `SegmentedControl`,
159
181
  `Select`, `TokenSearchField` (+ `readTokenSearchField`, `placeTokenSearchCaret`,
160
182
  `wireTokenSearchFields`), `AppTab`, `TabBar` (+ `wireTabBars`, `reorderTabs`),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kerfjs/ui",
3
- "version": "5.0.0-beta.23",
3
+ "version": "5.0.0-beta.25",
4
4
  "description": "Accessible, composable UI primitives for kerf applications.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -64,6 +64,11 @@
64
64
  "browser": "./dist/browser/toolbar-control-group.js",
65
65
  "import": "./dist/toolbar-control-group.js"
66
66
  },
67
+ "./surface-scaffold": {
68
+ "types": "./dist/surface-scaffold.d.ts",
69
+ "browser": "./dist/browser/surface-scaffold.js",
70
+ "import": "./dist/surface-scaffold.js"
71
+ },
67
72
  "./floating-toolbar": {
68
73
  "types": "./dist/floating-toolbar.d.ts",
69
74
  "browser": "./dist/browser/floating-toolbar.js",
@@ -74,6 +79,11 @@
74
79
  "browser": "./dist/browser/toolbar-text.js",
75
80
  "import": "./dist/toolbar-text.js"
76
81
  },
82
+ "./list": {
83
+ "types": "./dist/list.d.ts",
84
+ "browser": "./dist/browser/list.js",
85
+ "import": "./dist/list.js"
86
+ },
77
87
  "./list-action-row": {
78
88
  "types": "./dist/list-action-row.d.ts",
79
89
  "browser": "./dist/browser/list-action-row.js",
@@ -243,11 +253,6 @@
243
253
  "browser": "./dist/browser/empty-state.js",
244
254
  "import": "./dist/empty-state.js"
245
255
  },
246
- "./panel-header": {
247
- "types": "./dist/panel-header.d.ts",
248
- "browser": "./dist/browser/panel-header.js",
249
- "import": "./dist/panel-header.js"
250
- },
251
256
  "./value-table": {
252
257
  "types": "./dist/value-table.d.ts",
253
258
  "browser": "./dist/browser/value-table.js",
@@ -265,8 +270,10 @@
265
270
  "./disclosure-arrow.css": "./dist/styles/disclosure-arrow.css",
266
271
  "./toolbar.css": "./dist/styles/toolbar.css",
267
272
  "./toolbar-control-group.css": "./dist/styles/toolbar-control-group.css",
273
+ "./surface-scaffold.css": "./dist/styles/surface-scaffold.css",
268
274
  "./floating-toolbar.css": "./dist/styles/floating-toolbar.css",
269
275
  "./toolbar-text.css": "./dist/styles/toolbar-text.css",
276
+ "./list.css": "./dist/styles/list.css",
270
277
  "./list-action-row.css": "./dist/styles/list-action-row.css",
271
278
  "./list-item.css": "./dist/styles/list-item.css",
272
279
  "./list-header.css": "./dist/styles/list-header.css",
@@ -290,7 +297,6 @@
290
297
  "./token-search-field.css": "./dist/styles/token-search-field.css",
291
298
  "./state-banner.css": "./dist/styles/state-banner.css",
292
299
  "./empty-state.css": "./dist/styles/empty-state.css",
293
- "./panel-header.css": "./dist/styles/panel-header.css",
294
300
  "./value-table.css": "./dist/styles/value-table.css",
295
301
  "./ai/*": "./ai/*",
296
302
  "./docs/*": "./docs/*"
@@ -377,7 +383,7 @@
377
383
  "@typescript-eslint/eslint-plugin": "^8.65.0",
378
384
  "@typescript-eslint/parser": "^8.65.0",
379
385
  "@vitest/coverage-v8": "4.1.11",
380
- "domotion-svg": "^0.29.0",
386
+ "domotion-svg": "^0.30.1",
381
387
  "esbuild": "^0.25.0",
382
388
  "eslint": "^10.8.0",
383
389
  "eslint-plugin-simple-import-sort": "^12.1.1",
@@ -1,6 +1,6 @@
1
1
  import { relative, sep } from 'node:path';
2
2
 
3
- const ignoredDirectoryNames = new Set([
3
+ export const UI_TRAVERSAL_IGNORED_DIRECTORY_NAMES = Object.freeze([
4
4
  '.git',
5
5
  '.kerf-cache',
6
6
  'coverage',
@@ -8,6 +8,12 @@ const ignoredDirectoryNames = new Set([
8
8
  'kerf-ui-evidence',
9
9
  'node_modules',
10
10
  ]);
11
+ const ignoredDirectoryNames = new Set(UI_TRAVERSAL_IGNORED_DIRECTORY_NAMES);
12
+
13
+ export const UI_TRAVERSAL_ESLINT_IGNORES = Object.freeze([
14
+ ...UI_TRAVERSAL_IGNORED_DIRECTORY_NAMES.map((name) => `**/${name}/**`),
15
+ '**/.claude/worktrees/**',
16
+ ]);
11
17
 
12
18
  export function isUiTraversalExcluded(root, candidate) {
13
19
  const segments = relative(root, candidate).split(sep);
@@ -4,7 +4,6 @@ import './recipes.css';
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 { PanelHeader } from '@kerfjs/ui/panel-header';
8
7
  import { ResizableRegion } from '@kerfjs/ui/resizable-region';
9
8
  import { Toolbar } from '@kerfjs/ui/toolbar';
10
9
  import { ToolbarControlGroup } from '@kerfjs/ui/toolbar-control-group';
@@ -30,11 +29,7 @@ export const createRecipe: RecipeFactory = (announce) => {
30
29
  >
31
30
  <Toolbar
32
31
  label="Atlas workspace"
33
- leading={
34
- <ToolbarControlGroup appearance="borderless" single>
35
- <ToolbarText text="Atlas" />
36
- </ToolbarControlGroup>
37
- }
32
+ leading={<ToolbarText text="Atlas" />}
38
33
  trailing={
39
34
  <div class="recipe-shell__toolbar-actions">
40
35
  <ToolbarControlGroup
@@ -134,21 +129,32 @@ export const createRecipe: RecipeFactory = (announce) => {
134
129
  </ResizableRegion>
135
130
  </div>
136
131
  <main id="recipe-shell-content" class="recipe-shell__main kui-pane">
137
- <PanelHeader
138
- title={
139
- selected.value === 'inbox' ? 'Inbox triage' : 'Active projects'
132
+ <Toolbar
133
+ label="Current workspace view"
134
+ dividerSides=""
135
+ leading={
136
+ <ToolbarText
137
+ text={
138
+ selected.value === 'inbox'
139
+ ? 'Inbox triage'
140
+ : 'Active projects'
141
+ }
142
+ size="xlarge"
143
+ id="recipe-shell-main-title"
144
+ />
140
145
  }
141
- titleId="recipe-shell-main-title"
142
- actions={
143
- <button
144
- class="kui-recipe__button"
145
- data-primary="true"
146
- type="button"
147
- data-action="recipe-action"
148
- data-recipe-command="new"
149
- >
150
- New task
151
- </button>
146
+ trailing={
147
+ <ToolbarControlGroup appearance="borderless" single>
148
+ <button
149
+ class="kui-recipe__button"
150
+ data-primary="true"
151
+ type="button"
152
+ data-action="recipe-action"
153
+ data-recipe-command="new"
154
+ >
155
+ New task
156
+ </button>
157
+ </ToolbarControlGroup>
152
158
  }
153
159
  />
154
160
  <div class="recipe-shell__main-body kui-pane__content kui-content">
@@ -183,9 +189,16 @@ export const createRecipe: RecipeFactory = (announce) => {
183
189
  edge="start"
184
190
  >
185
191
  <aside class="recipe-shell__inspector kui-pane">
186
- <PanelHeader
187
- title="Inspector"
188
- titleId="recipe-shell-inspector-title"
192
+ <Toolbar
193
+ label="Inspector"
194
+ dividerSides=""
195
+ leading={
196
+ <ToolbarText
197
+ text="Inspector"
198
+ size="xlarge"
199
+ id="recipe-shell-inspector-title"
200
+ />
201
+ }
189
202
  />
190
203
  <div class="recipe-shell__inspector-body kui-pane__content kui-content">
191
204
  <ValueTable label="Selected task">
@@ -10,7 +10,6 @@ import { deviceClass } from '@kerfjs/ui/device-class';
10
10
  import { ListHeader } from '@kerfjs/ui/list-header';
11
11
  import { ListItem } from '@kerfjs/ui/list-item';
12
12
  import { LucideIcon } from '@kerfjs/ui/lucide-icon';
13
- import { PanelHeader } from '@kerfjs/ui/panel-header';
14
13
  import { Toolbar } from '@kerfjs/ui/toolbar';
15
14
  import { ToolbarControlGroup } from '@kerfjs/ui/toolbar-control-group';
16
15
  import { ToolbarText } from '@kerfjs/ui/toolbar-text';
@@ -119,17 +118,28 @@ export const createRecipe: RecipeFactory = (announce) => {
119
118
  </nav>
120
119
  </CollapsiblePanel>
121
120
  <main class="recipe-collapsible-sidebar__main kui-pane">
122
- <PanelHeader
123
- title={
124
- selected.value === 'projects'
125
- ? 'Projects'
126
- : selected.value === 'shared'
127
- ? 'Shared with me'
128
- : 'Inbox'
121
+ <Toolbar
122
+ label="Current navigation view"
123
+ dividerSides=""
124
+ leading={
125
+ <>
126
+ <ToolbarControlGroup appearance="borderless" single>
127
+ {railToggle(false)}
128
+ </ToolbarControlGroup>
129
+ <ToolbarText
130
+ text={
131
+ selected.value === 'projects'
132
+ ? 'Projects'
133
+ : selected.value === 'shared'
134
+ ? 'Shared with me'
135
+ : 'Inbox'
136
+ }
137
+ size="xlarge"
138
+ id="recipe-collapsible-main-title"
139
+ />
140
+ </>
129
141
  }
130
- titleId="recipe-collapsible-main-title"
131
- icon={railToggle(false)}
132
- actions={
142
+ trailing={
133
143
  <ToolbarControlGroup appearance="borderless" single>
134
144
  {drawerToggle()}
135
145
  </ToolbarControlGroup>
@@ -160,12 +170,8 @@ export const createRecipe: RecipeFactory = (announce) => {
160
170
  >
161
171
  <Toolbar
162
172
  label="Activity"
163
- divider
164
- leading={
165
- <ToolbarControlGroup appearance="borderless" single>
166
- <ToolbarText text="Activity" size="small" />
167
- </ToolbarControlGroup>
168
- }
173
+ dividerSides="b"
174
+ leading={<ToolbarText text="Activity" size="small" />}
169
175
  trailing={
170
176
  <ToolbarControlGroup appearance="borderless" single>
171
177
  {drawerToggle()}
@@ -6,9 +6,10 @@ import '@awesome.me/webawesome/dist/components/input/input.js';
6
6
  import '@awesome.me/webawesome/dist/components/textarea/textarea.js';
7
7
  import './recipes.css';
8
8
 
9
- import { PanelHeader } from '@kerfjs/ui/panel-header';
10
9
  import { Select } from '@kerfjs/ui/select';
11
10
  import { StateBanner } from '@kerfjs/ui/state-banner';
11
+ import { Toolbar } from '@kerfjs/ui/toolbar';
12
+ import { ToolbarText } from '@kerfjs/ui/toolbar-text';
12
13
  import { signal } from 'kerfjs';
13
14
 
14
15
  import type { RecipeFactory } from './types.js';
@@ -44,12 +45,20 @@ export const createRecipe: RecipeFactory = (announce) => {
44
45
  aria-describedby="recipe-composer-summary"
45
46
  noValidate
46
47
  >
47
- <PanelHeader
48
- title="Publish workspace update"
49
- titleId="recipe-composer-title"
50
- summary="Share a concise, actionable update with collaborators."
51
- summaryId="recipe-composer-summary"
48
+ <Toolbar
49
+ label="Publish workspace update"
50
+ dividerSides=""
51
+ leading={
52
+ <ToolbarText
53
+ text="Publish workspace update"
54
+ size="xlarge"
55
+ id="recipe-composer-title"
56
+ />
57
+ }
52
58
  />
59
+ <p class="kui-recipe__heading-summary" id="recipe-composer-summary">
60
+ Share a concise, actionable update with collaborators.
61
+ </p>
53
62
  {status.value === 'error' && (
54
63
  <StateBanner
55
64
  title="Add a title before publishing"
@@ -7,7 +7,9 @@ import './recipes.css';
7
7
  import { ListHeader } from '@kerfjs/ui/list-header';
8
8
  import { ListItem } from '@kerfjs/ui/list-item';
9
9
  import { LucideIcon } from '@kerfjs/ui/lucide-icon';
10
- import { PanelHeader } from '@kerfjs/ui/panel-header';
10
+ import { Toolbar } from '@kerfjs/ui/toolbar';
11
+ import { ToolbarControlGroup } from '@kerfjs/ui/toolbar-control-group';
12
+ import { ToolbarText } from '@kerfjs/ui/toolbar-text';
11
13
  import { ValueTable, ValueTableRow } from '@kerfjs/ui/value-table';
12
14
  import { signal } from 'kerfjs';
13
15
  import { FileText } from 'lucide';
@@ -89,22 +91,36 @@ export const createRecipe: RecipeFactory = (announce) => {
89
91
  </div>
90
92
  </nav>
91
93
  <section class="recipe-list-detail__detail kui-pane">
92
- <PanelHeader
93
- title="Project details"
94
- titleId="recipe-dialog-title"
95
- summary="Compare delivery state without leaving the workspace."
96
- summaryId="recipe-dialog-summary"
97
- icon={<LucideIcon icon={FileText} name="file-text" />}
98
- actions={
99
- <wa-button
100
- appearance="plain"
101
- data-action="recipe-action"
102
- data-recipe-command="close"
103
- >
104
- Close
105
- </wa-button>
94
+ <Toolbar
95
+ label="Project details"
96
+ dividerSides=""
97
+ leading={
98
+ <>
99
+ <ToolbarControlGroup appearance="borderless" single>
100
+ <LucideIcon icon={FileText} name="file-text" />
101
+ </ToolbarControlGroup>
102
+ <ToolbarText
103
+ text="Project details"
104
+ size="xlarge"
105
+ id="recipe-dialog-title"
106
+ />
107
+ </>
108
+ }
109
+ trailing={
110
+ <ToolbarControlGroup appearance="borderless" single>
111
+ <wa-button
112
+ appearance="plain"
113
+ data-action="recipe-action"
114
+ data-recipe-command="close"
115
+ >
116
+ Close
117
+ </wa-button>
118
+ </ToolbarControlGroup>
106
119
  }
107
120
  />
121
+ <p class="kui-recipe__heading-summary" id="recipe-dialog-summary">
122
+ Compare delivery state without leaving the workspace.
123
+ </p>
108
124
  <div
109
125
  class="recipe-list-detail__body kui-pane__content kui-content"
110
126
  aria-live="polite"
@@ -3,8 +3,10 @@ import './recipes.css';
3
3
 
4
4
  import { EmptyState } from '@kerfjs/ui/empty-state';
5
5
  import { LoadingSpinner } from '@kerfjs/ui/loading-spinner';
6
- import { PanelHeader } from '@kerfjs/ui/panel-header';
7
6
  import { StateBanner } from '@kerfjs/ui/state-banner';
7
+ import { Toolbar } from '@kerfjs/ui/toolbar';
8
+ import { ToolbarControlGroup } from '@kerfjs/ui/toolbar-control-group';
9
+ import { ToolbarText } from '@kerfjs/ui/toolbar-text';
8
10
  import { signal } from 'kerfjs';
9
11
 
10
12
  import type { RecipeFactory } from './types.js';
@@ -122,11 +124,18 @@ export const createRecipe: RecipeFactory = (announce) => {
122
124
  data-recipe="recipe-list-workspace-states"
123
125
  data-list-state={state.value}
124
126
  >
125
- <PanelHeader
126
- title="Release tasks"
127
- titleId="recipe-list-title"
128
- actions={
129
- <div class="kui-control-cluster">
127
+ <Toolbar
128
+ label="Release tasks"
129
+ dividerSides=""
130
+ leading={
131
+ <ToolbarText
132
+ text="Release tasks"
133
+ size="xlarge"
134
+ id="recipe-list-title"
135
+ />
136
+ }
137
+ trailing={
138
+ <ToolbarControlGroup appearance="borderless">
130
139
  <button
131
140
  class="kui-recipe__button"
132
141
  type="button"
@@ -152,7 +161,7 @@ export const createRecipe: RecipeFactory = (announce) => {
152
161
  >
153
162
  Refresh
154
163
  </button>
155
- </div>
164
+ </ToolbarControlGroup>
156
165
  }
157
166
  />
158
167
  <div class="recipe-list__body kui-pane__content kui-content">
@@ -4,10 +4,13 @@ import './recipes.css';
4
4
 
5
5
  import { ListItem } from '@kerfjs/ui/list-item';
6
6
  import { LucideIcon } from '@kerfjs/ui/lucide-icon';
7
- import { PanelHeader } from '@kerfjs/ui/panel-header';
8
7
  import { SegmentedControl } from '@kerfjs/ui/segmented-control';
9
8
  import { Select } from '@kerfjs/ui/select';
9
+ import { Skeleton } from '@kerfjs/ui/skeleton';
10
10
  import { StateBanner } from '@kerfjs/ui/state-banner';
11
+ import { Toolbar } from '@kerfjs/ui/toolbar';
12
+ import { ToolbarControlGroup } from '@kerfjs/ui/toolbar-control-group';
13
+ import { ToolbarText } from '@kerfjs/ui/toolbar-text';
11
14
  import { ValueTable, ValueTableRow } from '@kerfjs/ui/value-table';
12
15
  import { signal } from 'kerfjs';
13
16
  import { Columns3, FileText, Inbox, List } from 'lucide';
@@ -35,25 +38,43 @@ export const createRecipe: RecipeFactory = (announce) => {
35
38
  data-recipe="recipe-loading-inspector"
36
39
  data-inspector-loading={String(p)}
37
40
  >
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>
41
+ <Toolbar
42
+ label="Ticket inspector"
43
+ dividerSides=""
44
+ leading={
45
+ <>
46
+ <ToolbarControlGroup appearance="borderless" single>
47
+ {icon(FileText, 'file-text')}
48
+ </ToolbarControlGroup>
49
+ <ToolbarText
50
+ text="Ticket · KF-2048"
51
+ size="xlarge"
52
+ id="recipe-inspector-title"
53
+ placeholder={p}
54
+ />
55
+ </>
56
+ }
57
+ trailing={
58
+ <ToolbarControlGroup appearance="borderless" single>
59
+ <button
60
+ class="kui-recipe__button"
61
+ data-primary="true"
62
+ type="button"
63
+ data-action="recipe-action"
64
+ data-recipe-command="toggle"
65
+ >
66
+ {p ? 'Show loaded' : 'Show loading'}
67
+ </button>
68
+ </ToolbarControlGroup>
55
69
  }
56
70
  />
71
+ <p class="kui-recipe__heading-summary" id="recipe-inspector-summary">
72
+ {p ? (
73
+ <Skeleton width="18em" />
74
+ ) : (
75
+ 'Restore keyboard focus after a dialog closes'
76
+ )}
77
+ </p>
57
78
  <div class="recipe-inspector__body kui-pane__content kui-content">
58
79
  <section>
59
80
  <ValueTable label="Ticket details">
@@ -92,7 +92,7 @@ export const createRecipe: RecipeFactory = (announce) => {
92
92
  <footer class="recipe-sidebar__footer kui-pane__footer">
93
93
  <Toolbar
94
94
  label="Sidebar actions"
95
- divider={false}
95
+ dividerSides=""
96
96
  leading={
97
97
  <ToolbarControlGroup appearance="borderless" single>
98
98
  <button