@xemahq/ui-kernel 0.10.0 → 0.11.0

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 (377) 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.map +1 -1
  182. package/dist/ui/chrome/page-shell.js +9 -3
  183. package/dist/ui/chrome/page-shell.js.map +1 -1
  184. package/dist/ui/chrome/status-badge.d.ts.map +1 -1
  185. package/dist/ui/chrome/status-badge.js +1 -1
  186. package/dist/ui/chrome/status-badge.js.map +1 -1
  187. package/dist/ui/design-tokens.d.ts +4 -6
  188. package/dist/ui/design-tokens.d.ts.map +1 -1
  189. package/dist/ui/design-tokens.js +17 -11
  190. package/dist/ui/design-tokens.js.map +1 -1
  191. package/dist/ui/index.d.ts +1 -0
  192. package/dist/ui/index.d.ts.map +1 -1
  193. package/dist/ui/index.js +1 -0
  194. package/dist/ui/index.js.map +1 -1
  195. package/dist/ui/primitives/async-combobox.d.ts.map +1 -1
  196. package/dist/ui/primitives/async-combobox.js +4 -2
  197. package/dist/ui/primitives/async-combobox.js.map +1 -1
  198. package/dist/ui/primitives/badge.d.ts +2 -2
  199. package/dist/ui/primitives/badge.d.ts.map +1 -1
  200. package/dist/ui/primitives/badge.js +3 -3
  201. package/dist/ui/primitives/badge.js.map +1 -1
  202. package/dist/ui/primitives/button.d.ts +2 -2
  203. package/dist/ui/primitives/button.d.ts.map +1 -1
  204. package/dist/ui/primitives/button.js +5 -5
  205. package/dist/ui/primitives/button.js.map +1 -1
  206. package/dist/ui/primitives/overflow-tabs.d.ts.map +1 -1
  207. package/dist/ui/primitives/overflow-tabs.js +19 -12
  208. package/dist/ui/primitives/overflow-tabs.js.map +1 -1
  209. package/dist/ui/primitives/preview-device-frame.js +8 -4
  210. package/dist/ui/primitives/preview-device-frame.js.map +1 -1
  211. package/dist/ui/primitives/tag-multi-select.d.ts.map +1 -1
  212. package/dist/ui/primitives/tag-multi-select.js +10 -5
  213. package/dist/ui/primitives/tag-multi-select.js.map +1 -1
  214. package/dist/ui/primitives/url-preview-chrome.d.ts.map +1 -1
  215. package/dist/ui/primitives/url-preview-chrome.js.map +1 -1
  216. package/dist/vista/GenericCatalogueSurface.d.ts.map +1 -1
  217. package/dist/vista/GenericCatalogueSurface.js +5 -3
  218. package/dist/vista/GenericCatalogueSurface.js.map +1 -1
  219. package/dist/vista/VistaPanel.d.ts.map +1 -1
  220. package/dist/vista/VistaPanel.js +8 -4
  221. package/dist/vista/VistaPanel.js.map +1 -1
  222. package/dist/vista/html/CustomUiFrame.d.ts.map +1 -1
  223. package/dist/vista/html/CustomUiFrame.js +2 -1
  224. package/dist/vista/html/CustomUiFrame.js.map +1 -1
  225. package/dist/vista/html/custom-ui-frame-bridge.d.ts.map +1 -1
  226. package/dist/vista/html/custom-ui-frame-bridge.js +6 -3
  227. package/dist/vista/html/custom-ui-frame-bridge.js.map +1 -1
  228. package/dist/vista/html/custom-ui-intents.d.ts.map +1 -1
  229. package/dist/vista/html/custom-ui-intents.js +13 -15
  230. package/dist/vista/html/custom-ui-intents.js.map +1 -1
  231. package/dist/vista/surface-catalogue.d.ts.map +1 -1
  232. package/dist/vista/surface-catalogue.js +6 -3
  233. package/dist/vista/surface-catalogue.js.map +1 -1
  234. package/dist/vista/surfaces/FormSurface.d.ts.map +1 -1
  235. package/dist/vista/surfaces/FormSurface.js +20 -7
  236. package/dist/vista/surfaces/FormSurface.js.map +1 -1
  237. package/dist/vista/surfaces/TableSurface.d.ts.map +1 -1
  238. package/dist/vista/surfaces/TableSurface.js +2 -1
  239. package/dist/vista/surfaces/TableSurface.js.map +1 -1
  240. package/dist/vista/surfaces/blob-surfaces.d.ts.map +1 -1
  241. package/dist/vista/surfaces/blob-surfaces.js +7 -2
  242. package/dist/vista/surfaces/blob-surfaces.js.map +1 -1
  243. package/dist/vista/surfaces/elicitation-transport.d.ts.map +1 -1
  244. package/dist/vista/surfaces/elicitation-transport.js +14 -7
  245. package/dist/vista/surfaces/elicitation-transport.js.map +1 -1
  246. package/dist/vista/surfaces/file-surface-utils.d.ts.map +1 -1
  247. package/dist/vista/surfaces/file-surface-utils.js +8 -4
  248. package/dist/vista/surfaces/file-surface-utils.js.map +1 -1
  249. package/dist/vista/surfaces/register-surfaces.js +2 -1
  250. package/dist/vista/surfaces/register-surfaces.js.map +1 -1
  251. package/dist/vista/surfaces/text-surfaces.d.ts +1 -1
  252. package/dist/vista/surfaces/text-surfaces.d.ts.map +1 -1
  253. package/dist/vista/surfaces/text-surfaces.js +13 -7
  254. package/dist/vista/surfaces/text-surfaces.js.map +1 -1
  255. package/dist/vista/use-vista-tabs.d.ts.map +1 -1
  256. package/dist/vista/use-vista-tabs.js +8 -4
  257. package/dist/vista/use-vista-tabs.js.map +1 -1
  258. package/dist/vista/vista-code-renderer.d.ts.map +1 -1
  259. package/dist/vista/vista-code-renderer.js.map +1 -1
  260. package/dist/vista/vista-file-source.d.ts.map +1 -1
  261. package/dist/vista/vista-file-source.js +9 -5
  262. package/dist/vista/vista-file-source.js.map +1 -1
  263. package/dist/vista/vista-form-host.d.ts.map +1 -1
  264. package/dist/vista/vista-form-host.js +1 -1
  265. package/dist/vista/vista-form-host.js.map +1 -1
  266. package/dist/vista/vista-model.d.ts.map +1 -1
  267. package/dist/vista/vista-model.js +5 -3
  268. package/dist/vista/vista-model.js.map +1 -1
  269. package/dist/vista/vista-open-context.d.ts.map +1 -1
  270. package/dist/vista/vista-open-context.js +1 -1
  271. package/dist/vista/vista-open-context.js.map +1 -1
  272. package/dist/vista/vista-payloads.d.ts.map +1 -1
  273. package/dist/vista/vista-payloads.js +127 -63
  274. package/dist/vista/vista-payloads.js.map +1 -1
  275. package/dist/vista/vista-tabs-manifest.d.ts.map +1 -1
  276. package/dist/vista/vista-tabs-manifest.js +18 -9
  277. package/dist/vista/vista-tabs-manifest.js.map +1 -1
  278. package/dist/vista/vista-tools.d.ts.map +1 -1
  279. package/dist/vista/vista-tools.js +12 -6
  280. package/dist/vista/vista-tools.js.map +1 -1
  281. package/package.json +3 -3
  282. package/src/lib/biome-host/agent-validation.ts +37 -13
  283. package/src/lib/biome-host/biome-registry.ts +48 -13
  284. package/src/lib/biome-host/biome-scope-hooks.ts +3 -1
  285. package/src/lib/biome-host/biome-scoped-query.ts +7 -6
  286. package/src/lib/biome-host/frontend-biome.ts +1 -1
  287. package/src/lib/biome-host/host-bridge.ts +5 -4
  288. package/src/lib/biome-host/i18n-hooks.ts +1 -0
  289. package/src/lib/biome-host/realtime-hooks.ts +1 -0
  290. package/src/lib/biome-host/session-contributions.ts +1 -1
  291. package/src/lib/biome-host/use-mutation-with-error-toast.ts +4 -2
  292. package/src/lib/biome-host/use-page-state.ts +27 -10
  293. package/src/lib/capabilities/capability-provider.tsx +12 -5
  294. package/src/lib/capabilities/use-capability.ts +8 -4
  295. package/src/lib/contribution-registry/contribution-registry.ts +3 -1
  296. package/src/lib/system-bus/deeplink.ts +14 -4
  297. package/src/lib/system-bus/host-ports.ts +3 -7
  298. package/src/lib/system-bus/intent-registry.ts +12 -8
  299. package/src/lib/system-bus/intents.ts +6 -2
  300. package/src/lib/system-bus/palette.ts +2 -1
  301. package/src/lib/system-bus/system-bus-builder.ts +4 -2
  302. package/src/lib/system-bus/windows.ts +1 -1
  303. package/src/offline/outbox.test.ts +12 -3
  304. package/src/offline/outbox.ts +5 -1
  305. package/src/offline/react-hooks.ts +5 -2
  306. package/src/org-db/components/DbResultTable.tsx +48 -15
  307. package/src/registry/lib/agent-validation-host.ts +1 -2
  308. package/src/registry/lib/biome-slot.tsx +7 -4
  309. package/src/registry/lib/primitives/SessionEventCard.tsx +29 -5
  310. package/src/registry/lib/primitives/SessionEventTimeline.tsx +9 -3
  311. package/src/registry/lib/primitives/SessionTabbedDrawer.tsx +15 -5
  312. package/src/registry/lib/session-context-provider.tsx +1 -1
  313. package/src/registry/lib/session-selectors.ts +66 -27
  314. package/src/session/comments/CommentRail.tsx +2 -2
  315. package/src/session/shell/SessionWorkspaceShell.tsx +2 -2
  316. package/src/session-kit/approvals/ApprovalCard.tsx +7 -2
  317. package/src/session-kit/approvals/ApprovalsCenter.tsx +13 -4
  318. package/src/session-kit/combobox/Combobox.tsx +42 -11
  319. package/src/session-kit/display/MD.tsx +14 -5
  320. package/src/ui/branding/app-branding-provider.tsx +2 -3
  321. package/src/ui/branding/sanitize.ts +18 -6
  322. package/src/ui/capture/document-preview.tsx +84 -19
  323. package/src/ui/capture/field-spec-to-zod.ts +62 -14
  324. package/src/ui/capture/field-spec-validate.ts +132 -43
  325. package/src/ui/capture/field-spec.test.ts +2 -2
  326. package/src/ui/capture/field-spec.ts +41 -10
  327. package/src/ui/capture/schema-field-input.tsx +218 -38
  328. package/src/ui/capture/schema-form.tsx +54 -13
  329. package/src/ui/capture/use-prefill.ts +50 -17
  330. package/src/ui/capture/use-schema-validation.ts +45 -13
  331. package/src/ui/capture/use-wizard.ts +57 -11
  332. package/src/ui/capture/value-format.ts +14 -4
  333. package/src/ui/capture/wizard.tsx +9 -5
  334. package/src/ui/charts/bar-chart.tsx +8 -4
  335. package/src/ui/charts/chart-frame.tsx +18 -5
  336. package/src/ui/charts/chart-utils.ts +47 -15
  337. package/src/ui/charts/donut-chart.tsx +24 -6
  338. package/src/ui/charts/line-chart.tsx +34 -12
  339. package/src/ui/charts/sparkline.tsx +17 -9
  340. package/src/ui/chrome/AsyncBoundary.tsx +14 -6
  341. package/src/ui/chrome/EmptyState.tsx +116 -43
  342. package/src/ui/chrome/RecordCardList.tsx +98 -0
  343. package/src/ui/chrome/page-shell.tsx +32 -8
  344. package/src/ui/chrome/status-badge.tsx +8 -4
  345. package/src/ui/design-tokens.ts +39 -13
  346. package/src/ui/index.ts +5 -0
  347. package/src/ui/primitives/async-combobox.tsx +7 -3
  348. package/src/ui/primitives/badge.tsx +14 -5
  349. package/src/ui/primitives/button.tsx +13 -6
  350. package/src/ui/primitives/overflow-tabs.tsx +46 -16
  351. package/src/ui/primitives/preview-device-frame.tsx +12 -4
  352. package/src/ui/primitives/tag-multi-select.tsx +30 -9
  353. package/src/ui/primitives/url-preview-chrome.tsx +1 -0
  354. package/src/vista/GenericCatalogueSurface.tsx +7 -5
  355. package/src/vista/VistaPanel.tsx +12 -4
  356. package/src/vista/html/CustomUiFrame.spec.tsx +3 -1
  357. package/src/vista/html/CustomUiFrame.tsx +3 -1
  358. package/src/vista/html/custom-ui-frame-bridge.ts +9 -3
  359. package/src/vista/html/custom-ui-intents.spec.ts +3 -1
  360. package/src/vista/html/custom-ui-intents.ts +19 -15
  361. package/src/vista/surface-catalogue.ts +9 -3
  362. package/src/vista/surfaces/FormSurface.tsx +27 -10
  363. package/src/vista/surfaces/TableSurface.tsx +4 -3
  364. package/src/vista/surfaces/blob-surfaces.tsx +13 -3
  365. package/src/vista/surfaces/elicitation-transport.ts +21 -7
  366. package/src/vista/surfaces/file-surface-utils.ts +11 -4
  367. package/src/vista/surfaces/register-surfaces.tsx +3 -1
  368. package/src/vista/surfaces/text-surfaces.tsx +21 -8
  369. package/src/vista/use-vista-tabs.ts +12 -4
  370. package/src/vista/vista-code-renderer.tsx +6 -5
  371. package/src/vista/vista-file-source.tsx +15 -14
  372. package/src/vista/vista-form-host.tsx +3 -8
  373. package/src/vista/vista-model.ts +10 -3
  374. package/src/vista/vista-open-context.tsx +3 -8
  375. package/src/vista/vista-payloads.ts +186 -63
  376. package/src/vista/vista-tabs-manifest.ts +28 -13
  377. 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;
