@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
@@ -8,9 +8,16 @@
8
8
  // can nudge "you still need to fill X" without waiting for a 422.
9
9
  // ═══════════════════════════════════════════════════════════════════════════
10
10
  import { useMemo } from 'react';
11
- import { z } from 'zod';
11
+ import { type z } from 'zod';
12
12
 
13
- import { CaptureFieldType, type CaptureFieldSpec, type CaptureSchema, type CaptureSection, type CaptureValues, toFieldList } from './field-spec';
13
+ import {
14
+ CaptureFieldType,
15
+ type CaptureFieldSpec,
16
+ type CaptureSchema,
17
+ type CaptureSection,
18
+ type CaptureValues,
19
+ toFieldList,
20
+ } from './field-spec';
14
21
  import { fieldSpecToZod, isEmptyValue } from './field-spec-to-zod';
15
22
 
16
23
  export interface SchemaValidationResult {
@@ -29,34 +36,52 @@ type ValidationInput =
29
36
  | readonly CaptureSection[];
30
37
 
31
38
  function isZodSchema(input: ValidationInput): input is z.ZodType {
32
- return typeof (input as z.ZodType)?.safeParse === 'function';
39
+ return 'safeParse' in input && typeof input.safeParse === 'function';
33
40
  }
34
41
 
35
42
  /** Deterministic required sweep over the flat spec list (nested-aware). */
36
- function sweepMissing(fields: readonly CaptureFieldSpec[], values: CaptureValues, prefix = ''): string[] {
43
+ function sweepMissing(
44
+ fields: readonly CaptureFieldSpec[],
45
+ values: CaptureValues,
46
+ prefix = '',
47
+ ): string[] {
37
48
  const missing: string[] = [];
38
49
  for (const field of fields) {
39
50
  const path = prefix ? `${prefix}.${field.key}` : field.key;
40
- const value = values?.[field.key];
51
+ const value = values[field.key];
41
52
  if (field.type === CaptureFieldType.Object) {
42
- if (field.required && isEmptyValue(value)) missing.push(path);
53
+ if (field.required && isEmptyValue(value)) {
54
+ missing.push(path);
55
+ }
43
56
  if (value && typeof value === 'object' && !Array.isArray(value)) {
44
- missing.push(...sweepMissing(field.fields ?? [], value as CaptureValues, path));
57
+ missing.push(
58
+ ...sweepMissing(field.fields ?? [], value as CaptureValues, path),
59
+ );
45
60
  }
46
61
  continue;
47
62
  }
48
63
  if (field.type === CaptureFieldType.List) {
49
- if (field.required && isEmptyValue(value)) missing.push(path);
64
+ if (field.required && isEmptyValue(value)) {
65
+ missing.push(path);
66
+ }
50
67
  if (Array.isArray(value)) {
51
68
  value.forEach((item, i) => {
52
69
  if (item && typeof item === 'object') {
53
- missing.push(...sweepMissing(field.fields ?? [], item as CaptureValues, `${path}.${i}`));
70
+ missing.push(
71
+ ...sweepMissing(
72
+ field.fields ?? [],
73
+ item as CaptureValues,
74
+ `${path}.${i}`,
75
+ ),
76
+ );
54
77
  }
55
78
  });
56
79
  }
57
80
  continue;
58
81
  }
59
- if (field.required && isEmptyValue(value)) missing.push(path);
82
+ if (field.required && isEmptyValue(value)) {
83
+ missing.push(path);
84
+ }
60
85
  }
61
86
  return missing;
62
87
  }
@@ -70,7 +95,10 @@ function sweepMissing(fields: readonly CaptureFieldSpec[], values: CaptureValues
70
95
  * // gate a wizard step / submit button:
71
96
  * <Button disabled={!isValid}>Continue</Button>
72
97
  */
73
- export function useSchemaValidation(input: ValidationInput, values: CaptureValues): SchemaValidationResult {
98
+ export function useSchemaValidation(
99
+ input: ValidationInput,
100
+ values: CaptureValues,
101
+ ): SchemaValidationResult {
74
102
  // Field specs (when supplied) drive the deterministic required sweep and the
75
103
  // auto-adapted zod schema; a raw zod schema is used as-is.
76
104
  const fields = useMemo<readonly CaptureFieldSpec[] | null>(
@@ -89,7 +117,9 @@ export function useSchemaValidation(input: ValidationInput, values: CaptureValue
89
117
  for (const issue of result.error.issues) {
90
118
  const path = issue.path.map(String).join('.');
91
119
  // First error per path wins (deterministic, matches display order).
92
- if (!(path in errors)) errors[path] = issue.message;
120
+ if (!(path in errors)) {
121
+ errors[path] = issue.message;
122
+ }
93
123
  }
94
124
  }
95
125
 
@@ -100,7 +130,9 @@ export function useSchemaValidation(input: ValidationInput, values: CaptureValue
100
130
  : Object.keys(errors).filter((path) => {
101
131
  const segments = path.split('.');
102
132
  let cur: unknown = values;
103
- for (const seg of segments) cur = (cur as CaptureValues | undefined)?.[seg];
133
+ for (const seg of segments) {
134
+ cur = (cur as CaptureValues | undefined)?.[seg];
135
+ }
104
136
  return isEmptyValue(cur);
105
137
  });
106
138
 
@@ -50,6 +50,29 @@ export interface WizardApi {
50
50
  readonly status: (index: number) => FormStepStatus;
51
51
  }
52
52
 
53
+ /**
54
+ * Strict access guard — keeps `steps[index]` typed as defined.
55
+ *
56
+ * `activeIndex` is clamped into `[0, count - 1]`, so the only way this misses is
57
+ * an EMPTY `steps` array: `clamp` floors at 0 and `steps[0]` is then `undefined`.
58
+ * `WizardApi.activeStep` is declared non-optional and consumers dereference it
59
+ * (`api.activeStep.key`), so a zero-step wizard must fail here with a message
60
+ * naming the cause rather than hand back an `undefined` typed as `WizardStepDef`.
61
+ */
62
+ function requireStep(
63
+ steps: readonly WizardStepDef[],
64
+ index: number,
65
+ ): WizardStepDef {
66
+ const step = steps[index];
67
+ if (!step) {
68
+ throw new Error(
69
+ `useWizard: no step at index ${index} (have ${steps.length}). ` +
70
+ '`steps` must contain at least one entry.',
71
+ );
72
+ }
73
+ return step;
74
+ }
75
+
53
76
  /**
54
77
  * @example
55
78
  * const wizard = useWizard({
@@ -64,20 +87,30 @@ export interface WizardApi {
64
87
  export function useWizard(options: UseWizardOptions): WizardApi {
65
88
  const { steps, canAdvance, initialStep = 0, step, onStepChange } = options;
66
89
  const count = steps.length;
67
- const clamp = useCallback((i: number) => Math.max(0, Math.min(count - 1, i)), [count]);
90
+ const clamp = useCallback(
91
+ (i: number) => Math.max(0, Math.min(count - 1, i)),
92
+ [count],
93
+ );
68
94
 
69
95
  const isControlled = step !== undefined;
70
96
  const [internal, setInternal] = useState(() => clamp(initialStep));
71
97
  const activeIndex = clamp(isControlled ? step : internal);
72
98
 
73
- const gate = useCallback((i: number) => (canAdvance ? canAdvance(i) : true), [canAdvance]);
99
+ const gate = useCallback(
100
+ (i: number) => (canAdvance ? canAdvance(i) : true),
101
+ [canAdvance],
102
+ );
74
103
 
75
104
  const request = useCallback(
76
105
  (target: number) => {
77
106
  const next = clamp(target);
78
- if (next === activeIndex) return;
107
+ if (next === activeIndex) {
108
+ return;
109
+ }
79
110
  onStepChange?.(next);
80
- if (!isControlled) setInternal(next);
111
+ if (!isControlled) {
112
+ setInternal(next);
113
+ }
81
114
  },
82
115
  [activeIndex, clamp, isControlled, onStepChange],
83
116
  );
@@ -91,7 +124,9 @@ export function useWizard(options: UseWizardOptions): WizardApi {
91
124
  }
92
125
  // Forward: every step from active..target-1 must pass its gate.
93
126
  for (let i = activeIndex; i < target; i += 1) {
94
- if (!gate(i)) return;
127
+ if (!gate(i)) {
128
+ return;
129
+ }
95
130
  }
96
131
  request(target);
97
132
  },
@@ -99,17 +134,28 @@ export function useWizard(options: UseWizardOptions): WizardApi {
99
134
  );
100
135
 
101
136
  const next = useCallback(() => {
102
- if (activeIndex >= count - 1) return;
103
- if (!gate(activeIndex)) return;
137
+ if (activeIndex >= count - 1) {
138
+ return;
139
+ }
140
+ if (!gate(activeIndex)) {
141
+ return;
142
+ }
104
143
  request(activeIndex + 1);
105
144
  }, [activeIndex, count, gate, request]);
106
145
 
107
- const prev = useCallback(() => request(activeIndex - 1), [activeIndex, request]);
146
+ const prev = useCallback(
147
+ () => request(activeIndex - 1),
148
+ [activeIndex, request],
149
+ );
108
150
 
109
151
  const status = useCallback(
110
152
  (index: number): FormStepStatus => {
111
- if (index < activeIndex) return FormStepStatus.DONE;
112
- if (index === activeIndex) return FormStepStatus.ACTIVE;
153
+ if (index < activeIndex) {
154
+ return FormStepStatus.DONE;
155
+ }
156
+ if (index === activeIndex) {
157
+ return FormStepStatus.ACTIVE;
158
+ }
113
159
  return FormStepStatus.PENDING;
114
160
  },
115
161
  [activeIndex],
@@ -119,7 +165,7 @@ export function useWizard(options: UseWizardOptions): WizardApi {
119
165
  () => ({
120
166
  steps,
121
167
  activeIndex,
122
- activeStep: steps[activeIndex],
168
+ activeStep: requireStep(steps, activeIndex),
123
169
  isFirst: activeIndex === 0,
124
170
  isLast: activeIndex === count - 1,
125
171
  canAdvance: gate(activeIndex),
@@ -5,14 +5,24 @@ import { CaptureFieldType, type CaptureFieldSpec } from './field-spec';
5
5
 
6
6
  /** Coerce any stored value to a display/edit string (empty for absent). */
7
7
  export function asString(value: unknown): string {
8
- if (typeof value === 'string') return value;
9
- if (value === undefined || value === null) return '';
8
+ if (typeof value === 'string') {
9
+ return value;
10
+ }
11
+ if (value === undefined || value === null) {
12
+ return '';
13
+ }
10
14
  return String(value);
11
15
  }
12
16
 
13
17
  /** Human-readable rendering of a scalar field value for the read-only preview. */
14
- export function formatScalar(field: CaptureFieldSpec, value: unknown, emptyText: string): string {
15
- if (value === undefined || value === null || value === '') return emptyText;
18
+ export function formatScalar(
19
+ field: CaptureFieldSpec,
20
+ value: unknown,
21
+ emptyText: string,
22
+ ): string {
23
+ if (value === undefined || value === null || value === '') {
24
+ return emptyText;
25
+ }
16
26
  switch (field.type) {
17
27
  case CaptureFieldType.Boolean:
18
28
  return value === true ? 'Yes' : 'No';
@@ -6,14 +6,18 @@
6
6
  // renders a Back / Next / Finish nav bar. All state lives in the `useWizard`
7
7
  // engine you pass via `api`; this component is presentation only.
8
8
  // ═══════════════════════════════════════════════════════════════════════════
9
- import { Children, isValidElement, type ReactElement, type ReactNode } from 'react';
9
+ import {
10
+ Children,
11
+ isValidElement,
12
+ type ReactNode,
13
+ } from 'react';
10
14
 
11
15
  import { cn } from '../cn';
12
16
  import { Button } from '../primitives/button';
13
17
  import { FormStepper } from '../primitives/form-stepper';
14
- import type { FormStep } from '../primitives/form-stepper.types';
15
18
 
16
19
  import type { WizardApi } from './use-wizard';
20
+ import type { FormStep } from '../primitives/form-stepper.types';
17
21
 
18
22
  export interface WizardStepProps {
19
23
  /** Must match a `useWizard` step `key`. */
@@ -46,8 +50,8 @@ export interface WizardProps {
46
50
  function stepBodies(children: ReactNode): Map<string, ReactNode> {
47
51
  const map = new Map<string, ReactNode>();
48
52
  Children.forEach(children, (child) => {
49
- if (isValidElement(child) && (child as ReactElement<WizardStepProps>).props?.stepKey) {
50
- const p = (child as ReactElement<WizardStepProps>).props;
53
+ if (isValidElement<WizardStepProps>(child) && child.props.stepKey) {
54
+ const p = child.props;
51
55
  map.set(p.stepKey, p.children);
52
56
  }
53
57
  });
@@ -73,7 +77,7 @@ export function Wizard({
73
77
  status: api.status(index),
74
78
  // Render the active step's body inline; pending/done steps stay empty so
75
79
  // the rail reads as a guided one-step-at-a-time flow.
76
- children: index === api.activeIndex ? bodies.get(step.key) ?? null : null,
80
+ children: index === api.activeIndex ? (bodies.get(step.key) ?? null) : null,
77
81
  }));
78
82
 
79
83
  return (
@@ -1,10 +1,8 @@
1
1
  // ═══════════════════════════════════════════════════════════════════════════
2
2
  // BarChart — categorical bars, pure SVG (Wave 9.2)
3
3
  // ═══════════════════════════════════════════════════════════════════════════
4
- import type { ReactNode } from 'react';
5
4
 
6
5
  import { ChartEmpty, ChartFrame, type ChartLegendItem } from './chart-frame';
7
- import type { ChartBaseProps, ChartDatum } from './chart-types';
8
6
  import {
9
7
  buildAriaSummary,
10
8
  chartColorAt,
@@ -13,6 +11,9 @@ import {
13
11
  niceScale,
14
12
  } from './chart-utils';
15
13
 
14
+ import type { ChartBaseProps, ChartDatum } from './chart-types';
15
+ import type { ReactNode } from 'react';
16
+
16
17
  // Internal coordinate space — the `viewBox`. `width="100%"` makes the SVG scale
17
18
  // to its container (D20 fluid), so these are ratios, not device pixels.
18
19
  const VIEW_W = 640;
@@ -42,13 +43,16 @@ export function BarChart({
42
43
  const points = finitePoints(data);
43
44
 
44
45
  if (points.length === 0) {
45
- return <ChartEmpty title={title} label={emptyLabel} className={className} />;
46
+ return (
47
+ <ChartEmpty title={title} label={emptyLabel} className={className} />
48
+ );
46
49
  }
47
50
 
48
51
  const values = points.map((p) => p.value);
49
52
  const scale = niceScale(Math.min(...values), Math.max(...values));
50
53
  const span = scale.max - scale.min;
51
- const yToPx = (v: number): number => PLOT_B - ((v - scale.min) / span) * PLOT_H;
54
+ const yToPx = (v: number): number =>
55
+ PLOT_B - ((v - scale.min) / span) * PLOT_H;
52
56
  const baseline = yToPx(0);
53
57
 
54
58
  const band = PLOT_W / points.length;
@@ -6,11 +6,12 @@
6
6
  // below `md`. That decision is driven by `useIsMobile()` — which reads the one
7
7
  // shared `MOBILE_BREAKPOINT` token — never a second breakpoint.
8
8
  // ═══════════════════════════════════════════════════════════════════════════
9
- import type { ReactNode } from 'react';
10
9
 
11
10
  import { cn } from '../cn';
12
11
  import { useIsMobile } from '../hooks/use-is-mobile';
13
12
 
13
+ import type { ReactNode } from 'react';
14
+
14
15
  /** One row of the legend: a color swatch + its label + (optional) value. */
15
16
  export interface ChartLegendItem {
16
17
  readonly label: string;
@@ -29,7 +30,9 @@ interface ChartLegendProps {
29
30
  * secondary cue, so a color-blind or monochrome reader loses nothing.
30
31
  */
31
32
  export function ChartLegend({ items, layout }: ChartLegendProps): ReactNode {
32
- if (items.length === 0) return null;
33
+ if (items.length === 0) {
34
+ return null;
35
+ }
33
36
  return (
34
37
  <ul
35
38
  className={cn(
@@ -48,7 +51,9 @@ export function ChartLegend({ items, layout }: ChartLegendProps): ReactNode {
48
51
  />
49
52
  <span className="text-ink-3">{item.label}</span>
50
53
  {item.value !== undefined && (
51
- <span className="ml-auto font-medium tabular-nums text-ink">{item.value}</span>
54
+ <span className="ml-auto font-medium tabular-nums text-ink">
55
+ {item.value}
56
+ </span>
52
57
  )}
53
58
  </li>
54
59
  ))}
@@ -68,7 +73,11 @@ interface ChartFrameProps {
68
73
  * so below `md` the legend renders BELOW the plot; at/above `md` it sits to the
69
74
  * right. One token (`MOBILE_BREAKPOINT`), no second breakpoint.
70
75
  */
71
- export function ChartFrame({ plot, legend, className }: ChartFrameProps): ReactNode {
76
+ export function ChartFrame({
77
+ plot,
78
+ legend,
79
+ className,
80
+ }: ChartFrameProps): ReactNode {
72
81
  const isMobile = useIsMobile();
73
82
  return (
74
83
  <div className={cn('w-full min-w-0 text-ink-3', className)}>
@@ -96,7 +105,11 @@ interface ChartEmptyProps {
96
105
  * no finite points. Still carries `role="img"` + an `aria-label` so assistive
97
106
  * tech announces the (empty) chart rather than a silent gap.
98
107
  */
99
- export function ChartEmpty({ title, label, className }: ChartEmptyProps): ReactNode {
108
+ export function ChartEmpty({
109
+ title,
110
+ label,
111
+ className,
112
+ }: ChartEmptyProps): ReactNode {
100
113
  return (
101
114
  <div
102
115
  role="img"
@@ -29,8 +29,23 @@ export const CHART_PALETTE: readonly string[] = [
29
29
 
30
30
  /** Resolve the color for the datum at `index`: explicit override wins, else palette (wraps). */
31
31
  export function chartColorAt(index: number, override?: string): string {
32
- if (override !== undefined && override.length > 0) return override;
33
- return CHART_PALETTE[index % CHART_PALETTE.length];
32
+ if (override !== undefined && override.length > 0) {
33
+ return override;
34
+ }
35
+ const size = CHART_PALETTE.length;
36
+ // `index % size` alone is NOT a wrap: JS `%` keeps the sign, so a negative
37
+ // index lands on a negative slot and reads back `undefined` — which used to
38
+ // be returned as a `string` and rendered as a missing `fill`/`stroke`. Wrap
39
+ // forward instead. A non-finite index yields a NaN slot and falls through to
40
+ // the throw rather than silently painting the wrong series color.
41
+ const slot = ((Math.trunc(index) % size) + size) % size;
42
+ const color = CHART_PALETTE[slot];
43
+ if (color === undefined) {
44
+ throw new Error(
45
+ `chartColorAt: no palette color for index ${index} (resolved slot ${slot} of ${size}).`,
46
+ );
47
+ }
48
+ return color;
34
49
  }
35
50
 
36
51
  /**
@@ -39,8 +54,12 @@ export function chartColorAt(index: number, override?: string): string {
39
54
  * SVG is byte-identical across machines/locales.
40
55
  */
41
56
  export function defaultFormatValue(value: number): string {
42
- if (!Number.isFinite(value)) return '—';
43
- if (Number.isInteger(value)) return String(value);
57
+ if (!Number.isFinite(value)) {
58
+ return '—';
59
+ }
60
+ if (Number.isInteger(value)) {
61
+ return String(value);
62
+ }
44
63
  return String(Number(value.toFixed(2)));
45
64
  }
46
65
 
@@ -70,15 +89,25 @@ function niceNum(range: number, round: boolean): number {
70
89
  const fraction = range / pow;
71
90
  let niceFraction: number;
72
91
  if (round) {
73
- if (fraction < 1.5) niceFraction = 1;
74
- else if (fraction < 3) niceFraction = 2;
75
- else if (fraction < 7) niceFraction = 5;
76
- else niceFraction = 10;
92
+ if (fraction < 1.5) {
93
+ niceFraction = 1;
94
+ } else if (fraction < 3) {
95
+ niceFraction = 2;
96
+ } else if (fraction < 7) {
97
+ niceFraction = 5;
98
+ } else {
99
+ niceFraction = 10;
100
+ }
77
101
  } else {
78
- if (fraction <= 1) niceFraction = 1;
79
- else if (fraction <= 2) niceFraction = 2;
80
- else if (fraction <= 5) niceFraction = 5;
81
- else niceFraction = 10;
102
+ if (fraction <= 1) {
103
+ niceFraction = 1;
104
+ } else if (fraction <= 2) {
105
+ niceFraction = 2;
106
+ } else if (fraction <= 5) {
107
+ niceFraction = 5;
108
+ } else {
109
+ niceFraction = 10;
110
+ }
82
111
  }
83
112
  return niceFraction * pow;
84
113
  }
@@ -117,7 +146,7 @@ export function niceScale(
117
146
  ): NiceScale {
118
147
  const pinZero = options.pinZero ?? true;
119
148
  const maxTicks = options.maxTicks ?? 5;
120
- let lo = pinZero ? Math.min(0, dataMin) : dataMin;
149
+ const lo = pinZero ? Math.min(0, dataMin) : dataMin;
121
150
  let hi = pinZero ? Math.max(0, dataMax) : dataMax;
122
151
  if (lo === hi) {
123
152
  // Flat series (e.g. all equal): open a unit window so we never divide by 0.
@@ -149,10 +178,13 @@ export function buildAriaSummary(
149
178
  noun: string,
150
179
  maxItems = 8,
151
180
  ): string {
152
- if (points.length === 0) return `${title}: no data.`;
181
+ if (points.length === 0) {
182
+ return `${title}: no data.`;
183
+ }
153
184
  const shown = points.slice(0, maxItems);
154
185
  const pairs = shown.map((p) => `${p.label} ${format(p.value)}`).join(', ');
155
- const suffix = points.length > maxItems ? `, and ${points.length - maxItems} more` : '';
186
+ const suffix =
187
+ points.length > maxItems ? `, and ${points.length - maxItems} more` : '';
156
188
  const count = points.length === 1 ? `1 ${noun}` : `${points.length} ${noun}s`;
157
189
  return `${title}: ${count}. ${pairs}${suffix}.`;
158
190
  }
@@ -5,11 +5,16 @@
5
5
  // If no finite positive value remains, an explicit empty state renders instead
6
6
  // of a broken ring.
7
7
  // ═══════════════════════════════════════════════════════════════════════════
8
- import type { ReactNode } from 'react';
9
8
 
10
9
  import { ChartEmpty, ChartFrame, type ChartLegendItem } from './chart-frame';
10
+ import {
11
+ buildAriaSummary,
12
+ chartColorAt,
13
+ defaultFormatValue,
14
+ } from './chart-utils';
15
+
11
16
  import type { ChartBaseProps, ChartDatum } from './chart-types';
12
- import { buildAriaSummary, chartColorAt, defaultFormatValue } from './chart-utils';
17
+ import type { ReactNode } from 'react';
13
18
 
14
19
  const SIZE = 200;
15
20
  const CX = SIZE / 2;
@@ -57,7 +62,9 @@ export function DonutChart({
57
62
  const total = slices.reduce((sum, d) => sum + d.value, 0);
58
63
 
59
64
  if (slices.length === 0 || total <= 0) {
60
- return <ChartEmpty title={title} label={emptyLabel} className={className} />;
65
+ return (
66
+ <ChartEmpty title={title} label={emptyLabel} className={className} />
67
+ );
61
68
  }
62
69
 
63
70
  const legend: ChartLegendItem[] = slices.map((d, i) => ({
@@ -67,7 +74,8 @@ export function DonutChart({
67
74
  }));
68
75
 
69
76
  const summaryPoints = slices.map((d) => ({ label: d.label, value: d.value }));
70
- const summary = ariaLabel ?? buildAriaSummary(title, summaryPoints, format, 'slice');
77
+ const summary =
78
+ ariaLabel ?? buildAriaSummary(title, summaryPoints, format, 'slice');
71
79
 
72
80
  let cursor = 0;
73
81
  const arcs = slices.map((d, i) => {
@@ -77,7 +85,11 @@ export function DonutChart({
77
85
  const sweep = slices.length === 1 ? FULL - 1e-3 : (d.value / total) * FULL;
78
86
  const end = start + sweep;
79
87
  cursor = end;
80
- return { path: slicePath(start, end), color: chartColorAt(i, d.color), key: `${d.label}-${i}` };
88
+ return {
89
+ path: slicePath(start, end),
90
+ color: chartColorAt(i, d.color),
91
+ key: `${d.label}-${i}`,
92
+ };
81
93
  });
82
94
 
83
95
  const plot = (
@@ -90,7 +102,13 @@ export function DonutChart({
90
102
  className="mx-auto block h-auto w-full max-w-[240px] text-ink-4"
91
103
  >
92
104
  {arcs.map((a) => (
93
- <path key={a.key} d={a.path} fill={a.color} stroke="var(--card, transparent)" strokeWidth={1} />
105
+ <path
106
+ key={a.key}
107
+ d={a.path}
108
+ fill={a.color}
109
+ stroke="var(--card, transparent)"
110
+ strokeWidth={1}
111
+ />
94
112
  ))}
95
113
  <text
96
114
  x={CX}
@@ -4,10 +4,8 @@
4
4
  // Non-finite points break the line (a new segment starts after the gap) rather
5
5
  // than emitting a NaN coordinate.
6
6
  // ═══════════════════════════════════════════════════════════════════════════
7
- import type { ReactNode } from 'react';
8
7
 
9
8
  import { ChartEmpty, ChartFrame, type ChartLegendItem } from './chart-frame';
10
- import type { ChartBaseProps, ChartLineSeries } from './chart-types';
11
9
  import {
12
10
  buildAriaSummary,
13
11
  chartColorAt,
@@ -15,6 +13,9 @@ import {
15
13
  niceScale,
16
14
  } from './chart-utils';
17
15
 
16
+ import type { ChartBaseProps, ChartLineSeries } from './chart-types';
17
+ import type { ReactNode } from 'react';
18
+
18
19
  const VIEW_W = 640;
19
20
  const VIEW_H = 360;
20
21
  const PAD = { top: 12, right: 12, bottom: 44, left: 48 } as const;
@@ -46,7 +47,9 @@ function toSegments(
46
47
  current = [];
47
48
  }
48
49
  });
49
- if (current.length > 0) segments.push(current.join(' '));
50
+ if (current.length > 0) {
51
+ segments.push(current.join(' '));
52
+ }
50
53
  return segments;
51
54
  }
52
55
 
@@ -65,23 +68,35 @@ export function LineChart({
65
68
  let maxLen = 0;
66
69
  for (const s of series) {
67
70
  maxLen = Math.max(maxLen, s.points.length);
68
- for (const p of s.points) if (Number.isFinite(p.value)) finiteValues.push(p.value);
71
+ for (const p of s.points) {
72
+ if (Number.isFinite(p.value)) {
73
+ finiteValues.push(p.value);
74
+ }
75
+ }
69
76
  }
70
77
 
71
78
  if (finiteValues.length === 0) {
72
- return <ChartEmpty title={title} label={emptyLabel} className={className} />;
79
+ return (
80
+ <ChartEmpty title={title} label={emptyLabel} className={className} />
81
+ );
73
82
  }
74
83
 
75
- const scale = niceScale(Math.min(...finiteValues), Math.max(...finiteValues), {
76
- pinZero: false,
77
- });
84
+ const scale = niceScale(
85
+ Math.min(...finiteValues),
86
+ Math.max(...finiteValues),
87
+ {
88
+ pinZero: false,
89
+ },
90
+ );
78
91
  const span = scale.max - scale.min;
79
- const yToPx = (v: number): number => PLOT_B - ((v - scale.min) / span) * PLOT_H;
92
+ const yToPx = (v: number): number =>
93
+ PLOT_B - ((v - scale.min) / span) * PLOT_H;
80
94
  const xToPx = (i: number): number =>
81
95
  maxLen <= 1 ? PLOT_L + PLOT_W / 2 : PLOT_L + (i / (maxLen - 1)) * PLOT_W;
82
96
 
83
97
  // x labels from the longest series (deterministic pick: first of that length).
84
- const xLabelSource = series.find((s) => s.points.length === maxLen)?.points ?? [];
98
+ const xLabelSource =
99
+ series.find((s) => s.points.length === maxLen)?.points ?? [];
85
100
 
86
101
  const legend: ChartLegendItem[] = series.map((s, i) => ({
87
102
  label: s.name,
@@ -94,7 +109,8 @@ export function LineChart({
94
109
  .filter((p) => Number.isFinite(p.value))
95
110
  .map((p) => ({ label: `${s.name} ${p.label}`, value: p.value })),
96
111
  );
97
- const summary = ariaLabel ?? buildAriaSummary(title, summaryPoints, format, 'point');
112
+ const summary =
113
+ ariaLabel ?? buildAriaSummary(title, summaryPoints, format, 'point');
98
114
 
99
115
  const plot = (
100
116
  <svg
@@ -165,7 +181,13 @@ export function LineChart({
165
181
  ))}
166
182
  {s.points.map((p, i) =>
167
183
  Number.isFinite(p.value) ? (
168
- <circle key={`pt-${i}`} cx={xToPx(i)} cy={yToPx(p.value)} r={2.5} fill={color}>
184
+ <circle
185
+ key={`pt-${i}`}
186
+ cx={xToPx(i)}
187
+ cy={yToPx(p.value)}
188
+ r={2.5}
189
+ fill={color}
190
+ >
169
191
  <title>{`${s.name} — ${p.label}: ${format(p.value)}`}</title>
170
192
  </circle>
171
193
  ) : null,