@puredesktop/puredesktop-ui-bridge 1.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (412) hide show
  1. package/package.json +96 -0
  2. package/src/agents/runtime/agentLiveReducer.test.ts +72 -0
  3. package/src/agents/runtime/agentLiveReducer.ts +139 -0
  4. package/src/agents/runtime/agentRunEventTypes.ts +115 -0
  5. package/src/agents/runtime/contextWindowUsage.test.ts +38 -0
  6. package/src/agents/runtime/contextWindowUsage.ts +25 -0
  7. package/src/agents/runtime/index.ts +24 -0
  8. package/src/agents/runtime/mapAgentMessages.ts +54 -0
  9. package/src/agents/runtime/mapAgentSnapshot.ts +71 -0
  10. package/src/agents/runtime/mergeUsageTurn.ts +23 -0
  11. package/src/agents/runtime/pendingToolCalls.test.ts +85 -0
  12. package/src/agents/runtime/pendingToolCalls.ts +14 -0
  13. package/src/agents/runtime/toolRequiresApproval.ts +20 -0
  14. package/src/agents/runtime/unresolvedToolCalls.ts +42 -0
  15. package/src/bridge/agentModelTiers.ts +50 -0
  16. package/src/bridge/agentToolHandlers.ts +23 -0
  17. package/src/bridge/agentToolHelpers.test.ts +27 -0
  18. package/src/bridge/agentToolHelpers.ts +20 -0
  19. package/src/bridge/agentTypes.ts +294 -0
  20. package/src/bridge/agents.d.mts +113 -0
  21. package/src/bridge/agents.mjs +233 -0
  22. package/src/bridge/agents.ts +62 -0
  23. package/src/bridge/appSettings.d.mts +9 -0
  24. package/src/bridge/appSettings.mjs +18 -0
  25. package/src/bridge/appSettings.ts +4 -0
  26. package/src/bridge/applyThemeFromHost.d.mts +7 -0
  27. package/src/bridge/applyThemeFromHost.mjs +33 -0
  28. package/src/bridge/assets.d.mts +66 -0
  29. package/src/bridge/assets.mjs +121 -0
  30. package/src/bridge/catalog.d.mts +5 -0
  31. package/src/bridge/catalog.mjs +24 -0
  32. package/src/bridge/catalog.ts +1 -0
  33. package/src/bridge/client.d.mts +19 -0
  34. package/src/bridge/client.mjs +147 -0
  35. package/src/bridge/collectionAssetAdapter.ts +63 -0
  36. package/src/bridge/collectionAssets.d.mts +1 -0
  37. package/src/bridge/collectionAssets.mjs +2 -0
  38. package/src/bridge/collectionAssets.ts +1 -0
  39. package/src/bridge/collectionDocumentHtml.test.ts +71 -0
  40. package/src/bridge/collectionDocumentHtml.ts +118 -0
  41. package/src/bridge/collectionImagePaste.test.ts +32 -0
  42. package/src/bridge/collectionImagePaste.ts +130 -0
  43. package/src/bridge/context.mjs +12 -0
  44. package/src/bridge/credentials.mjs +22 -0
  45. package/src/bridge/dialog.d.mts +5 -0
  46. package/src/bridge/dialog.mjs +13 -0
  47. package/src/bridge/events.d.mts +14 -0
  48. package/src/bridge/events.mjs +12 -0
  49. package/src/bridge/filePreviewKind.test.ts +43 -0
  50. package/src/bridge/filePreviewKind.ts +76 -0
  51. package/src/bridge/fs.d.mts +41 -0
  52. package/src/bridge/fs.mjs +82 -0
  53. package/src/bridge/fs.test.ts +16 -0
  54. package/src/bridge/fs.ts +10 -0
  55. package/src/bridge/index.ts +12 -0
  56. package/src/bridge/inlinePreview.d.mts +35 -0
  57. package/src/bridge/inlinePreview.mjs +99 -0
  58. package/src/bridge/inlinePreview.test.ts +56 -0
  59. package/src/bridge/inlinePreview.ts +13 -0
  60. package/src/bridge/methods.d.mts +115 -0
  61. package/src/bridge/methods.mjs +132 -0
  62. package/src/bridge/os.d.mts +11 -0
  63. package/src/bridge/os.mjs +26 -0
  64. package/src/bridge/plugins.d.mts +9 -0
  65. package/src/bridge/plugins.mjs +31 -0
  66. package/src/bridge/plugins.ts +5 -0
  67. package/src/bridge/preferences.d.mts +7 -0
  68. package/src/bridge/preferences.mjs +17 -0
  69. package/src/bridge/preferences.ts +13 -0
  70. package/src/bridge/printDocument.test.ts +47 -0
  71. package/src/bridge/printDocument.ts +75 -0
  72. package/src/bridge/pureRender/adapters.test.ts +144 -0
  73. package/src/bridge/pureRender/adapters.ts +175 -0
  74. package/src/bridge/pureRender/assets.test.ts +44 -0
  75. package/src/bridge/pureRender/base.css +76 -0
  76. package/src/bridge/pureRender/compiler.test.ts +279 -0
  77. package/src/bridge/pureRender/compiler.ts +660 -0
  78. package/src/bridge/pureRender/document.test.ts +283 -0
  79. package/src/bridge/pureRender/document.ts +35 -0
  80. package/src/bridge/pureRender/extraction.test.ts +432 -0
  81. package/src/bridge/pureRender/extraction.ts +1023 -0
  82. package/src/bridge/pureRender/flow.css +3 -0
  83. package/src/bridge/pureRender/index.ts +66 -0
  84. package/src/bridge/pureRender/normalize.test.ts +442 -0
  85. package/src/bridge/pureRender/normalize.ts +682 -0
  86. package/src/bridge/pureRender/presets.ts +365 -0
  87. package/src/bridge/pureRender/profiles/book.css +19 -0
  88. package/src/bridge/pureRender/profiles/manuscript.css +11 -0
  89. package/src/bridge/pureRender/profiles/writer.css +10 -0
  90. package/src/bridge/pureRender/reset.css +5 -0
  91. package/src/bridge/pureRender/samples.ts +94 -0
  92. package/src/bridge/pureRender/styles.ts +164 -0
  93. package/src/bridge/pureRender/theme.test.ts +53 -0
  94. package/src/bridge/pureRender/theme.ts +258 -0
  95. package/src/bridge/pureRender/tokens/default.css +36 -0
  96. package/src/bridge/pureRender/tokens/default.json +32 -0
  97. package/src/bridge/pureRender/types.ts +264 -0
  98. package/src/bridge/pureRender/visualLayoutInspection.test.ts +57 -0
  99. package/src/bridge/pureRender/visualLayoutInspection.ts +161 -0
  100. package/src/bridge/react/useDebouncedEffect.ts +21 -0
  101. package/src/bridge/react/useIpc.tsx +75 -0
  102. package/src/bridge/react/usePlatformAgentRunLiveState.tsx +78 -0
  103. package/src/bridge/react/usePlatformAgentSessionDrive.tsx +729 -0
  104. package/src/bridge/react/usePlatformAgentSessions.tsx +60 -0
  105. package/src/bridge/react/usePlatformAgentTools.tsx +82 -0
  106. package/src/bridge/react/usePlatformAppManifest.tsx +32 -0
  107. package/src/bridge/react/usePlatformBridge.tsx +56 -0
  108. package/src/bridge/react/usePlatformDeepLink.tsx +57 -0
  109. package/src/bridge/react/usePlatformFileBinaryDataUrl.tsx +54 -0
  110. package/src/bridge/react/usePlatformFilePreview.tsx +92 -0
  111. package/src/bridge/react/usePlatformPreferences.tsx +77 -0
  112. package/src/bridge/react/usePlatformThemeDocumentAttrs.ts +35 -0
  113. package/src/bridge/react/usePlatformThemeFromBridge.tsx +16 -0
  114. package/src/bridge/react/usePlatformViewportResource.test.tsx +106 -0
  115. package/src/bridge/react/usePlatformViewportResource.tsx +72 -0
  116. package/src/bridge/react/useScheduledTask.tsx +59 -0
  117. package/src/bridge/render.d.mts +31 -0
  118. package/src/bridge/render.mjs +62 -0
  119. package/src/bridge/render.ts +8 -0
  120. package/src/bridge/screenAnnotation.test.ts +103 -0
  121. package/src/bridge/screenAnnotation.ts +269 -0
  122. package/src/bridge/theme.d.mts +3 -0
  123. package/src/bridge/theme.mjs +9 -0
  124. package/src/bridge/types.ts +439 -0
  125. package/src/bridge/watch.d.mts +9 -0
  126. package/src/bridge/watch.mjs +34 -0
  127. package/src/bridge/watch.ts +1 -0
  128. package/src/bridge/window.d.mts +44 -0
  129. package/src/bridge/window.mjs +33 -0
  130. package/src/chrome/index.ts +1 -0
  131. package/src/components/accessibility/AccessibilityReviewDialog.test.tsx +104 -0
  132. package/src/components/accessibility/AccessibilityReviewDialog.tsx +350 -0
  133. package/src/components/accessibility/accessibilityReview.test.ts +101 -0
  134. package/src/components/accessibility/accessibilityReview.ts +639 -0
  135. package/src/components/accessibility/index.ts +16 -0
  136. package/src/components/agent-feedback/ScreenAnnotationAgentDialog.tsx +509 -0
  137. package/src/components/agent-feedback/index.ts +5 -0
  138. package/src/components/agents/AgentComposer.tsx +34 -0
  139. package/src/components/agents/AgentContextUsageBar.tsx +127 -0
  140. package/src/components/agents/AgentDrawerPanel.tsx +82 -0
  141. package/src/components/agents/AgentMarkdown.tsx +12 -0
  142. package/src/components/agents/AgentMessageBubble.tsx +82 -0
  143. package/src/components/agents/AgentMessageList.tsx +47 -0
  144. package/src/components/agents/AgentModelMenu.tsx +55 -0
  145. package/src/components/agents/AgentThinkingBlock.tsx +66 -0
  146. package/src/components/agents/AgentToolApprovalActions.tsx +65 -0
  147. package/src/components/agents/AgentToolCallCard.tsx +26 -0
  148. package/src/components/agents/AgentToolPendingList.tsx +39 -0
  149. package/src/components/agents/AgentToolPendingReview.tsx +118 -0
  150. package/src/components/agents/agentPanelStyles.ts +79 -0
  151. package/src/components/agents/agentTypes.ts +96 -0
  152. package/src/components/agents/formatToolCallArguments.test.ts +16 -0
  153. package/src/components/agents/formatToolCallArguments.ts +9 -0
  154. package/src/components/agents/index.ts +40 -0
  155. package/src/components/assets/AssetLibraryDialog.tsx +5 -0
  156. package/src/components/assets/asset-library/AssetLibraryDialog.tsx +43 -0
  157. package/src/components/assets/asset-library/AssetLibraryWorkspace.tsx +54 -0
  158. package/src/components/assets/asset-library/detail/AssetLibraryDetailActions.tsx +68 -0
  159. package/src/components/assets/asset-library/detail/AssetLibraryDetailHeader.tsx +56 -0
  160. package/src/components/assets/asset-library/detail/AssetLibraryDetailPane.tsx +90 -0
  161. package/src/components/assets/asset-library/detail/AssetLibraryDetailPreview.tsx +67 -0
  162. package/src/components/assets/asset-library/detail/AssetLibraryInlinePreview.tsx +87 -0
  163. package/src/components/assets/asset-library/detail/AssetLibraryInlineSourceField.tsx +29 -0
  164. package/src/components/assets/asset-library/detail/AssetLibraryMetadataFields.tsx +34 -0
  165. package/src/components/assets/asset-library/detail/AssetLibraryUsagePanel.tsx +46 -0
  166. package/src/components/assets/asset-library/detail/AssetLibraryVersionsPanel.tsx +145 -0
  167. package/src/components/assets/asset-library/helpers/assetKind.ts +74 -0
  168. package/src/components/assets/asset-library/helpers.ts +41 -0
  169. package/src/components/assets/asset-library/hooks/useAssetDetailDraft.ts +81 -0
  170. package/src/components/assets/asset-library/hooks/useAssetLibraryDialog.ts +233 -0
  171. package/src/components/assets/asset-library/hooks/useAssetLibraryMutations.ts +266 -0
  172. package/src/components/assets/asset-library/hooks/useAssetLibrarySelectionSync.ts +24 -0
  173. package/src/components/assets/asset-library/hooks/useAssetLibraryVersions.ts +145 -0
  174. package/src/components/assets/asset-library/hooks/useInlineAssetPreview.ts +44 -0
  175. package/src/components/assets/asset-library/index.ts +19 -0
  176. package/src/components/assets/asset-library/layout/assetLibraryLayout.ts +201 -0
  177. package/src/components/assets/asset-library/shared/fieldStyles.ts +62 -0
  178. package/src/components/assets/asset-library/sidebar/AssetLibraryFilterPills.tsx +89 -0
  179. package/src/components/assets/asset-library/sidebar/AssetLibraryList.tsx +91 -0
  180. package/src/components/assets/asset-library/sidebar/AssetLibraryListRow.tsx +99 -0
  181. package/src/components/assets/asset-library/sidebar/AssetLibraryListStatus.tsx +24 -0
  182. package/src/components/assets/asset-library/sidebar/AssetLibrarySidebar.tsx +48 -0
  183. package/src/components/assets/asset-library/sidebar/AssetLibrarySidebarActions.tsx +38 -0
  184. package/src/components/assets/asset-library/sidebar/AssetLibrarySidebarToolbar.tsx +78 -0
  185. package/src/components/assets/asset-library/sidebar/AssetListThumbnail.tsx +86 -0
  186. package/src/components/assets/asset-library/types.ts +128 -0
  187. package/src/components/assets/asset-library/utils/assetLibraryUtils.ts +181 -0
  188. package/src/components/assets/asset-library/utils/pathBasename.ts +5 -0
  189. package/src/components/assets/asset-library/utils/sanitizeUploadFileName.ts +7 -0
  190. package/src/components/assets/asset-library/utils/uploadCollectionAsset.ts +52 -0
  191. package/src/components/chrome/OverlayActionCapsule.test.tsx +82 -0
  192. package/src/components/chrome/OverlayActionCapsule.tsx +90 -0
  193. package/src/components/chrome/PanelTabStrip.tsx +113 -0
  194. package/src/components/chrome/PlatformIcon.tsx +27 -0
  195. package/src/components/chrome/PureAppWordmark.tsx +89 -0
  196. package/src/components/chrome/ShellWindowControls.tsx +51 -0
  197. package/src/components/chrome/ThemeModeButton.tsx +16 -0
  198. package/src/components/chrome/Titlebar.tsx +79 -0
  199. package/src/components/chrome/WorkspaceTabStrip.tsx +300 -0
  200. package/src/components/chrome/index.ts +31 -0
  201. package/src/components/chrome/workspaceTabTypes.ts +29 -0
  202. package/src/components/common/buttons/Button.tsx +241 -0
  203. package/src/components/common/buttons/ChoiceChip.tsx +73 -0
  204. package/src/components/common/buttons/CleanButton.tsx +34 -0
  205. package/src/components/common/buttons/IconButton.tsx +89 -0
  206. package/src/components/common/buttons/QuietAction.tsx +29 -0
  207. package/src/components/common/buttons/SegmentedControl.tsx +67 -0
  208. package/src/components/common/buttons/TextActionButton.tsx +55 -0
  209. package/src/components/common/buttons/TextLink.tsx +38 -0
  210. package/src/components/common/canvas/CanvasElementFrame.test.tsx +79 -0
  211. package/src/components/common/canvas/CanvasElementFrame.tsx +182 -0
  212. package/src/components/common/canvas/canvasGeometry.test.ts +66 -0
  213. package/src/components/common/canvas/canvasGeometry.ts +133 -0
  214. package/src/components/common/canvas/index.ts +27 -0
  215. package/src/components/common/canvas/useCanvasDragResize.test.tsx +152 -0
  216. package/src/components/common/canvas/useCanvasDragResize.ts +161 -0
  217. package/src/components/common/chat/ChatAssistantMessage.tsx +81 -0
  218. package/src/components/common/chat/ChatBox.tsx +189 -0
  219. package/src/components/common/chat/ChatMarkdown.tsx +109 -0
  220. package/src/components/common/chat/ChatModelMenu.tsx +258 -0
  221. package/src/components/common/chat/ChatStatusRow.tsx +24 -0
  222. package/src/components/common/chat/ChatThinkingIndicator.tsx +54 -0
  223. package/src/components/common/chat/ChatThread.tsx +59 -0
  224. package/src/components/common/chat/ChatToolRow.tsx +141 -0
  225. package/src/components/common/chat/ChatUserBubble.tsx +45 -0
  226. package/src/components/common/chat/chatUtils.ts +7 -0
  227. package/src/components/common/chat/index.ts +24 -0
  228. package/src/components/common/connections/ConnectionSetup.tsx +529 -0
  229. package/src/components/common/connections/index.ts +26 -0
  230. package/src/components/common/containers/AppFrame.test.tsx +47 -0
  231. package/src/components/common/containers/AppFrame.tsx +65 -0
  232. package/src/components/common/containers/AppHeader.tsx +60 -0
  233. package/src/components/common/containers/AutoFillGrid.tsx +37 -0
  234. package/src/components/common/containers/Collapsible.tsx +43 -0
  235. package/src/components/common/containers/CollapsibleGrid.tsx +174 -0
  236. package/src/components/common/containers/MotionScope.tsx +32 -0
  237. package/src/components/common/containers/PageHeader.tsx +35 -0
  238. package/src/components/common/containers/PanelToolbarHeader.tsx +113 -0
  239. package/src/components/common/containers/QuietDisclosure.tsx +91 -0
  240. package/src/components/common/containers/QuietSurface.tsx +41 -0
  241. package/src/components/common/containers/ScrollPanel.tsx +33 -0
  242. package/src/components/common/containers/StatusBar.tsx +42 -0
  243. package/src/components/common/containers/SurfacePanel.tsx +66 -0
  244. package/src/components/common/containers/ToolbarStrip.tsx +80 -0
  245. package/src/components/common/containers/flex.ts +117 -0
  246. package/src/components/common/containers/useOpenTransition.ts +33 -0
  247. package/src/components/common/context/ContextSelector.tsx +269 -0
  248. package/src/components/common/context/index.ts +7 -0
  249. package/src/components/common/desk/ActionReader.tsx +270 -0
  250. package/src/components/common/desk/ActivityLedger.tsx +143 -0
  251. package/src/components/common/desk/CreationDesk.tsx +139 -0
  252. package/src/components/common/desk/DailyBrief.tsx +160 -0
  253. package/src/components/common/desk/DeskCard.tsx +157 -0
  254. package/src/components/common/desk/index.ts +30 -0
  255. package/src/components/common/dropdown/ContextMenu.tsx +87 -0
  256. package/src/components/common/dropdown/MenuButtonDropdown.tsx +121 -0
  257. package/src/components/common/dropdown/MenuDropdown.tsx +63 -0
  258. package/src/components/common/dropdown/MenuDropdownEntry.tsx +51 -0
  259. package/src/components/common/dropdown/MenuDropdownItem.tsx +82 -0
  260. package/src/components/common/dropdown/MenuDropdownSubmenu.tsx +145 -0
  261. package/src/components/common/dropdown/MenuPanel.tsx +69 -0
  262. package/src/components/common/dropdown/MenuPortal.tsx +162 -0
  263. package/src/components/common/dropdown/MenuPortalLayer.tsx +6 -0
  264. package/src/components/common/dropdown/SelectMenu.tsx +243 -0
  265. package/src/components/common/dropdown/SelectMenuControl.tsx +23 -0
  266. package/src/components/common/dropdown/SelectMenuOptions.tsx +38 -0
  267. package/src/components/common/dropdown/menuPortalConstants.ts +11 -0
  268. package/src/components/common/dropdown/menuTypes.ts +71 -0
  269. package/src/components/common/dropdown/menuViewportPosition.test.ts +139 -0
  270. package/src/components/common/dropdown/menuViewportPosition.ts +122 -0
  271. package/src/components/common/dropdown/selectMenuLayout.test.ts +42 -0
  272. package/src/components/common/dropdown/selectMenuLayout.ts +123 -0
  273. package/src/components/common/dropdown/useMenuAnchorPosition.ts +109 -0
  274. package/src/components/common/dropdown/useSelectMenuAnchor.ts +30 -0
  275. package/src/components/common/evidence/StructuredEvidenceView.test.tsx +77 -0
  276. package/src/components/common/evidence/StructuredEvidenceView.tsx +312 -0
  277. package/src/components/common/evidence/index.ts +13 -0
  278. package/src/components/common/feedback/Badge.tsx +33 -0
  279. package/src/components/common/feedback/CapabilityPills.tsx +36 -0
  280. package/src/components/common/feedback/EmptyState.tsx +132 -0
  281. package/src/components/common/feedback/InfoHint.tsx +67 -0
  282. package/src/components/common/feedback/InlineBanner.tsx +82 -0
  283. package/src/components/common/feedback/PlatformChip.tsx +104 -0
  284. package/src/components/common/feedback/QuietPill.tsx +75 -0
  285. package/src/components/common/feedback/WorkProgressPanel.tsx +156 -0
  286. package/src/components/common/feedback/index.ts +33 -0
  287. package/src/components/common/inputs/BareInput.tsx +31 -0
  288. package/src/components/common/inputs/BareTextarea.tsx +10 -0
  289. package/src/components/common/inputs/Checkbox.tsx +13 -0
  290. package/src/components/common/inputs/FieldControlShell.tsx +49 -0
  291. package/src/components/common/inputs/FormField.tsx +40 -0
  292. package/src/components/common/inputs/HybridSearchField.tsx +280 -0
  293. package/src/components/common/inputs/InlineComposer.tsx +197 -0
  294. package/src/components/common/inputs/PaletteCirclePicker.tsx +26 -0
  295. package/src/components/common/inputs/PaletteDropdown.tsx +413 -0
  296. package/src/components/common/inputs/Radio.tsx +19 -0
  297. package/src/components/common/inputs/SearchField.tsx +128 -0
  298. package/src/components/common/inputs/SelectField.tsx +169 -0
  299. package/src/components/common/inputs/SurfacePalettePicker.tsx +54 -0
  300. package/src/components/common/inputs/TextAreaField.tsx +22 -0
  301. package/src/components/common/inputs/TextField.tsx +51 -0
  302. package/src/components/common/inputs/ToggleSwitch.tsx +110 -0
  303. package/src/components/common/inputs/WorkspacePicker.tsx +349 -0
  304. package/src/components/common/inputs/fieldStyles.ts +137 -0
  305. package/src/components/common/layout/PanelGroup.tsx +479 -0
  306. package/src/components/common/layout/index.ts +31 -0
  307. package/src/components/common/layout/panelLayoutConstants.ts +7 -0
  308. package/src/components/common/layout/panelLayoutPersistence.ts +35 -0
  309. package/src/components/common/layout/panelLayoutState.test.ts +38 -0
  310. package/src/components/common/layout/panelLayoutState.ts +174 -0
  311. package/src/components/common/layout/panelLayoutTypes.ts +19 -0
  312. package/src/components/common/layout/tabs/Tabs.tsx +136 -0
  313. package/src/components/common/lists/listRowStyles.ts +32 -0
  314. package/src/components/common/lists/quiet-ledger/QuietActivityList.tsx +64 -0
  315. package/src/components/common/lists/quiet-ledger/QuietLedgerRow.tsx +119 -0
  316. package/src/components/common/lists/quiet-ledger/index.ts +9 -0
  317. package/src/components/common/lists/reorderable/DragHandle.tsx +65 -0
  318. package/src/components/common/lists/reorderable/ReorderableList.tsx +280 -0
  319. package/src/components/common/lists/reorderable/ReorderableListRow.tsx +102 -0
  320. package/src/components/common/lists/reorderable/ReorderableSections.tsx +344 -0
  321. package/src/components/common/lists/reorderable/ReorderableSectionsDemo.tsx +94 -0
  322. package/src/components/common/lists/reorderable/index.ts +15 -0
  323. package/src/components/common/lists/reorderable/reorderableUtils.test.ts +28 -0
  324. package/src/components/common/lists/reorderable/reorderableUtils.ts +23 -0
  325. package/src/components/common/lists/reorderable/types.ts +40 -0
  326. package/src/components/common/lists/reorderable/useReorderableDragState.ts +49 -0
  327. package/src/components/common/media/ImageReferencePicker.tsx +242 -0
  328. package/src/components/common/menubar/MenuBar.tsx +78 -0
  329. package/src/components/common/menubar/MenuBarTrigger.tsx +70 -0
  330. package/src/components/common/narrative/NarrativeMention.tsx +74 -0
  331. package/src/components/common/navigation/PathBreadcrumbs.tsx +78 -0
  332. package/src/components/common/navigation/UnderlineTabs.tsx +83 -0
  333. package/src/components/common/overlays/InstallAppPromptDialog.tsx +59 -0
  334. package/src/components/common/overlays/Modal.tsx +285 -0
  335. package/src/components/common/overlays/ModalChromeHeader.tsx +105 -0
  336. package/src/components/common/overlays/ObjectActionStrip.tsx +80 -0
  337. package/src/components/common/people/AutoUpdateReviewList.tsx +182 -0
  338. package/src/components/common/people/EntityList.tsx +122 -0
  339. package/src/components/common/people/EntityPortrait.tsx +64 -0
  340. package/src/components/common/people/LinkedDossierList.tsx +99 -0
  341. package/src/components/common/people/OpportunityList.tsx +94 -0
  342. package/src/components/common/people/PeopleSourceList.tsx +145 -0
  343. package/src/components/common/people/RelationshipDossier.tsx +168 -0
  344. package/src/components/common/people/RelationshipMap.tsx +362 -0
  345. package/src/components/common/people/index.ts +40 -0
  346. package/src/components/common/preview/FileAudioPreview.tsx +89 -0
  347. package/src/components/common/preview/FileImagePreview.tsx +88 -0
  348. package/src/components/common/preview/FilePdfPreview.tsx +87 -0
  349. package/src/components/common/preview/FileTextPreview.tsx +96 -0
  350. package/src/components/common/preview/FileVideoPreview.tsx +87 -0
  351. package/src/components/common/preview/PlatformFilePreview.tsx +166 -0
  352. package/src/components/common/preview/previewLayout.ts +27 -0
  353. package/src/components/common/render/Each.tsx +42 -0
  354. package/src/components/common/research/EvidenceDossier.tsx +894 -0
  355. package/src/components/common/research/index.ts +7 -0
  356. package/src/components/common/tiles/CatalogCard.tsx +116 -0
  357. package/src/components/common/tiles/Tile.tsx +45 -0
  358. package/src/components/common/tiles/TileGrid.tsx +13 -0
  359. package/src/components/common/typography/Heading.tsx +27 -0
  360. package/src/components/common/typography/Kicker.tsx +30 -0
  361. package/src/components/common/typography/Text.tsx +80 -0
  362. package/src/components/credentials/CredentialsPanel.tsx +169 -0
  363. package/src/components/credentials/credentialsTypes.ts +14 -0
  364. package/src/components/data/DataChart.tsx +913 -0
  365. package/src/components/data/dataTable.ts +99 -0
  366. package/src/components/editor/EditorCommentPromptDialog.tsx +124 -0
  367. package/src/components/editor/EditorLinkPromptDialog.tsx +65 -0
  368. package/src/components/print-design/PrintDesignPanel.test.tsx +1446 -0
  369. package/src/components/print-design/PrintDesignPanel.tsx +3043 -0
  370. package/src/components/print-design/index.ts +9 -0
  371. package/src/components/proofing/PagedProofDialog.tsx +453 -0
  372. package/src/components/proofing/index.ts +4 -0
  373. package/src/editor/DocumentEditor.tsx +28 -0
  374. package/src/editor/EditorViewModeToggle.tsx +35 -0
  375. package/src/editor/index.ts +97 -0
  376. package/src/editor/toolbarOverlays.ts +8 -0
  377. package/src/index.ts +209 -0
  378. package/src/theme/ThemeProvider.tsx +113 -0
  379. package/src/theme/appAccents.ts +87 -0
  380. package/src/theme/buildThemeBridgePayload.ts +23 -0
  381. package/src/theme/composePlatformTheme.test.ts +30 -0
  382. package/src/theme/composePlatformTheme.ts +23 -0
  383. package/src/theme/platformFont.d.mts +7 -0
  384. package/src/theme/platformFont.mjs +20 -0
  385. package/src/theme/platformFont.ts +6 -0
  386. package/src/theme/reportsShellChromeSelectors.ts +136 -0
  387. package/src/theme/styled.d.ts +5 -0
  388. package/src/theme/surfacePalettes.ts +178 -0
  389. package/src/theme/surfaceRoleSelectors.ts +113 -0
  390. package/src/theme/themeVars.ts +13 -0
  391. package/src/theme/themes/dark.ts +59 -0
  392. package/src/theme/themes/light.ts +60 -0
  393. package/src/theme/themes/palette.ts +44 -0
  394. package/src/theme/themes/shared.ts +68 -0
  395. package/src/theme/tokens.ts +114 -0
  396. package/src/theme/utils/GlobalStyles.ts +88 -0
  397. package/src/theme/utils/appFrameDocumentStyles.d.mts +5 -0
  398. package/src/theme/utils/appFrameDocumentStyles.mjs +89 -0
  399. package/src/theme/utils/appFrameDocumentStyles.ts +5 -0
  400. package/src/theme/utils/applyTheme.ts +50 -0
  401. package/src/theme/utils/cssVariables.ts +49 -0
  402. package/src/theme/utils/useInjectThemeIntoIframe.ts +40 -0
  403. package/src/utils/extensionIconMap.ts +123 -0
  404. package/src/utils/generalUtils.ts +157 -0
  405. package/src/writing/DraftAssistantDialog.tsx +279 -0
  406. package/src/writing/WritingStyleManager.tsx +416 -0
  407. package/src/writing/condenseWritingStyle.ts +103 -0
  408. package/src/writing/draftTextWithAgent.ts +134 -0
  409. package/src/writing/index.ts +39 -0
  410. package/src/writing/styleStore.ts +32 -0
  411. package/src/writing/writingStyle.test.ts +122 -0
  412. package/src/writing/writingStyle.ts +217 -0