@@ -1,8 +1,8 @@
1
1
  import { FileQuestion, type LucideIcon } from 'lucide-react';
2
2
  import { type ReactNode } from 'react';
3
3
 
4
- import { useHostBridge, type PageBackTarget } from '../../lib/biome-host';
5
4
  import EmptyState from './EmptyState';
5
+ import { useHostBridge, type PageBackTarget } from '../../lib/biome-host';
6
6
  import { Tabs, TabsList, TabsTrigger } from '../primitives/tabs';
7
7
 
8
8
  interface TabDef {
@@ -63,7 +63,13 @@ export default function PageShell({
63
63
  // Single source of truth for the topbar title. Pages that bypass
64
64
  // PageShell call the page-meta hook directly; PageShell wraps the same
65
65
  // hook so consumers don't need to register meta twice.
66
- useHostBridge().pageMeta.usePageMeta({ title, description, eyebrow, backTo, topbarActions });
66
+ useHostBridge().pageMeta.usePageMeta({
67
+ title,
68
+ description,
69
+ eyebrow,
70
+ backTo,
71
+ topbarActions,
72
+ });
67
73
  if (embedded) {
68
74
  // Embedded mode: the host page already provides the title + tabs +
69
75
  // context, so we render ONLY the child content + any sub-tab strip +
@@ -75,7 +81,11 @@ export default function PageShell({
75
81
  <div className="shrink-0 border-b border-rule bg-paper-elev/40">
76
82
  <div className="flex items-center gap-3 px-4 py-2 lg:px-6">
77
83
  {tabs && tabs.length > 0 && (
78
- <Tabs value={activeTab} onValueChange={onTabChange} className="flex-1 min-w-0">
84
+ <Tabs
85
+ value={activeTab}
86
+ onValueChange={onTabChange}
87
+ className="flex-1 min-w-0"
88
+ >
79
89
  <div className="overflow-x-auto">
80
90
  <TabsList className="h-7 bg-transparent p-0 gap-0">
81
91
  {tabs.map((tab) => (
@@ -86,7 +96,9 @@ export default function PageShell({
86
96
  >
87
97
  {tab.label}
88
98
  {tab.count !== undefined && (
89
- <span className="ml-1.5 text-caption tabular-nums opacity-70">{tab.count}</span>
99
+ <span className="ml-1.5 text-caption tabular-nums opacity-70">
100
+ {tab.count}
101
+ </span>
90
102
  )}
91
103
  {tab.indicator && (
92
104
  <span className="ml-1.5 inline-block h-1.5 w-1.5 rounded-full bg-warning" />
@@ -98,12 +110,18 @@ export default function PageShell({
98
110
  </Tabs>
99
111
  )}
100
112
  {!tabs && <div className="flex-1" />}
101
- {actions && <div className="flex items-center gap-2 shrink-0">{actions}</div>}
113
+ {actions && (
114
+ <div className="flex items-center gap-2 shrink-0">
115
+ {actions}
116
+ </div>
117
+ )}
102
118
  </div>
103
119
  </div>
104
120
  ) : null}
105
121
  <div className="flex-1 overflow-auto min-h-0">
106
- <div className="flex h-full min-h-0 flex-col px-4 pb-4 pt-3 lg:px-6">{children}</div>
122
+ <div className="flex h-full min-h-0 flex-col px-4 pb-4 pt-3 lg:px-6">
123
+ {children}
124
+ </div>
107
125
  </div>
108
126
  </div>
109
127
  );
@@ -116,7 +134,11 @@ export default function PageShell({
116
134
  <div className="shrink-0 border-b border-border/50 px-4 sm:px-5 lg:px-8">
117
135
  <div className="flex min-h-[34px] flex-col gap-2 py-1.5 sm:flex-row sm:items-center sm:gap-3 sm:py-0">
118
136
  {tabs && tabs.length > 0 && (
119
- <Tabs value={activeTab} onValueChange={onTabChange} className="flex-1 min-w-0">
137
+ <Tabs
138
+ value={activeTab}
139
+ onValueChange={onTabChange}
140
+ className="flex-1 min-w-0"
141
+ >
120
142
  <div className="overflow-x-auto">
121
143
  <TabsList className="h-7 bg-transparent p-0 gap-0">
122
144
  {tabs.map((tab) => (
@@ -127,7 +149,9 @@ export default function PageShell({
127
149
  >
128
150
  {tab.label}
129
151
  {tab.count !== undefined && (
130
- <span className="ml-1.5 text-caption tabular-nums opacity-60">{tab.count}</span>
152
+ <span className="ml-1.5 text-caption tabular-nums opacity-60">
153
+ {tab.count}
154
+ </span>
131
155
  )}
132
156
  {tab.indicator && (
133
157
  <span className="ml-1.5 inline-block h-1.5 w-1.5 rounded-full bg-warning" />
@@ -1,9 +1,9 @@
1
- import type { ReactNode } from 'react';
2
-
3
1
  import { cn } from '../cn';
4
2
  import { getStatusStyle } from '../design-tokens';
5
3
  import { Badge } from '../primitives/badge';
6
4
 
5
+ import type { ReactNode } from 'react';
6
+
7
7
  export type StatusBadgeSize = 'xs' | 'sm' | 'md';
8
8
 
9
9
  export interface StatusBadgeProps {
@@ -68,8 +68,12 @@ export default function StatusBadge({
68
68
  className,
69
69
  )}
70
70
  >
71
- {dot && <span className={cn('shrink-0 rounded-full', sz.dot, style.dot)} />}
72
- {children ?? <span className="capitalize">{status.replace(/_/g, ' ')}</span>}
71
+ {dot && (
72
+ <span className={cn('shrink-0 rounded-full', sz.dot, style.dot)} />
73
+ )}
74
+ {children ?? (
75
+ <span className="capitalize">{status.replace(/_/g, ' ')}</span>
76
+ )}
73
77
  </Badge>
74
78
  );
75
79
  }
@@ -142,8 +142,16 @@ export const STATUS_STYLES: Record<string, StatusStyle> = {
142
142
  manual_review: WARNING_STYLE,
143
143
  };
144
144
 
145
+ /**
146
+ * Style for an unrecognised status. Same value `STATUS_STYLES.pending` carries —
147
+ * referenced as the fragment rather than re-read out of the open `Record`, so
148
+ * the fallback is structurally guaranteed instead of being a second lookup that
149
+ * can itself miss (e.g. if the `pending` key were ever renamed).
150
+ */
151
+ const DEFAULT_STATUS_STYLE: StatusStyle = INFO_STYLE;
152
+
145
153
  export function getStatusStyle(status: string): StatusStyle {
146
- return STATUS_STYLES[status] ?? STATUS_STYLES.pending;
154
+ return STATUS_STYLES[status] ?? DEFAULT_STATUS_STYLE;
147
155
  }
148
156
 
149
157
  // ── Priority Styles ────────────────────────────────────────────────
@@ -156,6 +164,17 @@ export interface PriorityStyle {
156
164
  label: string;
157
165
  }
158
166
 
167
+ // Lowest priority — also the style for an unrecognised priority. Named so the
168
+ // map entry and `getPriorityStyle`'s fallback are the same proven value rather
169
+ // than a second `Record` lookup that can itself miss.
170
+ const PRIORITY_LOW_STYLE: PriorityStyle = {
171
+ badge: 'bg-paper-elev text-ink-3 border-border',
172
+ text: 'text-ink-3',
173
+ bg: 'bg-muted/30',
174
+ border: 'border-border',
175
+ label: 'Low',
176
+ };
177
+
159
178
  export const PRIORITY_STYLES: Record<string, PriorityStyle> = {
160
179
  p0: {
161
180
  badge: 'bg-destructive text-white border-destructive',
@@ -178,17 +197,11 @@ export const PRIORITY_STYLES: Record<string, PriorityStyle> = {
178
197
  border: 'border-warning/30',
179
198
  label: 'Medium',
180
199
  },
181
- p3: {
182
- badge: 'bg-paper-elev text-ink-3 border-border',
183
- text: 'text-ink-3',
184
- bg: 'bg-muted/30',
185
- border: 'border-border',
186
- label: 'Low',
187
- },
200
+ p3: PRIORITY_LOW_STYLE,
188
201
  };
189
202
 
190
203
  export function getPriorityStyle(priority: string): PriorityStyle {
191
- return PRIORITY_STYLES[priority] ?? PRIORITY_STYLES.p3;
204
+ return PRIORITY_STYLES[priority] ?? PRIORITY_LOW_STYLE;
192
205
  }
193
206
 
194
207
  // ── Severity Styles ────────────────────────────────────────────────
@@ -285,15 +298,28 @@ export const IMPORTANCE_STYLES: Record<number, { badge: string; label: string; s
285
298
 
286
299
  // ── Risk Level Styles ──────────────────────────────────────────────
287
300
 
288
- export const RISK_LEVEL_STYLES: Record<string, { badge: string; text: string }> = {
289
- low: { badge: 'bg-success/15 text-success dark:text-success border-success/30', text: 'text-success dark:text-success' },
301
+ export interface RiskLevelStyle {
302
+ badge: string;
303
+ text: string;
304
+ }
305
+
306
+ // Lowest risk — also the style for an unrecognised level. Named for the same
307
+ // reason as PRIORITY_LOW_STYLE: the fallback must be a proven value, not a
308
+ // second lookup into the open `Record`.
309
+ const RISK_LOW_STYLE: RiskLevelStyle = {
310
+ badge: 'bg-success/15 text-success dark:text-success border-success/30',
311
+ text: 'text-success dark:text-success',
312
+ };
313
+
314
+ export const RISK_LEVEL_STYLES: Record<string, RiskLevelStyle> = {
315
+ low: RISK_LOW_STYLE,
290
316
  medium: { badge: 'bg-warning/15 text-warning dark:text-warning border-warning/30', text: 'text-warning dark:text-warning' },
291
317
  high: { badge: 'bg-warning/15 text-warning dark:text-warning border-warning/30', text: 'text-warning dark:text-warning' },
292
318
  critical: { badge: 'bg-destructive/15 text-destructive dark:text-destructive border-destructive/30', text: 'text-destructive dark:text-destructive' },
293
319
  };
294
320
 
295
- export function getRiskLevelStyle(level: string): { badge: string; text: string } {
296
- return RISK_LEVEL_STYLES[level] ?? RISK_LEVEL_STYLES.low;
321
+ export function getRiskLevelStyle(level: string): RiskLevelStyle {
322
+ return RISK_LEVEL_STYLES[level] ?? RISK_LOW_STYLE;
297
323
  }
298
324
 
299
325
  // ── Agent Source Styles ────────────────────────────────────────────
package/src/ui/index.ts CHANGED
@@ -92,6 +92,11 @@ export {
92
92
  type EmptyStateLinkComponent,
93
93
  } from './chrome/EmptyState';
94
94
  export { StateCard } from './chrome/StateCard';
95
+ export {
96
+ RecordCardList,
97
+ type RecordCardField,
98
+ type RecordCardListProps,
99
+ } from './chrome/RecordCardList';
95
100
  export { default as PageHeader, PageToolbar } from './chrome/PageHeader';
96
101
  export { default as LoadingState, type LoadingStateVariant } from './chrome/LoadingState';
97
102
  export { default as AsyncBoundary } from './chrome/AsyncBoundary';