@xemahq/ui-kernel 0.10.0 → 0.11.1

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 (379) hide show
  1. package/dist/lib/biome-host/agent-validation.d.ts.map +1 -1
  2. package/dist/lib/biome-host/agent-validation.js +26 -13
  3. package/dist/lib/biome-host/agent-validation.js.map +1 -1
  4. package/dist/lib/biome-host/biome-registry.d.ts.map +1 -1
  5. package/dist/lib/biome-host/biome-registry.js +27 -10
  6. package/dist/lib/biome-host/biome-registry.js.map +1 -1
  7. package/dist/lib/biome-host/biome-scope-hooks.d.ts.map +1 -1
  8. package/dist/lib/biome-host/biome-scope-hooks.js +2 -1
  9. package/dist/lib/biome-host/biome-scope-hooks.js.map +1 -1
  10. package/dist/lib/biome-host/biome-scoped-query.d.ts.map +1 -1
  11. package/dist/lib/biome-host/biome-scoped-query.js +5 -3
  12. package/dist/lib/biome-host/biome-scoped-query.js.map +1 -1
  13. package/dist/lib/biome-host/frontend-biome.d.ts +1 -1
  14. package/dist/lib/biome-host/frontend-biome.d.ts.map +1 -1
  15. package/dist/lib/biome-host/host-bridge.d.ts +1 -1
  16. package/dist/lib/biome-host/host-bridge.d.ts.map +1 -1
  17. package/dist/lib/biome-host/host-bridge.js.map +1 -1
  18. package/dist/lib/biome-host/i18n-hooks.d.ts.map +1 -1
  19. package/dist/lib/biome-host/i18n-hooks.js.map +1 -1
  20. package/dist/lib/biome-host/realtime-hooks.d.ts.map +1 -1
  21. package/dist/lib/biome-host/realtime-hooks.js.map +1 -1
  22. package/dist/lib/biome-host/session-contributions.d.ts +1 -1
  23. package/dist/lib/biome-host/session-contributions.d.ts.map +1 -1
  24. package/dist/lib/biome-host/use-mutation-with-error-toast.d.ts.map +1 -1
  25. package/dist/lib/biome-host/use-mutation-with-error-toast.js +3 -2
  26. package/dist/lib/biome-host/use-mutation-with-error-toast.js.map +1 -1
  27. package/dist/lib/biome-host/use-page-state.d.ts.map +1 -1
  28. package/dist/lib/biome-host/use-page-state.js +19 -10
  29. package/dist/lib/biome-host/use-page-state.js.map +1 -1
  30. package/dist/lib/capabilities/capability-provider.d.ts +1 -1
  31. package/dist/lib/capabilities/capability-provider.d.ts.map +1 -1
  32. package/dist/lib/capabilities/capability-provider.js +2 -2
  33. package/dist/lib/capabilities/capability-provider.js.map +1 -1
  34. package/dist/lib/capabilities/use-capability.d.ts +1 -1
  35. package/dist/lib/capabilities/use-capability.d.ts.map +1 -1
  36. package/dist/lib/capabilities/use-capability.js +2 -1
  37. package/dist/lib/capabilities/use-capability.js.map +1 -1
  38. package/dist/lib/contribution-registry/contribution-registry.d.ts.map +1 -1
  39. package/dist/lib/contribution-registry/contribution-registry.js +2 -1
  40. package/dist/lib/contribution-registry/contribution-registry.js.map +1 -1
  41. package/dist/lib/system-bus/deeplink.d.ts.map +1 -1
  42. package/dist/lib/system-bus/deeplink.js +4 -2
  43. package/dist/lib/system-bus/deeplink.js.map +1 -1
  44. package/dist/lib/system-bus/host-ports.d.ts +2 -2
  45. package/dist/lib/system-bus/host-ports.d.ts.map +1 -1
  46. package/dist/lib/system-bus/intent-registry.d.ts.map +1 -1
  47. package/dist/lib/system-bus/intent-registry.js +6 -3
  48. package/dist/lib/system-bus/intent-registry.js.map +1 -1
  49. package/dist/lib/system-bus/intents.d.ts +1 -1
  50. package/dist/lib/system-bus/intents.d.ts.map +1 -1
  51. package/dist/lib/system-bus/palette.d.ts +1 -1
  52. package/dist/lib/system-bus/palette.d.ts.map +1 -1
  53. package/dist/lib/system-bus/system-bus-builder.d.ts.map +1 -1
  54. package/dist/lib/system-bus/system-bus-builder.js +1 -1
  55. package/dist/lib/system-bus/system-bus-builder.js.map +1 -1
  56. package/dist/lib/system-bus/windows.d.ts +1 -1
  57. package/dist/lib/system-bus/windows.d.ts.map +1 -1
  58. package/dist/offline/outbox.d.ts +1 -0
  59. package/dist/offline/outbox.d.ts.map +1 -1
  60. package/dist/offline/outbox.js +4 -1
  61. package/dist/offline/outbox.js.map +1 -1
  62. package/dist/offline/react-hooks.d.ts +1 -1
  63. package/dist/offline/react-hooks.d.ts.map +1 -1
  64. package/dist/offline/react-hooks.js.map +1 -1
  65. package/dist/org-db/components/DbResultTable.d.ts.map +1 -1
  66. package/dist/org-db/components/DbResultTable.js +15 -6
  67. package/dist/org-db/components/DbResultTable.js.map +1 -1
  68. package/dist/registry/lib/agent-validation-host.d.ts.map +1 -1
  69. package/dist/registry/lib/agent-validation-host.js +1 -1
  70. package/dist/registry/lib/agent-validation-host.js.map +1 -1
  71. package/dist/registry/lib/biome-slot.d.ts.map +1 -1
  72. package/dist/registry/lib/biome-slot.js +5 -3
  73. package/dist/registry/lib/biome-slot.js.map +1 -1
  74. package/dist/registry/lib/primitives/SessionEventCard.d.ts.map +1 -1
  75. package/dist/registry/lib/primitives/SessionEventCard.js +14 -2
  76. package/dist/registry/lib/primitives/SessionEventCard.js.map +1 -1
  77. package/dist/registry/lib/primitives/SessionEventTimeline.d.ts.map +1 -1
  78. package/dist/registry/lib/primitives/SessionEventTimeline.js +6 -3
  79. package/dist/registry/lib/primitives/SessionEventTimeline.js.map +1 -1
  80. package/dist/registry/lib/primitives/SessionTabbedDrawer.d.ts.map +1 -1
  81. package/dist/registry/lib/primitives/SessionTabbedDrawer.js +10 -5
  82. package/dist/registry/lib/primitives/SessionTabbedDrawer.js.map +1 -1
  83. package/dist/registry/lib/session-context-provider.d.ts +1 -1
  84. package/dist/registry/lib/session-context-provider.d.ts.map +1 -1
  85. package/dist/registry/lib/session-context-provider.js.map +1 -1
  86. package/dist/registry/lib/session-selectors.d.ts.map +1 -1
  87. package/dist/registry/lib/session-selectors.js +35 -20
  88. package/dist/registry/lib/session-selectors.js.map +1 -1
  89. package/dist/session/comments/CommentRail.d.ts.map +1 -1
  90. package/dist/session/comments/CommentRail.js.map +1 -1
  91. package/dist/session/shell/SessionWorkspaceShell.d.ts.map +1 -1
  92. package/dist/session/shell/SessionWorkspaceShell.js.map +1 -1
  93. package/dist/session-kit/approvals/ApprovalCard.d.ts.map +1 -1
  94. package/dist/session-kit/approvals/ApprovalCard.js +6 -2
  95. package/dist/session-kit/approvals/ApprovalCard.js.map +1 -1
  96. package/dist/session-kit/approvals/ApprovalsCenter.d.ts.map +1 -1
  97. package/dist/session-kit/approvals/ApprovalsCenter.js +6 -3
  98. package/dist/session-kit/approvals/ApprovalsCenter.js.map +1 -1
  99. package/dist/session-kit/combobox/Combobox.d.ts.map +1 -1
  100. package/dist/session-kit/combobox/Combobox.js +20 -6
  101. package/dist/session-kit/combobox/Combobox.js.map +1 -1
  102. package/dist/session-kit/display/MD.d.ts.map +1 -1
  103. package/dist/session-kit/display/MD.js +7 -4
  104. package/dist/session-kit/display/MD.js.map +1 -1
  105. package/dist/ui/branding/app-branding-provider.d.ts.map +1 -1
  106. package/dist/ui/branding/app-branding-provider.js.map +1 -1
  107. package/dist/ui/branding/sanitize.d.ts.map +1 -1
  108. package/dist/ui/branding/sanitize.js +12 -6
  109. package/dist/ui/branding/sanitize.js.map +1 -1
  110. package/dist/ui/capture/document-preview.d.ts +1 -1
  111. package/dist/ui/capture/document-preview.d.ts.map +1 -1
  112. package/dist/ui/capture/document-preview.js +8 -6
  113. package/dist/ui/capture/document-preview.js.map +1 -1
  114. package/dist/ui/capture/field-spec-to-zod.d.ts.map +1 -1
  115. package/dist/ui/capture/field-spec-to-zod.js +45 -16
  116. package/dist/ui/capture/field-spec-to-zod.js.map +1 -1
  117. package/dist/ui/capture/field-spec-validate.d.ts.map +1 -1
  118. package/dist/ui/capture/field-spec-validate.js +79 -38
  119. package/dist/ui/capture/field-spec-validate.js.map +1 -1
  120. package/dist/ui/capture/field-spec.d.ts.map +1 -1
  121. package/dist/ui/capture/field-spec.js +17 -6
  122. package/dist/ui/capture/field-spec.js.map +1 -1
  123. package/dist/ui/capture/schema-field-input.d.ts.map +1 -1
  124. package/dist/ui/capture/schema-field-input.js +23 -18
  125. package/dist/ui/capture/schema-field-input.js.map +1 -1
  126. package/dist/ui/capture/schema-form.d.ts +1 -1
  127. package/dist/ui/capture/schema-form.d.ts.map +1 -1
  128. package/dist/ui/capture/schema-form.js +7 -6
  129. package/dist/ui/capture/schema-form.js.map +1 -1
  130. package/dist/ui/capture/use-prefill.d.ts.map +1 -1
  131. package/dist/ui/capture/use-prefill.js +32 -14
  132. package/dist/ui/capture/use-prefill.js.map +1 -1
  133. package/dist/ui/capture/use-schema-validation.d.ts +1 -1
  134. package/dist/ui/capture/use-schema-validation.d.ts.map +1 -1
  135. package/dist/ui/capture/use-schema-validation.js +13 -8
  136. package/dist/ui/capture/use-schema-validation.js.map +1 -1
  137. package/dist/ui/capture/use-wizard.d.ts.map +1 -1
  138. package/dist/ui/capture/use-wizard.js +23 -8
  139. package/dist/ui/capture/use-wizard.js.map +1 -1
  140. package/dist/ui/capture/value-format.d.ts.map +1 -1
  141. package/dist/ui/capture/value-format.js +6 -3
  142. package/dist/ui/capture/value-format.js.map +1 -1
  143. package/dist/ui/capture/wizard.d.ts.map +1 -1
  144. package/dist/ui/capture/wizard.js +3 -3
  145. package/dist/ui/capture/wizard.js.map +1 -1
  146. package/dist/ui/charts/bar-chart.d.ts +1 -1
  147. package/dist/ui/charts/bar-chart.d.ts.map +1 -1
  148. package/dist/ui/charts/bar-chart.js +1 -1
  149. package/dist/ui/charts/bar-chart.js.map +1 -1
  150. package/dist/ui/charts/chart-frame.d.ts +2 -2
  151. package/dist/ui/charts/chart-frame.d.ts.map +1 -1
  152. package/dist/ui/charts/chart-frame.js +4 -3
  153. package/dist/ui/charts/chart-frame.js.map +1 -1
  154. package/dist/ui/charts/chart-utils.d.ts.map +1 -1
  155. package/dist/ui/charts/chart-utils.js +32 -14
  156. package/dist/ui/charts/chart-utils.js.map +1 -1
  157. package/dist/ui/charts/donut-chart.d.ts +1 -1
  158. package/dist/ui/charts/donut-chart.d.ts.map +1 -1
  159. package/dist/ui/charts/donut-chart.js +7 -3
  160. package/dist/ui/charts/donut-chart.js.map +1 -1
  161. package/dist/ui/charts/line-chart.d.ts +1 -1
  162. package/dist/ui/charts/line-chart.d.ts.map +1 -1
  163. package/dist/ui/charts/line-chart.js +7 -4
  164. package/dist/ui/charts/line-chart.js.map +1 -1
  165. package/dist/ui/charts/sparkline.d.ts +1 -1
  166. package/dist/ui/charts/sparkline.d.ts.map +1 -1
  167. package/dist/ui/charts/sparkline.js +10 -6
  168. package/dist/ui/charts/sparkline.js.map +1 -1
  169. package/dist/ui/chrome/AsyncBoundary.d.ts +2 -2
  170. package/dist/ui/chrome/AsyncBoundary.d.ts.map +1 -1
  171. package/dist/ui/chrome/AsyncBoundary.js +3 -3
  172. package/dist/ui/chrome/AsyncBoundary.js.map +1 -1
  173. package/dist/ui/chrome/EmptyState.d.ts +19 -8
  174. package/dist/ui/chrome/EmptyState.d.ts.map +1 -1
  175. package/dist/ui/chrome/EmptyState.js +6 -4
  176. package/dist/ui/chrome/EmptyState.js.map +1 -1
  177. package/dist/ui/chrome/RecordCardList.d.ts +19 -0
  178. package/dist/ui/chrome/RecordCardList.d.ts.map +1 -0
  179. package/dist/ui/chrome/RecordCardList.js +12 -0
  180. package/dist/ui/chrome/RecordCardList.js.map +1 -0
  181. package/dist/ui/chrome/page-shell.d.ts +1 -1
  182. package/dist/ui/chrome/page-shell.d.ts.map +1 -1
  183. package/dist/ui/chrome/page-shell.js +16 -5
  184. package/dist/ui/chrome/page-shell.js.map +1 -1
  185. package/dist/ui/chrome/status-badge.d.ts.map +1 -1
  186. package/dist/ui/chrome/status-badge.js +1 -1
  187. package/dist/ui/chrome/status-badge.js.map +1 -1
  188. package/dist/ui/design-tokens.d.ts +4 -6
  189. package/dist/ui/design-tokens.d.ts.map +1 -1
  190. package/dist/ui/design-tokens.js +17 -11
  191. package/dist/ui/design-tokens.js.map +1 -1
  192. package/dist/ui/index.d.ts +1 -0
  193. package/dist/ui/index.d.ts.map +1 -1
  194. package/dist/ui/index.js +1 -0
  195. package/dist/ui/index.js.map +1 -1
  196. package/dist/ui/primitives/async-combobox.d.ts.map +1 -1
  197. package/dist/ui/primitives/async-combobox.js +4 -2
  198. package/dist/ui/primitives/async-combobox.js.map +1 -1
  199. package/dist/ui/primitives/badge.d.ts +2 -2
  200. package/dist/ui/primitives/badge.d.ts.map +1 -1
  201. package/dist/ui/primitives/badge.js +3 -3
  202. package/dist/ui/primitives/badge.js.map +1 -1
  203. package/dist/ui/primitives/button.d.ts +2 -2
  204. package/dist/ui/primitives/button.d.ts.map +1 -1
  205. package/dist/ui/primitives/button.js +5 -5
  206. package/dist/ui/primitives/button.js.map +1 -1
  207. package/dist/ui/primitives/overflow-tabs.d.ts.map +1 -1
  208. package/dist/ui/primitives/overflow-tabs.js +19 -12
  209. package/dist/ui/primitives/overflow-tabs.js.map +1 -1
  210. package/dist/ui/primitives/preview-device-frame.js +8 -4
  211. package/dist/ui/primitives/preview-device-frame.js.map +1 -1
  212. package/dist/ui/primitives/tag-multi-select.d.ts.map +1 -1
  213. package/dist/ui/primitives/tag-multi-select.js +10 -5
  214. package/dist/ui/primitives/tag-multi-select.js.map +1 -1
  215. package/dist/ui/primitives/url-preview-chrome.d.ts.map +1 -1
  216. package/dist/ui/primitives/url-preview-chrome.js.map +1 -1
  217. package/dist/vista/GenericCatalogueSurface.d.ts.map +1 -1
  218. package/dist/vista/GenericCatalogueSurface.js +5 -3
  219. package/dist/vista/GenericCatalogueSurface.js.map +1 -1
  220. package/dist/vista/VistaPanel.d.ts.map +1 -1
  221. package/dist/vista/VistaPanel.js +8 -4
  222. package/dist/vista/VistaPanel.js.map +1 -1
  223. package/dist/vista/html/CustomUiFrame.d.ts.map +1 -1
  224. package/dist/vista/html/CustomUiFrame.js +2 -1
  225. package/dist/vista/html/CustomUiFrame.js.map +1 -1
  226. package/dist/vista/html/custom-ui-frame-bridge.d.ts.map +1 -1
  227. package/dist/vista/html/custom-ui-frame-bridge.js +6 -3
  228. package/dist/vista/html/custom-ui-frame-bridge.js.map +1 -1
  229. package/dist/vista/html/custom-ui-intents.d.ts.map +1 -1
  230. package/dist/vista/html/custom-ui-intents.js +13 -15
  231. package/dist/vista/html/custom-ui-intents.js.map +1 -1
  232. package/dist/vista/surface-catalogue.d.ts.map +1 -1
  233. package/dist/vista/surface-catalogue.js +6 -3
  234. package/dist/vista/surface-catalogue.js.map +1 -1
  235. package/dist/vista/surfaces/FormSurface.d.ts.map +1 -1
  236. package/dist/vista/surfaces/FormSurface.js +20 -7
  237. package/dist/vista/surfaces/FormSurface.js.map +1 -1
  238. package/dist/vista/surfaces/TableSurface.d.ts.map +1 -1
  239. package/dist/vista/surfaces/TableSurface.js +2 -1
  240. package/dist/vista/surfaces/TableSurface.js.map +1 -1
  241. package/dist/vista/surfaces/blob-surfaces.d.ts.map +1 -1
  242. package/dist/vista/surfaces/blob-surfaces.js +7 -2
  243. package/dist/vista/surfaces/blob-surfaces.js.map +1 -1
  244. package/dist/vista/surfaces/elicitation-transport.d.ts.map +1 -1
  245. package/dist/vista/surfaces/elicitation-transport.js +14 -7
  246. package/dist/vista/surfaces/elicitation-transport.js.map +1 -1
  247. package/dist/vista/surfaces/file-surface-utils.d.ts.map +1 -1
  248. package/dist/vista/surfaces/file-surface-utils.js +8 -4
  249. package/dist/vista/surfaces/file-surface-utils.js.map +1 -1
  250. package/dist/vista/surfaces/register-surfaces.js +2 -1
  251. package/dist/vista/surfaces/register-surfaces.js.map +1 -1
  252. package/dist/vista/surfaces/text-surfaces.d.ts +1 -1
  253. package/dist/vista/surfaces/text-surfaces.d.ts.map +1 -1
  254. package/dist/vista/surfaces/text-surfaces.js +13 -7
  255. package/dist/vista/surfaces/text-surfaces.js.map +1 -1
  256. package/dist/vista/use-vista-tabs.d.ts.map +1 -1
  257. package/dist/vista/use-vista-tabs.js +8 -4
  258. package/dist/vista/use-vista-tabs.js.map +1 -1
  259. package/dist/vista/vista-code-renderer.d.ts.map +1 -1
  260. package/dist/vista/vista-code-renderer.js.map +1 -1
  261. package/dist/vista/vista-file-source.d.ts.map +1 -1
  262. package/dist/vista/vista-file-source.js +9 -5
  263. package/dist/vista/vista-file-source.js.map +1 -1
  264. package/dist/vista/vista-form-host.d.ts.map +1 -1
  265. package/dist/vista/vista-form-host.js +1 -1
  266. package/dist/vista/vista-form-host.js.map +1 -1
  267. package/dist/vista/vista-model.d.ts.map +1 -1
  268. package/dist/vista/vista-model.js +5 -3
  269. package/dist/vista/vista-model.js.map +1 -1
  270. package/dist/vista/vista-open-context.d.ts.map +1 -1
  271. package/dist/vista/vista-open-context.js +1 -1
  272. package/dist/vista/vista-open-context.js.map +1 -1
  273. package/dist/vista/vista-payloads.d.ts.map +1 -1
  274. package/dist/vista/vista-payloads.js +127 -63
  275. package/dist/vista/vista-payloads.js.map +1 -1
  276. package/dist/vista/vista-tabs-manifest.d.ts.map +1 -1
  277. package/dist/vista/vista-tabs-manifest.js +18 -9
  278. package/dist/vista/vista-tabs-manifest.js.map +1 -1
  279. package/dist/vista/vista-tools.d.ts.map +1 -1
  280. package/dist/vista/vista-tools.js +12 -6
  281. package/dist/vista/vista-tools.js.map +1 -1
  282. package/package.json +7 -4
  283. package/src/lib/biome-host/agent-validation.ts +37 -13
  284. package/src/lib/biome-host/biome-registry.ts +48 -13
  285. package/src/lib/biome-host/biome-scope-hooks.ts +3 -1
  286. package/src/lib/biome-host/biome-scoped-query.ts +7 -6
  287. package/src/lib/biome-host/frontend-biome.ts +1 -1
  288. package/src/lib/biome-host/host-bridge.ts +5 -4
  289. package/src/lib/biome-host/i18n-hooks.ts +1 -0
  290. package/src/lib/biome-host/realtime-hooks.ts +1 -0
  291. package/src/lib/biome-host/session-contributions.ts +1 -1
  292. package/src/lib/biome-host/use-mutation-with-error-toast.ts +4 -2
  293. package/src/lib/biome-host/use-page-state.ts +27 -10
  294. package/src/lib/capabilities/capability-provider.tsx +12 -5
  295. package/src/lib/capabilities/use-capability.ts +8 -4
  296. package/src/lib/contribution-registry/contribution-registry.ts +3 -1
  297. package/src/lib/system-bus/deeplink.ts +14 -4
  298. package/src/lib/system-bus/host-ports.ts +3 -7
  299. package/src/lib/system-bus/intent-registry.ts +12 -8
  300. package/src/lib/system-bus/intents.ts +6 -2
  301. package/src/lib/system-bus/palette.ts +2 -1
  302. package/src/lib/system-bus/system-bus-builder.ts +4 -2
  303. package/src/lib/system-bus/windows.ts +1 -1
  304. package/src/offline/outbox.test.ts +12 -3
  305. package/src/offline/outbox.ts +5 -1
  306. package/src/offline/react-hooks.ts +5 -2
  307. package/src/org-db/components/DbResultTable.tsx +48 -15
  308. package/src/registry/lib/agent-validation-host.ts +1 -2
  309. package/src/registry/lib/biome-slot.tsx +7 -4
  310. package/src/registry/lib/primitives/SessionEventCard.tsx +29 -5
  311. package/src/registry/lib/primitives/SessionEventTimeline.tsx +9 -3
  312. package/src/registry/lib/primitives/SessionTabbedDrawer.tsx +15 -5
  313. package/src/registry/lib/session-context-provider.tsx +1 -1
  314. package/src/registry/lib/session-selectors.ts +66 -27
  315. package/src/session/comments/CommentRail.tsx +2 -2
  316. package/src/session/shell/SessionWorkspaceShell.tsx +2 -2
  317. package/src/session-kit/approvals/ApprovalCard.tsx +7 -2
  318. package/src/session-kit/approvals/ApprovalsCenter.tsx +13 -4
  319. package/src/session-kit/combobox/Combobox.tsx +42 -11
  320. package/src/session-kit/display/MD.tsx +14 -5
  321. package/src/ui/branding/app-branding-provider.tsx +2 -3
  322. package/src/ui/branding/sanitize.ts +18 -6
  323. package/src/ui/capture/document-preview.tsx +84 -19
  324. package/src/ui/capture/field-spec-to-zod.ts +62 -14
  325. package/src/ui/capture/field-spec-validate.ts +132 -43
  326. package/src/ui/capture/field-spec.test.ts +2 -2
  327. package/src/ui/capture/field-spec.ts +41 -10
  328. package/src/ui/capture/schema-field-input.tsx +218 -38
  329. package/src/ui/capture/schema-form.tsx +54 -13
  330. package/src/ui/capture/use-prefill.ts +50 -17
  331. package/src/ui/capture/use-schema-validation.ts +45 -13
  332. package/src/ui/capture/use-wizard.ts +57 -11
  333. package/src/ui/capture/value-format.ts +14 -4
  334. package/src/ui/capture/wizard.tsx +9 -5
  335. package/src/ui/charts/bar-chart.tsx +8 -4
  336. package/src/ui/charts/chart-frame.tsx +18 -5
  337. package/src/ui/charts/chart-utils.ts +47 -15
  338. package/src/ui/charts/donut-chart.tsx +24 -6
  339. package/src/ui/charts/line-chart.tsx +34 -12
  340. package/src/ui/charts/sparkline.tsx +17 -9
  341. package/src/ui/chrome/AsyncBoundary.tsx +14 -6
  342. package/src/ui/chrome/EmptyState.tsx +116 -43
  343. package/src/ui/chrome/RecordCardList.tsx +98 -0
  344. package/src/ui/chrome/page-shell.spec.tsx +117 -0
  345. package/src/ui/chrome/page-shell.tsx +81 -25
  346. package/src/ui/chrome/status-badge.tsx +8 -4
  347. package/src/ui/design-tokens.ts +39 -13
  348. package/src/ui/index.ts +5 -0
  349. package/src/ui/primitives/async-combobox.tsx +7 -3
  350. package/src/ui/primitives/badge.tsx +14 -5
  351. package/src/ui/primitives/button.tsx +13 -6
  352. package/src/ui/primitives/overflow-tabs.tsx +46 -16
  353. package/src/ui/primitives/preview-device-frame.tsx +12 -4
  354. package/src/ui/primitives/tag-multi-select.tsx +30 -9
  355. package/src/ui/primitives/url-preview-chrome.tsx +1 -0
  356. package/src/vista/GenericCatalogueSurface.tsx +7 -5
  357. package/src/vista/VistaPanel.tsx +12 -4
  358. package/src/vista/html/CustomUiFrame.spec.tsx +3 -1
  359. package/src/vista/html/CustomUiFrame.tsx +3 -1
  360. package/src/vista/html/custom-ui-frame-bridge.ts +9 -3
  361. package/src/vista/html/custom-ui-intents.spec.ts +3 -1
  362. package/src/vista/html/custom-ui-intents.ts +19 -15
  363. package/src/vista/surface-catalogue.ts +9 -3
  364. package/src/vista/surfaces/FormSurface.tsx +27 -10
  365. package/src/vista/surfaces/TableSurface.tsx +4 -3
  366. package/src/vista/surfaces/blob-surfaces.tsx +13 -3
  367. package/src/vista/surfaces/elicitation-transport.ts +21 -7
  368. package/src/vista/surfaces/file-surface-utils.ts +11 -4
  369. package/src/vista/surfaces/register-surfaces.tsx +3 -1
  370. package/src/vista/surfaces/text-surfaces.tsx +21 -8
  371. package/src/vista/use-vista-tabs.ts +12 -4
  372. package/src/vista/vista-code-renderer.tsx +6 -5
  373. package/src/vista/vista-file-source.tsx +15 -14
  374. package/src/vista/vista-form-host.tsx +3 -8
  375. package/src/vista/vista-model.ts +10 -3
  376. package/src/vista/vista-open-context.tsx +3 -8
  377. package/src/vista/vista-payloads.ts +186 -63
  378. package/src/vista/vista-tabs-manifest.ts +28 -13
  379. package/src/vista/vista-tools.ts +18 -6