@@ -0,0 +1,913 @@
1
+ import {
2
+ arc,
3
+ area,
4
+ extent,
5
+ line,
6
+ max,
7
+ pie,
8
+ quantile,
9
+ scaleBand,
10
+ scaleLinear,
11
+ scalePoint,
12
+ } from 'd3'
13
+
14
+ export type DataChartType =
15
+ | 'line'
16
+ | 'bar'
17
+ | 'area'
18
+ | 'scatter'
19
+ | 'donut'
20
+ | 'lollipop'
21
+ | 'histogram'
22
+ | 'boxplot'
23
+ | 'heatmap'
24
+ | 'stackedBar'
25
+ | 'horizontalBar'
26
+ | 'bubble'
27
+
28
+ export type DataCellValue = string | number | boolean | null
29
+
30
+ export interface DataColumnInfo {
31
+ name: string
32
+ type: 'number' | 'text' | 'boolean' | 'empty'
33
+ }
34
+
35
+ export interface DataChartTable {
36
+ columns: DataColumnInfo[]
37
+ rows: Record<string, DataCellValue>[]
38
+ }
39
+
40
+ export interface DataChartView {
41
+ id?: string
42
+ title?: string
43
+ sourceId?: string
44
+ filterText: string
45
+ x?: string
46
+ y: string[]
47
+ groupBy?: string
48
+ limit?: number
49
+ }
50
+
51
+ export interface DataChartBlock {
52
+ title: string
53
+ chartType?: DataChartType
54
+ }
55
+
56
+ const INK = '#2e3338'
57
+ const MUTED = '#757e8a'
58
+ const FAINT = '#a5adb8'
59
+ const GRID = '#e5e9ee'
60
+ const AXIS = '#8d96a2'
61
+
62
+ function valueLabel(value: DataCellValue): string {
63
+ return value === null ? '' : String(value)
64
+ }
65
+
66
+ function numeric(value: DataCellValue): number {
67
+ return typeof value === 'number' ? value : Number(value) || 0
68
+ }
69
+
70
+ function compactLabel(label: string, length = 14): string {
71
+ return label.length > length ? `${label.slice(0, length - 2)}…` : label
72
+ }
73
+
74
+ function chartHeightFor(
75
+ chartType: string,
76
+ rowCount: number,
77
+ seriesCount: number,
78
+ ): number {
79
+ const visibleRows = Math.max(1, rowCount)
80
+ if (chartType === 'horizontalBar')
81
+ return Math.min(320, Math.max(188, 112 + Math.min(10, visibleRows) * 28))
82
+ if (chartType === 'lollipop')
83
+ return Math.min(340, Math.max(196, 116 + Math.min(9, visibleRows) * 30))
84
+ if (chartType === 'donut') return 318
85
+ if (chartType === 'histogram') return 300
86
+ if (chartType === 'boxplot') return 318
87
+ if (chartType === 'heatmap')
88
+ return Math.min(420, Math.max(270, 150 + Math.min(10, visibleRows) * 18))
89
+ if (chartType === 'scatter' || chartType === 'bubble') return 340
90
+ if (chartType === 'stackedBar')
91
+ return visibleRows <= 4 && seriesCount <= 3 ? 306 : 348
92
+ if (chartType === 'bar') return visibleRows <= 4 ? 286 : 342
93
+ if (chartType === 'line' || chartType === 'area')
94
+ return visibleRows <= 4 ? 292 : 340
95
+ return 340
96
+ }
97
+
98
+ function chartMarginsFor(chartType: string) {
99
+ if (chartType === 'horizontalBar' || chartType === 'lollipop')
100
+ return { top: 52, right: 54, bottom: 28, left: 58 }
101
+ if (chartType === 'donut') return { top: 52, right: 54, bottom: 36, left: 54 }
102
+ return { top: 52, right: 72, bottom: 52, left: 58 }
103
+ }
104
+
105
+ function quartiles(values: number[]): {
106
+ min: number
107
+ q1: number
108
+ median: number
109
+ q3: number
110
+ max: number
111
+ } | null {
112
+ const sorted = values.filter(Number.isFinite).sort((a, b) => a - b)
113
+ if (!sorted.length) return null
114
+ return {
115
+ min: sorted[0],
116
+ q1: quantile(sorted, 0.25) ?? sorted[0],
117
+ median: quantile(sorted, 0.5) ?? sorted[0],
118
+ q3: quantile(sorted, 0.75) ?? sorted.at(-1) ?? sorted[0],
119
+ max: sorted.at(-1) ?? sorted[0],
120
+ }
121
+ }
122
+
123
+ interface DataChartProps {
124
+ block: DataChartBlock
125
+ view: DataChartView
126
+ table: DataChartTable
127
+ palette: readonly string[]
128
+ }
129
+
130
+ function includesSearch(
131
+ row: Record<string, DataCellValue>,
132
+ search: string,
133
+ ): boolean {
134
+ if (!search.trim()) return true
135
+ const needle = search.toLowerCase()
136
+ return Object.values(row).some(value =>
137
+ String(value ?? '')
138
+ .toLowerCase()
139
+ .includes(needle),
140
+ )
141
+ }
142
+
143
+ function chartRowsForView({
144
+ view,
145
+ table,
146
+ xKey,
147
+ yKeys,
148
+ aggregate = true,
149
+ }: {
150
+ view: DataChartView
151
+ table: DataChartTable
152
+ xKey: string | undefined
153
+ yKeys: string[]
154
+ aggregate?: boolean
155
+ }): Record<string, DataCellValue>[] {
156
+ const rows = table.rows.filter(row => includesSearch(row, view.filterText))
157
+ const limitRows = (items: Record<string, DataCellValue>[]) =>
158
+ typeof view.limit === 'number' ? items.slice(0, view.limit) : items
159
+ const groupKey = view.groupBy ?? xKey
160
+ if (!aggregate || !groupKey) return limitRows(rows)
161
+
162
+ const groups = new Map<string, Record<string, DataCellValue>>()
163
+ let hasRepeatedGroup = false
164
+ for (const row of rows) {
165
+ const label = String(row[groupKey] ?? '')
166
+ const existing = groups.get(label)
167
+ if (existing) {
168
+ hasRepeatedGroup = true
169
+ for (const key of yKeys) existing[key] = numeric(existing[key]) + numeric(row[key])
170
+ continue
171
+ }
172
+ const groupedRow: Record<string, DataCellValue> = { ...row, [groupKey]: label }
173
+ for (const key of yKeys) groupedRow[key] = numeric(row[key])
174
+ groups.set(label, groupedRow)
175
+ }
176
+
177
+ return limitRows(
178
+ hasRepeatedGroup || view.groupBy ? [...groups.values()] : rows,
179
+ )
180
+ }
181
+
182
+ export function DataChart({ block, view, table, palette }: DataChartProps) {
183
+ const chartType = block.chartType ?? 'line'
184
+ const xKey = view.groupBy ?? view.x ?? table.columns[0]?.name
185
+ const yKeys =
186
+ view.y.length > 0
187
+ ? view.y
188
+ : table.columns
189
+ .filter(column => column.type === 'number')
190
+ .map(column => column.name)
191
+ .slice(0, 1)
192
+ const rows = chartRowsForView({
193
+ view: { ...view, limit: view.limit ?? 40 },
194
+ table,
195
+ xKey,
196
+ yKeys,
197
+ aggregate: chartType !== 'scatter' && chartType !== 'bubble',
198
+ })
199
+ const width = 760
200
+ const height = chartHeightFor(chartType, rows.length, yKeys.length)
201
+ const margin = chartMarginsFor(chartType)
202
+ const innerWidth = width - margin.left - margin.right
203
+ const innerHeight = height - margin.top - margin.bottom
204
+ const values = rows.flatMap(row => yKeys.map(key => numeric(row[key])))
205
+ const primaryKey = yKeys[0] ?? ''
206
+ const yDomain = [Math.min(0, extent(values)[0] ?? 0), max(values) ?? 1] as [
207
+ number,
208
+ number,
209
+ ]
210
+ const y = scaleLinear().domain(yDomain).nice().range([innerHeight, 0])
211
+ const zeroY = y(Math.max(0, y.domain()[0] ?? 0))
212
+ const labels = rows.map(row => valueLabel(row[xKey]))
213
+ // Scales are keyed by row index, not label text: band/point scales intern
214
+ // their domain, so duplicate labels would otherwise collapse onto one slot.
215
+ const rowKeys = rows.map((_, index) => String(index))
216
+ const pointX = scalePoint<string>()
217
+ .domain(rowKeys)
218
+ .range([0, innerWidth])
219
+ .padding(0.35)
220
+ const barX = scaleBand<string>()
221
+ .domain(rowKeys)
222
+ .range([0, innerWidth])
223
+ .padding(0.28)
224
+ const barSeries = scaleBand<string>()
225
+ .domain(yKeys)
226
+ .range([0, barX.bandwidth()])
227
+ .padding(0.16)
228
+
229
+ const colors = palette.length
230
+ ? palette
231
+ : ['#4f74a8', '#b47b3f', '#6f9278', '#8a738d']
232
+ const visibleXStep = Math.max(1, Math.ceil(labels.length / 7))
233
+ const showInlineLegend =
234
+ yKeys.length > 1 &&
235
+ ![
236
+ 'donut',
237
+ 'lollipop',
238
+ 'horizontalBar',
239
+ 'histogram',
240
+ 'boxplot',
241
+ 'heatmap',
242
+ ].includes(chartType)
243
+ const donutValues = rows
244
+ .map((row, index) => ({
245
+ index,
246
+ label: labels[index] ?? '',
247
+ value: Math.max(0, numeric(row[primaryKey])),
248
+ }))
249
+ .filter(item => item.value > 0)
250
+ const donutTotal = donutValues.reduce((sum, item) => sum + item.value, 0)
251
+ const donutPie = pie<(typeof donutValues)[number]>()
252
+ .sort(null)
253
+ .value(item => item.value)(donutValues)
254
+ const donutArc = arc<(typeof donutPie)[number]>()
255
+ .innerRadius(78)
256
+ .outerRadius(126)
257
+ .cornerRadius(5)
258
+ .padAngle(0.018)
259
+ const lollipopX = scaleLinear()
260
+ .domain([0, max(rows, row => Math.max(0, numeric(row[primaryKey]))) ?? 1])
261
+ .nice()
262
+ .range([0, Math.max(180, innerWidth - 230)])
263
+ const horizontalBarX = scaleLinear()
264
+ .domain([0, max(rows, row => Math.max(0, numeric(row[primaryKey]))) ?? 1])
265
+ .nice()
266
+ .range([0, Math.max(180, innerWidth - 240)])
267
+ const bubbleKey = yKeys[1] ?? yKeys[0] ?? ''
268
+ const bubbleSize = scaleLinear()
269
+ .domain([0, max(rows, row => Math.max(0, numeric(row[bubbleKey]))) ?? 1])
270
+ .range([4, 14])
271
+ const histogramValues = rows
272
+ .map(row => numeric(row[primaryKey]))
273
+ .filter(Number.isFinite)
274
+ const histogramDomain = extent(histogramValues) as [number, number]
275
+ const histogramBinCount = Math.min(
276
+ 12,
277
+ Math.max(4, Math.ceil(Math.sqrt(histogramValues.length || 1))),
278
+ )
279
+ const histogramStep =
280
+ histogramDomain[0] === histogramDomain[1]
281
+ ? 1
282
+ : (histogramDomain[1] - histogramDomain[0]) / histogramBinCount
283
+ const histogramBins = Array.from({ length: histogramBinCount }, (_, index) => {
284
+ const start = (histogramDomain[0] ?? 0) + histogramStep * index
285
+ const end =
286
+ index === histogramBinCount - 1
287
+ ? histogramDomain[1] ?? start
288
+ : start + histogramStep
289
+ const count = histogramValues.filter(value =>
290
+ index === histogramBinCount - 1
291
+ ? value >= start && value <= end
292
+ : value >= start && value < end,
293
+ ).length
294
+ return { start, end, count }
295
+ })
296
+ const histogramY = scaleLinear()
297
+ .domain([0, max(histogramBins, bin => bin.count) ?? 1])
298
+ .nice()
299
+ .range([innerHeight, 0])
300
+ const histogramX = scaleBand<string>()
301
+ .domain(histogramBins.map((_, index) => String(index)))
302
+ .range([0, innerWidth])
303
+ .padding(0.08)
304
+ const boxGroups = rows.reduce<Map<string, number[]>>((groups, row) => {
305
+ const label = valueLabel(row[xKey])
306
+ const valuesForGroup = groups.get(label) ?? []
307
+ valuesForGroup.push(numeric(row[primaryKey]))
308
+ groups.set(label, valuesForGroup)
309
+ return groups
310
+ }, new Map())
311
+ const boxStats = Array.from(boxGroups, ([label, valuesForGroup]) => ({
312
+ label,
313
+ stats: quartiles(valuesForGroup),
314
+ })).filter(
315
+ (
316
+ item,
317
+ ): item is {
318
+ label: string
319
+ stats: NonNullable<ReturnType<typeof quartiles>>
320
+ } =>
321
+ item.stats !== null,
322
+ )
323
+ const boxY = scaleLinear()
324
+ .domain([
325
+ Math.min(0, minValue(boxStats.map(item => item.stats.min))),
326
+ max(boxStats, item => item.stats.max) ?? 1,
327
+ ])
328
+ .nice()
329
+ .range([innerHeight, 0])
330
+ const boxX = scaleBand<string>()
331
+ .domain(boxStats.map(item => item.label))
332
+ .range([0, innerWidth])
333
+ .padding(0.36)
334
+ const heatmapYKey =
335
+ table.columns.find(
336
+ column => column.type !== 'number' && column.name !== xKey,
337
+ )?.name ?? table.columns.find(column => column.name !== xKey)?.name
338
+ const heatmapColumns = Array.from(
339
+ new Set(rows.map(row => valueLabel(row[xKey]))),
340
+ ).slice(0, 12)
341
+ const heatmapRows = Array.from(
342
+ new Set(rows.map(row => valueLabel(row[heatmapYKey ?? '']))),
343
+ ).slice(0, 10)
344
+ const heatmapValues = new Map<string, number>()
345
+ rows.forEach(row => {
346
+ const column = valueLabel(row[xKey])
347
+ const rowLabel = valueLabel(row[heatmapYKey ?? ''])
348
+ const key = `${column}::${rowLabel}`
349
+ heatmapValues.set(
350
+ key,
351
+ (heatmapValues.get(key) ?? 0) + numeric(row[primaryKey]),
352
+ )
353
+ })
354
+ const heatmapMax = max(Array.from(heatmapValues.values())) ?? 1
355
+ const heatmapX = scaleBand<string>()
356
+ .domain(heatmapColumns)
357
+ .range([0, innerWidth])
358
+ .padding(0.08)
359
+ const heatmapY = scaleBand<string>()
360
+ .domain(heatmapRows)
361
+ .range([0, innerHeight])
362
+ .padding(0.08)
363
+ const stackedTotals = rows.map(row =>
364
+ yKeys.reduce((sum, key) => sum + Math.max(0, numeric(row[key])), 0),
365
+ )
366
+ const stackedY = scaleLinear()
367
+ .domain([0, max(stackedTotals) ?? 1])
368
+ .nice()
369
+ .range([innerHeight, 0])
370
+ const valueY = chartType === 'stackedBar' ? stackedY : y
371
+ const ticks = valueY.ticks(4)
372
+
373
+ function minValue(valuesForScale: number[]): number {
374
+ return valuesForScale.length ? Math.min(...valuesForScale) : 0
375
+ }
376
+
377
+ return (
378
+ <svg viewBox={`0 0 ${width} ${height}`} role="img" aria-label={block.title}>
379
+ <text
380
+ x={margin.left}
381
+ y={26}
382
+ fill={INK}
383
+ fontFamily="Source Sans 3, system-ui, sans-serif"
384
+ fontSize="18"
385
+ fontWeight="700"
386
+ >
387
+ {block.title}
388
+ </text>
389
+ <text
390
+ x={margin.left}
391
+ y={44}
392
+ fill={MUTED}
393
+ fontFamily="Source Sans 3, system-ui, sans-serif"
394
+ fontSize="11"
395
+ fontWeight="600"
396
+ >
397
+ {compactLabel(yKeys.join(' / '), 44)} by {compactLabel(xKey ?? '', 20)}
398
+ </text>
399
+ <g transform={`translate(${margin.left},${margin.top})`}>
400
+ {showInlineLegend ? (
401
+ <g transform={`translate(${Math.max(0, innerWidth - 168)},-30)`}>
402
+ {yKeys.slice(0, 4).map((key, index) => (
403
+ <g key={key} transform={`translate(${(index % 2) * 84},${Math.floor(index / 2) * 16})`}>
404
+ <line
405
+ x1={0}
406
+ x2={14}
407
+ y1={0}
408
+ y2={0}
409
+ stroke={colors[index % colors.length]}
410
+ strokeWidth={3}
411
+ strokeLinecap="round"
412
+ />
413
+ <text
414
+ x={20}
415
+ y={4}
416
+ fill={MUTED}
417
+ fontFamily="Source Sans 3, system-ui, sans-serif"
418
+ fontSize="10"
419
+ fontWeight="700"
420
+ >
421
+ {compactLabel(key, 10)}
422
+ </text>
423
+ </g>
424
+ ))}
425
+ </g>
426
+ ) : null}
427
+ {chartType === 'donut' ? (
428
+ <g
429
+ transform={`translate(${innerWidth / 2 - 115},${innerHeight / 2})`}
430
+ >
431
+ {donutPie.map((slice, index) => (
432
+ <path
433
+ key={`${slice.data.label}-${index}`}
434
+ d={donutArc(slice) ?? ''}
435
+ fill={colors[index % colors.length]}
436
+ opacity={0.86}
437
+ />
438
+ ))}
439
+ <text
440
+ textAnchor="middle"
441
+ y={-4}
442
+ fill={INK}
443
+ fontFamily="Source Sans 3, system-ui, sans-serif"
444
+ fontSize="22"
445
+ fontWeight="800"
446
+ >
447
+ {donutTotal.toLocaleString()}
448
+ </text>
449
+ <text
450
+ textAnchor="middle"
451
+ y={17}
452
+ fill={MUTED}
453
+ fontFamily="Source Sans 3, system-ui, sans-serif"
454
+ fontSize="11"
455
+ fontWeight="700"
456
+ >
457
+ total {primaryKey}
458
+ </text>
459
+ </g>
460
+ ) : null}
461
+ {chartType === 'donut' ? (
462
+ <g transform={`translate(${innerWidth / 2 + 60},42)`}>
463
+ {donutValues.slice(0, 7).map((item, index) => {
464
+ const share = donutTotal > 0 ? item.value / donutTotal : 0
465
+ return (
466
+ <g key={item.label} transform={`translate(0,${index * 30})`}>
467
+ <circle
468
+ cx={0}
469
+ cy={0}
470
+ r={6}
471
+ fill={colors[index % colors.length]}
472
+ opacity={0.86}
473
+ />
474
+ <text
475
+ x={16}
476
+ y={4}
477
+ fill={INK}
478
+ fontFamily="Source Sans 3, system-ui, sans-serif"
479
+ fontSize="12"
480
+ fontWeight="700"
481
+ >
482
+ {compactLabel(item.label, 18)}
483
+ </text>
484
+ <text
485
+ x={190}
486
+ y={4}
487
+ textAnchor="end"
488
+ fill={MUTED}
489
+ fontFamily="Source Sans 3, system-ui, sans-serif"
490
+ fontSize="11"
491
+ fontWeight="700"
492
+ >
493
+ {Math.round(share * 100)}%
494
+ </text>
495
+ </g>
496
+ )
497
+ })}
498
+ </g>
499
+ ) : null}
500
+ {chartType !== 'donut' &&
501
+ chartType !== 'lollipop' &&
502
+ chartType !== 'horizontalBar' &&
503
+ chartType !== 'heatmap' &&
504
+ chartType !== 'boxplot'
505
+ ? ticks.map(tick => (
506
+ <g key={tick} transform={`translate(0,${valueY(tick)})`}>
507
+ <line
508
+ x1={0}
509
+ x2={innerWidth}
510
+ stroke={GRID}
511
+ strokeDasharray="2 9"
512
+ />
513
+ <text
514
+ x={-12}
515
+ y={4}
516
+ textAnchor="end"
517
+ fill={MUTED}
518
+ fontFamily="Source Sans 3, system-ui, sans-serif"
519
+ fontSize="11"
520
+ fontWeight="600"
521
+ >
522
+ {tick}
523
+ </text>
524
+ </g>
525
+ ))
526
+ : null}
527
+ {chartType !== 'donut' &&
528
+ chartType !== 'lollipop' &&
529
+ chartType !== 'horizontalBar' &&
530
+ chartType !== 'heatmap' &&
531
+ chartType !== 'boxplot' ? (
532
+ <>
533
+ <line
534
+ y1={innerHeight}
535
+ x2={innerWidth}
536
+ y2={innerHeight}
537
+ stroke={AXIS}
538
+ />
539
+ <line y1={0} y2={innerHeight} stroke={AXIS} />
540
+ </>
541
+ ) : null}
542
+ {chartType === 'lollipop'
543
+ ? rows.slice(0, 9).map((row, rowIndex) => {
544
+ const rowY = 20 + rowIndex * 27
545
+ const value = Math.max(0, numeric(row[primaryKey]))
546
+ const color = colors[rowIndex % colors.length]
547
+ return (
548
+ <g key={`${rowIndex}-${labels[rowIndex]}`}>
549
+ <text
550
+ x={0}
551
+ y={rowY + 4}
552
+ fill={INK}
553
+ fontFamily="Source Sans 3, system-ui, sans-serif"
554
+ fontSize="12"
555
+ fontWeight="700"
556
+ >
557
+ {compactLabel(labels[rowIndex] ?? '', 20)}
558
+ </text>
559
+ <line
560
+ x1={170}
561
+ x2={170 + lollipopX(value)}
562
+ y1={rowY}
563
+ y2={rowY}
564
+ stroke={GRID}
565
+ strokeWidth={5}
566
+ strokeLinecap="round"
567
+ />
568
+ <circle
569
+ cx={170 + lollipopX(value)}
570
+ cy={rowY}
571
+ r={7}
572
+ fill={color}
573
+ opacity={0.84}
574
+ />
575
+ <text
576
+ x={180 + lollipopX(value)}
577
+ y={rowY + 4}
578
+ fill={MUTED}
579
+ fontFamily="Source Sans 3, system-ui, sans-serif"
580
+ fontSize="11"
581
+ fontWeight="700"
582
+ >
583
+ {value.toLocaleString()}
584
+ </text>
585
+ </g>
586
+ )
587
+ })
588
+ : null}
589
+ {chartType === 'horizontalBar'
590
+ ? rows.slice(0, 10).map((row, rowIndex) => {
591
+ const rowY = 18 + rowIndex * 25
592
+ const value = Math.max(0, numeric(row[primaryKey]))
593
+ const color = colors[rowIndex % colors.length]
594
+ const barWidth = horizontalBarX(value)
595
+ return (
596
+ <g key={`${rowIndex}-${labels[rowIndex]}`}>
597
+ <text
598
+ x={0}
599
+ y={rowY + 4}
600
+ fill={INK}
601
+ fontFamily="Source Sans 3, system-ui, sans-serif"
602
+ fontSize="11"
603
+ fontWeight="700"
604
+ >
605
+ {compactLabel(labels[rowIndex] ?? '', 22)}
606
+ </text>
607
+ <rect
608
+ x={178}
609
+ y={rowY - 8}
610
+ width={barWidth}
611
+ height={16}
612
+ rx={8}
613
+ fill={color}
614
+ opacity={0.72}
615
+ />
616
+ <text
617
+ x={Math.min(innerWidth - 28, 188 + barWidth)}
618
+ y={rowY + 4}
619
+ fill={MUTED}
620
+ fontFamily="Source Sans 3, system-ui, sans-serif"
621
+ fontSize="10"
622
+ fontWeight="700"
623
+ >
624
+ {value.toLocaleString()}
625
+ </text>
626
+ </g>
627
+ )
628
+ })
629
+ : null}
630
+ {chartType === 'histogram'
631
+ ? histogramBins.map((bin, index) => {
632
+ const x = histogramX(String(index)) ?? 0
633
+ return (
634
+ <g key={`${bin.start}-${bin.end}`}>
635
+ <rect
636
+ x={x}
637
+ y={histogramY(bin.count)}
638
+ width={histogramX.bandwidth()}
639
+ height={innerHeight - histogramY(bin.count)}
640
+ rx={5}
641
+ fill={colors[0]}
642
+ opacity={0.72}
643
+ />
644
+ <text
645
+ x={x + histogramX.bandwidth() / 2}
646
+ y={innerHeight + 24}
647
+ textAnchor="middle"
648
+ fill={FAINT}
649
+ fontFamily="Source Sans 3, system-ui, sans-serif"
650
+ fontSize="10"
651
+ fontWeight="700"
652
+ >
653
+ {Math.round(bin.start).toLocaleString()}
654
+ </text>
655
+ </g>
656
+ )
657
+ })
658
+ : null}
659
+ {chartType === 'boxplot'
660
+ ? boxStats.slice(0, 10).map((item, index) => {
661
+ const x = boxX(item.label) ?? 0
662
+ const mid = x + boxX.bandwidth() / 2
663
+ const color = colors[index % colors.length]
664
+ return (
665
+ <g key={item.label}>
666
+ <line
667
+ x1={mid}
668
+ x2={mid}
669
+ y1={boxY(item.stats.min)}
670
+ y2={boxY(item.stats.max)}
671
+ stroke={color}
672
+ strokeWidth={2}
673
+ />
674
+ <rect
675
+ x={x}
676
+ y={boxY(item.stats.q3)}
677
+ width={boxX.bandwidth()}
678
+ height={Math.max(2, boxY(item.stats.q1) - boxY(item.stats.q3))}
679
+ rx={5}
680
+ fill={color}
681
+ opacity={0.22}
682
+ stroke={color}
683
+ strokeWidth={1.5}
684
+ />
685
+ <line
686
+ x1={x}
687
+ x2={x + boxX.bandwidth()}
688
+ y1={boxY(item.stats.median)}
689
+ y2={boxY(item.stats.median)}
690
+ stroke={color}
691
+ strokeWidth={2.4}
692
+ />
693
+ <text
694
+ x={mid}
695
+ y={innerHeight + 24}
696
+ textAnchor="middle"
697
+ fill={FAINT}
698
+ fontFamily="Source Sans 3, system-ui, sans-serif"
699
+ fontSize="10"
700
+ fontWeight="700"
701
+ >
702
+ {compactLabel(item.label, 12)}
703
+ </text>
704
+ </g>
705
+ )
706
+ })
707
+ : null}
708
+ {chartType === 'heatmap'
709
+ ? heatmapRows.flatMap(rowLabel =>
710
+ heatmapColumns.map(columnLabel => {
711
+ const value = heatmapValues.get(`${columnLabel}::${rowLabel}`) ?? 0
712
+ const opacity = heatmapMax > 0 ? 0.12 + (value / heatmapMax) * 0.72 : 0.12
713
+ return (
714
+ <g key={`${columnLabel}-${rowLabel}`}>
715
+ <rect
716
+ x={heatmapX(columnLabel) ?? 0}
717
+ y={heatmapY(rowLabel) ?? 0}
718
+ width={heatmapX.bandwidth()}
719
+ height={heatmapY.bandwidth()}
720
+ rx={4}
721
+ fill={colors[0]}
722
+ opacity={opacity}
723
+ />
724
+ {heatmapX.bandwidth() > 46 && heatmapY.bandwidth() > 24 ? (
725
+ <text
726
+ x={(heatmapX(columnLabel) ?? 0) + heatmapX.bandwidth() / 2}
727
+ y={(heatmapY(rowLabel) ?? 0) + heatmapY.bandwidth() / 2 + 4}
728
+ textAnchor="middle"
729
+ fill={INK}
730
+ fontFamily="Source Sans 3, system-ui, sans-serif"
731
+ fontSize="10"
732
+ fontWeight="700"
733
+ >
734
+ {value ? value.toLocaleString() : ''}
735
+ </text>
736
+ ) : null}
737
+ </g>
738
+ )
739
+ }),
740
+ )
741
+ : null}
742
+ {chartType === 'heatmap'
743
+ ? heatmapColumns.map(columnLabel => (
744
+ <text
745
+ key={columnLabel}
746
+ x={(heatmapX(columnLabel) ?? 0) + heatmapX.bandwidth() / 2}
747
+ y={innerHeight + 24}
748
+ textAnchor="middle"
749
+ fill={FAINT}
750
+ fontFamily="Source Sans 3, system-ui, sans-serif"
751
+ fontSize="10"
752
+ fontWeight="700"
753
+ >
754
+ {compactLabel(columnLabel, 10)}
755
+ </text>
756
+ ))
757
+ : null}
758
+ {chartType === 'heatmap'
759
+ ? heatmapRows.map(rowLabel => (
760
+ <text
761
+ key={rowLabel}
762
+ x={-10}
763
+ y={(heatmapY(rowLabel) ?? 0) + heatmapY.bandwidth() / 2 + 4}
764
+ textAnchor="end"
765
+ fill={MUTED}
766
+ fontFamily="Source Sans 3, system-ui, sans-serif"
767
+ fontSize="10"
768
+ fontWeight="700"
769
+ >
770
+ {compactLabel(rowLabel, 12)}
771
+ </text>
772
+ ))
773
+ : null}
774
+ {chartType === 'stackedBar'
775
+ ? rows.map((row, rowIndex) => {
776
+ let cursor = 0
777
+ return (
778
+ <g key={`${rowIndex}-${labels[rowIndex]}`}>
779
+ {yKeys.map((key, index) => {
780
+ const value = Math.max(0, numeric(row[key]))
781
+ const y0 = stackedY(cursor)
782
+ cursor += value
783
+ const y1 = stackedY(cursor)
784
+ return (
785
+ <rect
786
+ key={key}
787
+ x={barX(String(rowIndex)) ?? 0}
788
+ y={y1}
789
+ width={barX.bandwidth()}
790
+ height={Math.max(0, y0 - y1)}
791
+ rx={index === yKeys.length - 1 ? 4 : 0}
792
+ fill={colors[index % colors.length]}
793
+ opacity={0.78}
794
+ />
795
+ )
796
+ })}
797
+ </g>
798
+ )
799
+ })
800
+ : null}
801
+ {chartType === 'bar'
802
+ ? rows.flatMap((row, rowIndex) =>
803
+ yKeys.map((key, index) => {
804
+ const x0 = barX(String(rowIndex)) ?? 0
805
+ const x1 = barSeries(key) ?? 0
806
+ const value = numeric(row[key])
807
+ return (
808
+ <rect
809
+ key={`${rowIndex}-${valueLabel(row[xKey])}-${key}`}
810
+ x={x0 + x1}
811
+ y={Math.min(y(value), zeroY)}
812
+ width={barSeries.bandwidth()}
813
+ height={Math.abs(zeroY - y(value))}
814
+ rx={4}
815
+ fill={colors[index % colors.length]}
816
+ opacity={0.78}
817
+ />
818
+ )
819
+ }),
820
+ )
821
+ : chartType === 'donut' ||
822
+ chartType === 'lollipop' ||
823
+ chartType === 'horizontalBar' ||
824
+ chartType === 'histogram' ||
825
+ chartType === 'boxplot' ||
826
+ chartType === 'heatmap' ||
827
+ chartType === 'stackedBar'
828
+ ? null
829
+ : (chartType === 'bubble' ? yKeys.slice(0, 1) : yKeys).map((key, index) => {
830
+ const path = line<Record<string, DataCellValue>>()
831
+ .x((_, rowIndex) => pointX(String(rowIndex)) ?? 0)
832
+ .y(row => y(numeric(row[key])))(rows)
833
+ const areaPath = area<Record<string, DataCellValue>>()
834
+ .x((_, rowIndex) => pointX(String(rowIndex)) ?? 0)
835
+ .y0(zeroY)
836
+ .y1(row => y(numeric(row[key])))(rows)
837
+ const color = colors[index % colors.length]
838
+ return (
839
+ <g key={key}>
840
+ {chartType === 'area' ? (
841
+ <path d={areaPath ?? ''} fill={color} opacity={0.18} />
842
+ ) : null}
843
+ {chartType !== 'scatter' && chartType !== 'bubble' ? (
844
+ <path
845
+ d={path ?? ''}
846
+ fill="none"
847
+ stroke={color}
848
+ strokeWidth={2.2}
849
+ />
850
+ ) : null}
851
+ {rows.map((row, rowIndex) => (
852
+ <g key={`${key}-${rowIndex}-${valueLabel(row[xKey])}`}>
853
+ <circle
854
+ cx={pointX(String(rowIndex)) ?? 0}
855
+ cy={y(numeric(row[key]))}
856
+ r={
857
+ chartType === 'bubble'
858
+ ? bubbleSize(numeric(row[bubbleKey]))
859
+ : chartType === 'scatter'
860
+ ? 4
861
+ : rowIndex === rows.length - 1
862
+ ? 3.8
863
+ : 2.7
864
+ }
865
+ fill={chartType === 'area' ? '#fff' : color}
866
+ stroke={color}
867
+ strokeWidth={chartType === 'area' ? 1.8 : 0}
868
+ opacity={
869
+ chartType === 'line' && rowIndex !== rows.length - 1
870
+ ? 0.82
871
+ : 1
872
+ }
873
+ />
874
+ </g>
875
+ ))}
876
+ </g>
877
+ )
878
+ })}
879
+ {chartType !== 'donut' &&
880
+ chartType !== 'lollipop' &&
881
+ chartType !== 'horizontalBar' &&
882
+ chartType !== 'histogram' &&
883
+ chartType !== 'boxplot' &&
884
+ chartType !== 'heatmap'
885
+ ? labels.map((label, index) => {
886
+ const x =
887
+ chartType === 'bar'
888
+ ? (barX(String(index)) ?? 0) + barX.bandwidth() / 2
889
+ : pointX(String(index)) ?? 0
890
+ const visible =
891
+ labels.length <= 7 ||
892
+ index % visibleXStep === 0 ||
893
+ index === labels.length - 1
894
+ return visible ? (
895
+ <text
896
+ key={`${index}-${label}`}
897
+ x={x}
898
+ y={innerHeight + 25}
899
+ textAnchor="middle"
900
+ fill={FAINT}
901
+ fontFamily="Source Sans 3, system-ui, sans-serif"
902
+ fontSize="11"
903
+ fontWeight="600"
904
+ >
905
+ {compactLabel(label)}
906
+ </text>
907
+ ) : null
908
+ })
909
+ : null}
910
+ </g>
911
+ </svg>
912
+ )
913
+ }