@@ -1,12 +1,12 @@
1
1
  // ═══════════════════════════════════════════════════════════════════════════
2
2
  // Sparkline — tiny inline trend line, pure SVG, no axes/legend (Wave 9.2)
3
3
  // ═══════════════════════════════════════════════════════════════════════════
4
- import type { ReactNode } from 'react';
5
4
 
6
5
  import { cn } from '../cn';
6
+ import { chartColorAt, defaultFormatValue, niceScale } from './chart-utils';
7
7
 
8
8
  import type { ChartValueFormatter } from './chart-types';
9
- import { chartColorAt, defaultFormatValue, niceScale } from './chart-utils';
9
+ import type { ReactNode } from 'react';
10
10
 
11
11
  const VIEW_W = 100;
12
12
  const VIEW_H = 28;
@@ -36,8 +36,13 @@ export function Sparkline({
36
36
  }: SparklineProps): ReactNode {
37
37
  const format = formatValue ?? defaultFormatValue;
38
38
  const finite = values.filter((v) => Number.isFinite(v));
39
+ // Read the endpoints BEFORE the empty guard so the guard itself narrows them:
40
+ // both are `undefined` exactly when `finite` is empty, which is the case the
41
+ // guard already returns for.
42
+ const first = finite[0];
43
+ const last = finite[finite.length - 1];
39
44
 
40
- if (finite.length === 0) {
45
+ if (first === undefined || last === undefined) {
41
46
  return (
42
47
  <span
43
48
  role="img"
@@ -49,7 +54,9 @@ export function Sparkline({
49
54
  );
50
55
  }
51
56
 
52
- const scale = niceScale(Math.min(...finite), Math.max(...finite), { pinZero: false });
57
+ const scale = niceScale(Math.min(...finite), Math.max(...finite), {
58
+ pinZero: false,
59
+ });
53
60
  const span = scale.max - scale.min;
54
61
  const yToPx = (v: number): number =>
55
62
  VIEW_H - PAD_Y - ((v - scale.min) / span) * (VIEW_H - 2 * PAD_Y);
@@ -60,17 +67,18 @@ export function Sparkline({
60
67
  const segments: string[] = [];
61
68
  let current: string[] = [];
62
69
  values.forEach((v, i) => {
63
- if (Number.isFinite(v)) current.push(`${xToPx(i)},${yToPx(v)}`);
64
- else if (current.length > 0) {
70
+ if (Number.isFinite(v)) {
71
+ current.push(`${xToPx(i)},${yToPx(v)}`);
72
+ } else if (current.length > 0) {
65
73
  segments.push(current.join(' '));
66
74
  current = [];
67
75
  }
68
76
  });
69
- if (current.length > 0) segments.push(current.join(' '));
77
+ if (current.length > 0) {
78
+ segments.push(current.join(' '));
79
+ }
70
80
 
71
81
  const stroke = chartColorAt(0, color);
72
- const first = finite[0];
73
- const last = finite[finite.length - 1];
74
82
  const summary =
75
83
  ariaLabel ??
76
84
  `${title}: trend of ${finite.length} points, from ${format(first)} to ${format(last)}.`;
@@ -1,10 +1,10 @@
1
- import type { LucideIcon } from 'lucide-react';
2
- import type { ReactNode } from 'react';
3
-
4
- import ErrorCard, { type ErrorMessageFormatter } from './ErrorCard';
5
1
  import EmptyState from './EmptyState';
2
+ import ErrorCard, { type ErrorMessageFormatter } from './ErrorCard';
6
3
  import LoadingState, { type LoadingStateVariant } from './LoadingState';
7
4
 
5
+ import type { LucideIcon } from 'lucide-react';
6
+ import type { ReactNode } from 'react';
7
+
8
8
  interface AsyncBoundaryEmpty {
9
9
  icon: LucideIcon;
10
10
  title: string;
@@ -55,11 +55,19 @@ export default function AsyncBoundary({
55
55
  }
56
56
 
57
57
  if (error) {
58
- return <ErrorCard error={error} onRetry={onRetry} formatError={formatError} />;
58
+ return (
59
+ <ErrorCard error={error} onRetry={onRetry} formatError={formatError} />
60
+ );
59
61
  }
60
62
 
61
63
  if (isEmpty && empty) {
62
- return <EmptyState icon={empty.icon} title={empty.title} description={empty.description} />;
64
+ return (
65
+ <EmptyState
66
+ icon={empty.icon}
67
+ title={empty.title}
68
+ description={empty.description}
69
+ />
70
+ );
63
71
  }
64
72
 
65
73
  return <>{children}</>;
@@ -1,11 +1,14 @@
1
- import type { LucideIcon } from 'lucide-react';
2
- import type { ComponentType, ReactNode } from 'react';
3
-
4
1
  import { cn } from '../cn';
5
2
  import { Button } from '../primitives/button';
6
3
  import { Card, CardContent } from '../primitives/card';
7
4
 
8
- export type EmptyStateVariant = 'not-configured' | 'no-results' | 'disabled-context';
5
+ import type { LucideIcon } from 'lucide-react';
6
+ import type { ComponentType, ReactNode } from 'react';
7
+
8
+ export type EmptyStateVariant =
9
+ | 'not-configured'
10
+ | 'no-results'
11
+ | 'disabled-context';
9
12
 
10
13
  /**
11
14
  * Visual density.
@@ -45,67 +48,94 @@ interface EmptyStateSecondaryAction {
45
48
  href: string;
46
49
  }
47
50
 
48
- interface EmptyStateProps {
49
- icon: LucideIcon;
51
+ interface EmptyStateCommonProps {
50
52
  title: string;
51
53
  description?: ReactNode;
54
+ action?: EmptyStateAction;
55
+ secondaryAction?: EmptyStateSecondaryAction;
56
+ /** Host link component for `secondaryAction.href` (defaults to `<a>`). */
57
+ linkComponent?: EmptyStateLinkComponent;
58
+ className?: string;
59
+ }
60
+
61
+ /** `comfortable` / `dense` render an icon block, so the icon is required. */
62
+ interface EmptyStateIconicProps extends EmptyStateCommonProps {
63
+ size?: Exclude<EmptyStateSize, 'inline'>;
64
+ icon: LucideIcon;
52
65
  /** Optional illustration or extra content above the title */
53
66
  illustration?: ReactNode;
54
67
  /** Visual variant — drives default iconBg/iconColor unless overridden. */
55
68
  variant?: EmptyStateVariant;
56
- size?: EmptyStateSize;
57
69
  /** Icon tint — overrides variant defaults */
58
70
  iconBg?: string;
59
71
  iconColor?: string;
60
- action?: EmptyStateAction;
61
- secondaryAction?: EmptyStateSecondaryAction;
62
- /** Host link component for `secondaryAction.href` (defaults to `<a>`). */
63
- linkComponent?: EmptyStateLinkComponent;
64
- className?: string;
65
72
  }
66
73
 
67
- const VARIANT_DEFAULTS: Record<EmptyStateVariant, { iconBg: string; iconColor: string }> = {
74
+ /**
75
+ * `inline` is text-only by definition — no icon block, therefore no icon,
76
+ * illustration, variant or icon tint. They are typed `never` rather than
77
+ * silently ignored: an accepted-but-unrendered prop is how callers ended up
78
+ * importing a lucide icon that renders nowhere.
79
+ */
80
+ interface EmptyStateInlineProps extends EmptyStateCommonProps {
81
+ size: 'inline';
82
+ icon?: never;
83
+ illustration?: never;
84
+ variant?: never;
85
+ iconBg?: never;
86
+ iconColor?: never;
87
+ }
88
+
89
+ type EmptyStateProps = EmptyStateIconicProps | EmptyStateInlineProps;
90
+
91
+ const VARIANT_DEFAULTS: Record<
92
+ EmptyStateVariant,
93
+ { iconBg: string; iconColor: string }
94
+ > = {
68
95
  'not-configured': { iconBg: 'bg-info/10', iconColor: 'text-info' },
69
96
  'no-results': { iconBg: 'bg-warning/10', iconColor: 'text-warning' },
70
97
  'disabled-context': { iconBg: 'bg-muted', iconColor: 'text-ink-3' },
71
98
  };
72
99
 
73
- export default function EmptyState({
74
- icon: Icon,
75
- title,
76
- description,
77
- illustration,
78
- variant = 'not-configured',
79
- size = 'comfortable',
80
- iconBg,
81
- iconColor,
82
- action,
83
- secondaryAction,
84
- linkComponent,
85
- className,
86
- }: Readonly<EmptyStateProps>) {
100
+ export default function EmptyState(props: Readonly<EmptyStateProps>) {
101
+ const { title, description, action, secondaryAction, linkComponent, className } =
102
+ props;
87
103
  const Link = linkComponent ?? DefaultLink;
88
- const defaults = VARIANT_DEFAULTS[variant];
89
- const resolvedIconBg = iconBg ?? defaults.iconBg;
90
- const resolvedIconColor = iconColor ?? defaults.iconColor;
91
104
 
92
- if (size === 'inline') {
105
+ if (props.size === 'inline') {
93
106
  return (
94
- <div className={cn('flex items-center justify-center px-3 py-6 text-center text-body-2 text-ink-4', className)}>
107
+ <div
108
+ className={cn(
109
+ 'flex items-center justify-center px-3 py-6 text-center text-body-2 text-ink-4',
110
+ className,
111
+ )}
112
+ >
95
113
  <div className="max-w-sm space-y-1">
96
114
  <p className="text-ink-3">{title}</p>
97
115
  {description && <p className="text-ink-4">{description}</p>}
98
116
  {(action || secondaryAction) && (
99
117
  <div className="mt-3 flex items-center justify-center gap-2">
100
118
  {action && (
101
- <Button size="sm" variant="outline" onClick={action.onClick} className="h-7 gap-1.5 text-body-2">
119
+ <Button
120
+ size="sm"
121
+ variant="outline"
122
+ onClick={action.onClick}
123
+ className="h-7 gap-1.5 text-body-2"
124
+ >
102
125
  {action.icon && <action.icon className="h-3.5 w-3.5" />}
103
126
  {action.label}
104
127
  </Button>
105
128
  )}
106
129
  {secondaryAction && (
107
- <Button asChild size="sm" variant="ghost" className="h-7 px-2 text-body-2">
108
- <Link href={secondaryAction.href}>{secondaryAction.label}</Link>
130
+ <Button
131
+ asChild
132
+ size="sm"
133
+ variant="ghost"
134
+ className="h-7 px-2 text-body-2"
135
+ >
136
+ <Link href={secondaryAction.href}>
137
+ {secondaryAction.label}
138
+ </Link>
109
139
  </Button>
110
140
  )}
111
141
  </div>
@@ -115,6 +145,18 @@ export default function EmptyState({
115
145
  );
116
146
  }
117
147
 
148
+ const {
149
+ icon: Icon,
150
+ illustration,
151
+ variant = 'not-configured',
152
+ size = 'comfortable',
153
+ iconBg,
154
+ iconColor,
155
+ } = props;
156
+ const defaults = VARIANT_DEFAULTS[variant];
157
+ const resolvedIconBg = iconBg ?? defaults.iconBg;
158
+ const resolvedIconColor = iconColor ?? defaults.iconColor;
159
+
118
160
  if (size === 'dense') {
119
161
  return (
120
162
  <div
@@ -124,24 +166,41 @@ export default function EmptyState({
124
166
  )}
125
167
  >
126
168
  {illustration ?? (
127
- <div className={cn('h-9 w-9 rounded-xl flex items-center justify-center mb-3', resolvedIconBg)}>
169
+ <div
170
+ className={cn(
171
+ 'h-9 w-9 rounded-xl flex items-center justify-center mb-3',
172
+ resolvedIconBg,
173
+ )}
174
+ >
128
175
  <Icon className={cn('h-4 w-4', resolvedIconColor)} />
129
176
  </div>
130
177
  )}
131
178
  <p className="text-body-1 font-semibold text-ink">{title}</p>
132
179
  {description && (
133
- <p className="mt-1 max-w-md text-body-2 leading-snug text-ink-3">{description}</p>
180
+ <p className="mt-1 max-w-md text-body-2 leading-snug text-ink-3">
181
+ {description}
182
+ </p>
134
183
  )}
135
184
  {(action || secondaryAction) && (
136
185
  <div className="mt-3 flex items-center gap-2">
137
186
  {action && (
138
- <Button size="sm" variant="outline" onClick={action.onClick} className="h-7 gap-1.5 text-body-2">
187
+ <Button
188
+ size="sm"
189
+ variant="outline"
190
+ onClick={action.onClick}
191
+ className="h-7 gap-1.5 text-body-2"
192
+ >
139
193
  {action.icon && <action.icon className="h-3.5 w-3.5" />}
140
194
  {action.label}
141
195
  </Button>
142
196
  )}
143
197
  {secondaryAction && (
144
- <Button asChild size="sm" variant="ghost" className="h-7 px-2 text-body-2">
198
+ <Button
199
+ asChild
200
+ size="sm"
201
+ variant="ghost"
202
+ className="h-7 px-2 text-body-2"
203
+ >
145
204
  <Link href={secondaryAction.href}>{secondaryAction.label}</Link>
146
205
  </Button>
147
206
  )}
@@ -152,21 +211,35 @@ export default function EmptyState({
152
211
  }
153
212
 
154
213
  return (
155
- <Card className={cn('border-2 border-dashed border-border/50 rounded-xl', className)}>
214
+ <Card
215
+ className={cn(
216
+ 'border-2 border-dashed border-border/50 rounded-xl',
217
+ className,
218
+ )}
219
+ >
156
220
  <CardContent className="flex flex-col items-center justify-center py-16 text-center">
157
221
  {illustration ?? (
158
- <div className={`h-16 w-16 rounded-2xl flex items-center justify-center mb-5 ${resolvedIconBg}`}>
222
+ <div
223
+ className={`h-16 w-16 rounded-2xl flex items-center justify-center mb-5 ${resolvedIconBg}`}
224
+ >
159
225
  <Icon className={`h-7 w-7 ${resolvedIconColor}`} />
160
226
  </div>
161
227
  )}
162
228
  <p className="text-subtitle font-semibold text-ink">{title}</p>
163
229
  {description && (
164
- <p className="text-body-1 mt-2 max-w-sm text-ink-3 leading-relaxed">{description}</p>
230
+ <p className="text-body-1 mt-2 max-w-sm text-ink-3 leading-relaxed">
231
+ {description}
232
+ </p>
165
233
  )}
166
234
  {(action || secondaryAction) && (
167
235
  <div className="mt-6 flex items-center gap-3">
168
236
  {action && (
169
- <Button size="sm" variant="outline" onClick={action.onClick} className="gap-2 h-10 px-5">
237
+ <Button
238
+ size="sm"
239
+ variant="outline"
240
+ onClick={action.onClick}
241
+ className="gap-2 h-10 px-5"
242
+ >
170
243
  {action.icon && <action.icon className="h-4 w-4" />}
171
244
  {action.label}
172
245
  </Button>
@@ -0,0 +1,98 @@
1
+ import { cn } from '../cn';
2
+
3
+ import type { ReactNode } from 'react';
4
+
5
+ /**
6
+ * One label/value row inside a record card — mirrors one table column.
7
+ *
8
+ * `key` exists because a card's rows are keyed by the COLUMN, and a column's
9
+ * identity is its field key, not its user-facing label (two columns may carry
10
+ * the same label). It defaults to `label` for the common case where the label
11
+ * is already unique.
12
+ */
13
+ export interface RecordCardField {
14
+ readonly key?: string;
15
+ readonly label: string;
16
+ readonly value: ReactNode;
17
+ /**
18
+ * `data-*` attributes for the row element — e.g. the same hook the equivalent
19
+ * table cell carries, so a click-to-context resolver lands on the identical
20
+ * node at every viewport width. Deliberately `data-*` only: styling stays in
21
+ * this primitive, so a caller cannot re-open the drift it closed.
22
+ */
23
+ readonly rowAttributes?: Readonly<Record<`data-${string}`, string>>;
24
+ }
25
+
26
+ export interface RecordCardListProps<T> {
27
+ readonly items: readonly T[];
28
+ readonly getKey: (item: T) => string;
29
+ /** Card header rendered above the field list (title, status, row toggle). */
30
+ readonly renderHeader?: (item: T) => ReactNode;
31
+ readonly getFields: (item: T) => readonly RecordCardField[];
32
+ /** Row actions, rendered right-aligned below a divider. */
33
+ readonly renderActions?: (item: T) => ReactNode;
34
+ /** Free block appended after the actions (expanded detail). */
35
+ readonly renderDetail?: (item: T) => ReactNode;
36
+ /** Extra classes for the list element. */
37
+ readonly className?: string;
38
+ }
39
+
40
+ /**
41
+ * Small-viewport (below `md`) layout for a record list: one stacked card per
42
+ * record with the table's columns rendered as label/value rows, instead of a
43
+ * horizontal-scroll-only table.
44
+ *
45
+ * This is the ONE definition of that card chrome — spacing, border, divider,
46
+ * label/value alignment. Callers name their columns and their actions; they do
47
+ * not restate the chrome. Deliberately NOT parameterised by card class: a
48
+ * per-caller class hook is how the three copies this replaced drifted apart in
49
+ * the first place.
50
+ */
51
+ export function RecordCardList<T>(props: Readonly<RecordCardListProps<T>>) {
52
+ const {
53
+ items,
54
+ getKey,
55
+ renderHeader,
56
+ getFields,
57
+ renderActions,
58
+ renderDetail,
59
+ className,
60
+ } = props;
61
+
62
+ return (
63
+ <ul className={cn('space-y-2', className)}>
64
+ {items.map((item) => {
65
+ const actions = renderActions?.(item);
66
+ const detail = renderDetail?.(item);
67
+ return (
68
+ <li
69
+ key={getKey(item)}
70
+ className="space-y-2 rounded-lg border border-rule bg-paper-elev p-3"
71
+ >
72
+ {renderHeader?.(item)}
73
+ <dl className="space-y-1.5">
74
+ {getFields(item).map((field) => (
75
+ <div
76
+ key={field.key ?? field.label}
77
+ {...field.rowAttributes}
78
+ className="flex justify-between gap-3 text-sm"
79
+ >
80
+ <dt className="shrink-0 text-ink-3">{field.label}</dt>
81
+ <dd className="text-right text-ink-2">{field.value}</dd>
82
+ </div>
83
+ ))}
84
+ </dl>
85
+ {actions ? (
86
+ <div className="flex items-center justify-end gap-2 border-t border-rule/50 pt-2">
87
+ {actions}
88
+ </div>
89
+ ) : null}
90
+ {detail}
91
+ </li>
92
+ );
93
+ })}
94
+ </ul>
95
+ );
96
+ }
97
+
98
+ export default RecordCardList;
@@ -0,0 +1,117 @@
1
+ /**
2
+ * An EMBEDDED PageShell must not touch the topbar.
3
+ *
4
+ * ── THE DEFECT ────────────────────────────────────────────────────────────
5
+ *
6
+ * `embedded` means "the host page already owns the topbar — render only my
7
+ * body". But `usePageMeta` was called UNCONDITIONALLY, above the `embedded`
8
+ * check, and the page-meta store is a STACK: "nested pages can push their own
9
+ * meta; on unmount the outer meta is restored".
10
+ *
11
+ * So an embedded shell pushed its own `title`, `description`, `eyebrow`,
12
+ * `backTo` and `topbarActions` OVER its host's — the precise opposite of what
13
+ * embedding means. The host's title and back button silently became the
14
+ * child's for as long as the child was mounted, and the page-meta contract
15
+ * ("never render a back button inside the page body… move it into
16
+ * usePageMeta") made that the ONLY back affordance on screen, so it pointed at
17
+ * the wrong parent.
18
+ *
19
+ * A hook cannot be called conditionally, so the fix is structural: `PageShell`
20
+ * calls no hooks and only chooses between two components. These tests pin the
21
+ * OBSERVABLE property — whether meta is registered — not the file layout, so
22
+ * any future refactor that reintroduces the push fails them.
23
+ *
24
+ * Runs under the host-web vitest mirror (this package carries no vitest dep).
25
+ */
26
+ import { FileQuestion } from 'lucide-react';
27
+ import { renderToStaticMarkup } from 'react-dom/server';
28
+ import { describe, expect, it, vi, beforeEach } from 'vitest';
29
+
30
+
31
+ const registered: unknown[] = [];
32
+
33
+ // The kernel reaches the page-meta store through the HostBridge singleton,
34
+ // never a host import — so the bridge is the seam to observe.
35
+ vi.mock('../../lib/biome-host/host-bridge', async () => {
36
+ const actual = await vi.importActual<Record<string, unknown>>(
37
+ '../../lib/biome-host/host-bridge',
38
+ );
39
+ return {
40
+ ...actual,
41
+ useHostBridge: () => ({
42
+ pageMeta: {
43
+ usePageMeta: (meta: unknown) => {
44
+ registered.push(meta);
45
+ },
46
+ },
47
+ }),
48
+ };
49
+ });
50
+
51
+ const { default: PageShell } = await import('./page-shell');
52
+
53
+ beforeEach(() => {
54
+ registered.length = 0;
55
+ });
56
+
57
+ const META = {
58
+ icon: FileQuestion,
59
+ title: 'Child Title',
60
+ description: 'Child description',
61
+ eyebrow: 'Child eyebrow',
62
+ backTo: { to: '/child-parent', label: 'Child parent' },
63
+ } as const;
64
+
65
+ describe('PageShell page-meta ownership', () => {
66
+ it('registers NOTHING when embedded — the host owns the topbar', () => {
67
+ // THE BUG, directly. Before the fix this registered the child's meta,
68
+ // replacing the host's title and back button on a stack-based store.
69
+ renderToStaticMarkup(
70
+ <PageShell {...META} embedded>
71
+ <p>body</p>
72
+ </PageShell>,
73
+ );
74
+ expect(registered).toEqual([]);
75
+ });
76
+
77
+ it('registers its meta when NOT embedded — a full page owns its topbar', () => {
78
+ // The other half: the fix must not silence the normal case.
79
+ renderToStaticMarkup(
80
+ <PageShell {...META}>
81
+ <p>body</p>
82
+ </PageShell>,
83
+ );
84
+ expect(registered).toHaveLength(1);
85
+ expect(registered[0]).toMatchObject({
86
+ title: 'Child Title',
87
+ description: 'Child description',
88
+ eyebrow: 'Child eyebrow',
89
+ backTo: { to: '/child-parent' },
90
+ });
91
+ });
92
+
93
+ it('still renders the embedded body — not registering is not "render nothing"', () => {
94
+ const html = renderToStaticMarkup(
95
+ <PageShell {...META} embedded>
96
+ <p>embedded-body-marker</p>
97
+ </PageShell>,
98
+ );
99
+ expect(html).toContain('embedded-body-marker');
100
+ });
101
+
102
+ it('renders the embedded sub-tab strip, which is the child’s own chrome', () => {
103
+ // Embedding suppresses the TOPBAR meta, not the child's in-body tabs.
104
+ const html = renderToStaticMarkup(
105
+ <PageShell
106
+ {...META}
107
+ embedded
108
+ tabs={[{ value: 'a', label: 'Alpha' }]}
109
+ activeTab="a"
110
+ >
111
+ <p>body</p>
112
+ </PageShell>,
113
+ );
114
+ expect(html).toContain('Alpha');
115
+ expect(registered).toEqual([]);
116
+ });
117
+ });