@marimo-team/islands 0.25.1-dev4 → 0.25.1-dev40

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 (274) hide show
  1. package/dist/{ConnectedDataExplorerComponent-KVhjDMSe.js → ConnectedDataExplorerComponent-CwMXfDQR.js} +3 -3
  2. package/dist/{ErrorBoundary-pV36lYEK.js → ErrorBoundary-CAJO-M56.js} +1 -1
  3. package/dist/{ImageComparisonComponent-Dlm5aWnH.js → ImageComparisonComponent-Cpfz30OZ.js} +51 -52
  4. package/dist/{abnfDiagram-VCTEODGH-CpN0FRda.js → abnfDiagram-VCTEODGH-AFhOQTt8.js} +3 -3
  5. package/dist/{architectureDiagram-5GKGNRK7-DDyj5SRB.js → architectureDiagram-5GKGNRK7-BngksAAQ.js} +5 -5
  6. package/dist/{blockDiagram-I7D4REHJ-BbXEXJRu.js → blockDiagram-I7D4REHJ-CvBmppdy.js} +9 -9
  7. package/dist/{c4Diagram-7LVT6UL2-DcLsbQmR.js → c4Diagram-7LVT6UL2-EceL4_jH.js} +7 -7
  8. package/dist/{cells-B5-y5EY3.js → cells-Cv93oav_.js} +3 -3
  9. package/dist/{channel-B5XnTarr.js → channel-z7HZXHwv.js} +1 -1
  10. package/dist/{chat-ui-HJZsTl7o.js → chat-ui-DLSF8a04.js} +4 -4
  11. package/dist/{chunk-4HAMMTFA-D2qv8E0X.js → chunk-4HAMMTFA-BPTTOOC5.js} +5 -5
  12. package/dist/{chunk-75Z2AOVW-5_HsvXwr.js → chunk-75Z2AOVW-C4AOleKf.js} +1 -1
  13. package/dist/{chunk-DU6HZSFF-BUgAHvnM.js → chunk-DU6HZSFF-1TwWR6gh.js} +1 -1
  14. package/dist/{chunk-F27PBJKO-DHmYWZXr.js → chunk-F27PBJKO-DMI1PBe4.js} +1 -1
  15. package/dist/{chunk-GMAD6QVW-Czynz8aA.js → chunk-GMAD6QVW-vStrMz2P.js} +3 -3
  16. package/dist/{chunk-GVQU2GXP-yQEdulRS.js → chunk-GVQU2GXP-2HwWgs4u.js} +2 -2
  17. package/dist/{chunk-IMKFNOWR-BfwTebD0.js → chunk-IMKFNOWR-UOVZuZVn.js} +5 -5
  18. package/dist/{chunk-L3NEJ4N5-DwRWnDDK.js → chunk-L3NEJ4N5-RhC7i0I2.js} +5 -5
  19. package/dist/{chunk-OSK3NFVY-BBKU_Ign.js → chunk-OSK3NFVY-CZV09N-U.js} +6 -6
  20. package/dist/{chunk-P2QGCYS3-C0iGU29N.js → chunk-P2QGCYS3-0TAWai9C.js} +1 -1
  21. package/dist/{chunk-POPQ4Y6H-BCbS3Ozc.js → chunk-POPQ4Y6H-Cc3_56GX.js} +1 -1
  22. package/dist/{chunk-PWAF6VOD-CTFCL0jI.js → chunk-PWAF6VOD-lNxB9k8z.js} +1 -1
  23. package/dist/{chunk-SHT3W25Y-BspJEJ5H.js → chunk-SHT3W25Y-CrEPyWy1.js} +7 -7
  24. package/dist/{chunk-SVP7TREG-DX3rFNTe.js → chunk-SVP7TREG-uIyyySp6.js} +2 -2
  25. package/dist/{chunk-TICWLB2K-fVF7Uujg.js → chunk-TICWLB2K-DdXM3eg6.js} +5 -5
  26. package/dist/classDiagram-ZZMXUADV-BiATbBE4.js +30 -0
  27. package/dist/classDiagram-v2-VYDZK3BY-JnH97GYw.js +30 -0
  28. package/dist/{code-visibility-CgZS2a3W.js → code-visibility-XU9RAJNV.js} +2 -2
  29. package/dist/{common-DnMDPPaW.js → common-C0fbrgB8.js} +13 -13
  30. package/dist/{cynefinDiagram-5FMLGOSQ-CFQrqzSX.js → cynefinDiagram-5FMLGOSQ-zknaAsGy.js} +3 -3
  31. package/dist/{dagre-GXQ25YYZ-xHNAUTyG.js → dagre-GXQ25YYZ-BhMOoMGJ.js} +10 -10
  32. package/dist/{data-grid-overlay-editor-hHYgD_Sm.js → data-grid-overlay-editor-BnhbJgoq.js} +1 -1
  33. package/dist/{diagram-S7CK7UJ4-Bt1rPbAx.js → diagram-S7CK7UJ4-V5-Z-EDY.js} +4 -4
  34. package/dist/{diagram-UQ7AKVKN-D1sq5FoZ.js → diagram-UQ7AKVKN-qw8AjDal.js} +3 -3
  35. package/dist/{diagram-VSXAHHWV-BKpmG23x.js → diagram-VSXAHHWV-CR7BJygZ.js} +2 -2
  36. package/dist/{diagram-VX7I27RA-BMwGFVD6.js → diagram-VX7I27RA-DfuqFb1E.js} +5 -5
  37. package/dist/{diagram-Z3DM3KII--KLDR9Pl.js → diagram-Z3DM3KII-DpWwlYZB.js} +3 -3
  38. package/dist/{dist-BaHjhkpZ.js → dist-CcyKTBTF.js} +1 -1
  39. package/dist/{ebnfDiagram-PWID7BFC-WnG4cvSQ.js → ebnfDiagram-PWID7BFC-C20OnNMZ.js} +3 -3
  40. package/dist/{erDiagram-RLTQ6QDP-DhzKiYHc.js → erDiagram-RLTQ6QDP-DBXLWO9v.js} +12 -12
  41. package/dist/{error-entries-Bkbpx0T0.js → error-entries-DLl0XqoW.js} +1 -1
  42. package/dist/{feedback-button-CvKssdG_.js → feedback-button-B0QSkbSp.js} +4 -4
  43. package/dist/flowDiagram-HODETNUW-DL52nMkt.js +16 -0
  44. package/dist/{formats-C8rLgZT9.js → formats-Cl_67ghI.js} +1 -1
  45. package/dist/{ganttDiagram-EL5Y4UJY-DbzEBLbl.js → ganttDiagram-EL5Y4UJY-cRRaDt88.js} +2 -2
  46. package/dist/{gitGraphDiagram-WWUBYQGX-BMf0iKi1.js → gitGraphDiagram-WWUBYQGX-Pox5k9-Y.js} +2 -2
  47. package/dist/{glide-data-editor-Ohetlgag.js → glide-data-editor-ymIQdwrb.js} +3 -3
  48. package/dist/{globals-CPNNcOJI.js → globals-B0S3-e_D.js} +1 -1
  49. package/dist/{html-to-image-BAgJOlSW.js → html-to-image-CGVgroef.js} +2 -2
  50. package/dist/{infoDiagram-27XIBGKW-BagtCX_5.js → infoDiagram-27XIBGKW-ntpxMfrq.js} +2 -2
  51. package/dist/{ishikawaDiagram-5VMMS53U-DByDehYy.js → ishikawaDiagram-5VMMS53U-BllIlHE5.js} +3 -3
  52. package/dist/{journeyDiagram-3NMN7TZE-D2LcKDUO.js → journeyDiagram-3NMN7TZE-EPJDPlt0.js} +2 -2
  53. package/dist/{kanban-definition-UXKFOSKX-BxwkbBI_.js → kanban-definition-UXKFOSKX-GYtNMjtS.js} +9 -9
  54. package/dist/{katex-C6D4cX_N.js → katex-BNCmKUol.js} +983 -1120
  55. package/dist/{loader-D2W4oM-3.js → loader-DEZSzvma.js} +253 -248
  56. package/dist/main.js +72 -69
  57. package/dist/{mermaid-DPNuhemn.js → mermaid-Dnzoxjt1.js} +49 -49
  58. package/dist/{mhchem-DWCF06w9.js → mhchem-BEc7A1or.js} +1 -1
  59. package/dist/{mindmap-definition-YA3MSWOX-Cgvojw3y.js → mindmap-definition-YA3MSWOX-Cth76xgH.js} +11 -11
  60. package/dist/{number-overlay-editor-CHWg5gGO.js → number-overlay-editor-DB3HJDI1.js} +1 -1
  61. package/dist/{pegDiagram-XKGWAZYB-DahHhYyN.js → pegDiagram-XKGWAZYB-Cu4uOXii.js} +3 -3
  62. package/dist/{pieDiagram-E7YTZNPT-CCtX0oCK.js → pieDiagram-E7YTZNPT-Bh3eDa9s.js} +3 -3
  63. package/dist/{process-output-zDX4jbhd.js → process-output-CGfg-JmZ.js} +2 -2
  64. package/dist/{quadrantDiagram-AXDQQJYC-DftINo6g.js → quadrantDiagram-AXDQQJYC--kqzFC3w.js} +1 -1
  65. package/dist/{railroadDiagram-O6MQD6OU-Du5NsPUb.js → railroadDiagram-O6MQD6OU-DG-M6Rnc.js} +3 -3
  66. package/dist/{react-vega-5AcMW8gG.js → react-vega-ewj7q_U5.js} +1 -1
  67. package/dist/{requirementDiagram-BXWQKSXE-0pmmxL6_.js → requirementDiagram-BXWQKSXE-DCwsThh0.js} +11 -11
  68. package/dist/{reveal-component-BujcZI2B.js → reveal-component-CfTzIkA2.js} +3 -3
  69. package/dist/{sankeyDiagram-P5KCCOFB-CDKR5TJH.js → sankeyDiagram-P5KCCOFB-BdzhT0BM.js} +1 -1
  70. package/dist/{sequenceDiagram-WJ2MYXX4-DB-ChWwU.js → sequenceDiagram-WJ2MYXX4-CbXB1_PU.js} +4 -4
  71. package/dist/{stateDiagram-D77RDMKH-orN6AwMx.js → stateDiagram-D77RDMKH-A-Zf3Sb2.js} +13 -13
  72. package/dist/stateDiagram-v2-MP3YSRHH-D9YMnUGx.js +30 -0
  73. package/dist/style.css +1 -1
  74. package/dist/{swimlanes-42K2YHIH-BkSDcqDT.js → swimlanes-42K2YHIH-B_pMf0J4.js} +10 -10
  75. package/dist/swimlanesDiagram-VR7AAH4N-Ctgy-yGP.js +30 -0
  76. package/dist/{timeline-definition-24CTP7MA-BuqJUIRZ.js → timeline-definition-24CTP7MA-DTXFjTTM.js} +3 -3
  77. package/dist/{vega-component-CNf5gcrm.js → vega-component-tFOzgarw.js} +4 -4
  78. package/dist/{vega-embed-container-CbnTccZi.js → vega-embed-container-sSR5hAsy.js} +2 -2
  79. package/dist/{vega-loader.browser-D95WfUcj.js → vega-loader.browser-DNST6uVf.js} +2 -2
  80. package/dist/{vennDiagram-4TSXK5OY-CTUlJ2PK.js → vennDiagram-4TSXK5OY-BPHjZo0R.js} +3 -3
  81. package/dist/{wardleyDiagram-VM6X3IG4-3evLUb0M.js → wardleyDiagram-VM6X3IG4-6fTLYBuD.js} +3 -3
  82. package/dist/{xychartDiagram-S5SC5T6Z-DL2E3K8-.js → xychartDiagram-S5SC5T6Z-BYjwjrzE.js} +5 -5
  83. package/package.json +1 -2
  84. package/src/__mocks__/common.ts +3 -3
  85. package/src/__tests__/CellStatus.test.tsx +1 -1
  86. package/src/__tests__/setup.ts +7 -7
  87. package/src/components/app-config/ai-config.tsx +2 -0
  88. package/src/components/app-config/optional-features.tsx +1 -1
  89. package/src/components/chat/chat-panel.tsx +19 -8
  90. package/src/components/data-table/charts/__tests__/chart-panel.test.tsx +286 -0
  91. package/src/components/data-table/charts/charts.tsx +26 -13
  92. package/src/components/data-table/column-summary/chart-spec-model.tsx +4 -4
  93. package/src/components/dependency-graph/elements.ts +2 -2
  94. package/src/components/editor/__tests__/package-alert.test.tsx +140 -0
  95. package/src/components/editor/actions/__tests__/pair-with-agent.test.tsx +107 -0
  96. package/src/components/editor/actions/pair-with-agent.tsx +119 -0
  97. package/src/components/editor/actions/useNotebookActions.tsx +2 -1
  98. package/src/components/editor/ai/add-cell-with-ai.tsx +2 -0
  99. package/src/components/editor/ai/staged-cell-submission.ts +2 -2
  100. package/src/components/editor/ai/transport/chat-transport.tsx +1 -1
  101. package/src/components/editor/chrome/components/contribute-snippet-button.tsx +6 -1
  102. package/src/components/editor/connections/database/as-code.ts +44 -44
  103. package/src/components/editor/connections/storage/as-code.ts +3 -3
  104. package/src/components/editor/file-tree/requesting-tree.tsx +16 -13
  105. package/src/components/editor/navigation/clipboard.ts +2 -2
  106. package/src/components/editor/notebook-cell.tsx +2 -2
  107. package/src/components/editor/output/MarimoTracebackOutput.tsx +1 -1
  108. package/src/components/editor/output/VideoOutput.tsx +1 -1
  109. package/src/components/editor/output/ansi-reduce.ts +21 -17
  110. package/src/components/editor/output/console/ConsoleOutput.tsx +3 -3
  111. package/src/components/editor/output/console/__tests__/ConsoleOutput.test.tsx +59 -0
  112. package/src/components/editor/output/console/text-rendering.tsx +3 -1
  113. package/src/components/editor/package-alert.tsx +20 -7
  114. package/src/components/home/components.tsx +1 -0
  115. package/src/components/pages/run-page.tsx +1 -0
  116. package/src/components/slides/__tests__/minimap-actions.test.tsx +7 -7
  117. package/src/components/slides/__tests__/minimap.test.ts +12 -12
  118. package/src/components/slides/__tests__/slide-scroll-hint.test.tsx +8 -8
  119. package/src/components/static-html/share-modal.tsx +2 -1
  120. package/src/components/static-html/static-banner.tsx +2 -2
  121. package/src/components/ui/links.tsx +6 -1
  122. package/src/components/ui/typography.tsx +16 -8
  123. package/src/core/ai/context/__tests__/registry.test.ts +31 -28
  124. package/src/core/ai/context/providers/cell-output.ts +8 -8
  125. package/src/core/ai/context/providers/datasource.ts +10 -7
  126. package/src/core/ai/context/providers/error.ts +7 -7
  127. package/src/core/ai/context/providers/file.ts +8 -8
  128. package/src/core/ai/context/providers/tables.ts +7 -7
  129. package/src/core/ai/context/providers/variable.ts +7 -7
  130. package/src/core/ai/context/registry.ts +18 -18
  131. package/src/core/ai/ids/ids.ts +5 -5
  132. package/src/core/ai/model-registry.ts +12 -9
  133. package/src/core/ai/staged-cells.ts +6 -6
  134. package/src/core/ai/tools/base.ts +6 -6
  135. package/src/core/ai/tools/edit-notebook-tool.ts +6 -6
  136. package/src/core/ai/tools/registry.ts +4 -4
  137. package/src/core/ai/tools/run-cells-tool.ts +7 -7
  138. package/src/core/ai/tools/sample-tool.ts +6 -6
  139. package/src/core/cells/__tests__/cells.test.ts +27 -0
  140. package/src/core/cells/cells.ts +2 -1
  141. package/src/core/codemirror/cells/debugger-decorations.ts +13 -7
  142. package/src/core/codemirror/cells/line-timing-decorations.ts +9 -9
  143. package/src/core/codemirror/cells/traceback-decorations.ts +7 -4
  144. package/src/core/codemirror/code-lens/extension.ts +13 -13
  145. package/src/core/codemirror/copilot/__tests__/language-server.test.ts +6 -6
  146. package/src/core/codemirror/copilot/__tests__/transport.test.ts +12 -12
  147. package/src/core/codemirror/copilot/language-server.ts +13 -13
  148. package/src/core/codemirror/copilot/transport.ts +1 -1
  149. package/src/core/codemirror/find-replace/search-highlight.ts +5 -5
  150. package/src/core/codemirror/go-to-definition/underline.ts +3 -3
  151. package/src/core/codemirror/keymaps/vim.ts +3 -3
  152. package/src/core/codemirror/language/languages/markdown.ts +8 -8
  153. package/src/core/codemirror/language/languages/python.ts +7 -7
  154. package/src/core/codemirror/language/languages/sql/completion-builder.ts +5 -5
  155. package/src/core/codemirror/language/languages/sql/completion-store.ts +4 -4
  156. package/src/core/codemirror/language/languages/sql/sql.ts +21 -21
  157. package/src/core/codemirror/lsp/__tests__/transports.test.ts +10 -10
  158. package/src/core/codemirror/lsp/federated-lsp.ts +29 -27
  159. package/src/core/codemirror/lsp/notebook-lsp.ts +21 -21
  160. package/src/core/codemirror/misc/__tests__/dnd.test.ts +10 -10
  161. package/src/core/codemirror/misc/__tests__/paste.test.ts +7 -4
  162. package/src/core/codemirror/reactive-references/extension.ts +3 -3
  163. package/src/core/codemirror/rtc/loro/awareness.ts +12 -12
  164. package/src/core/codemirror/rtc/loro/sync.ts +5 -5
  165. package/src/core/codemirror/vim/cursor-visibility.ts +3 -3
  166. package/src/core/dom/ui-element.ts +5 -5
  167. package/src/core/dom/uiregistry.ts +10 -10
  168. package/src/core/hotkeys/hotkeys.ts +9 -9
  169. package/src/core/islands/__tests__/bridge.test.ts +4 -4
  170. package/src/core/islands/__tests__/test-utils.tsx +4 -4
  171. package/src/core/islands/bridge.ts +85 -82
  172. package/src/core/islands/components/web-components.tsx +7 -7
  173. package/src/core/islands/worker/__tests__/controller.test.ts +1 -1
  174. package/src/core/islands/worker/controller.ts +6 -3
  175. package/src/core/islands/worker-factory.ts +2 -2
  176. package/src/core/kernel/RuntimeState.ts +4 -4
  177. package/src/core/lsp/__tests__/transport.test.ts +19 -19
  178. package/src/core/lsp/transport.ts +5 -5
  179. package/src/core/network/CachingRequestRegistry.ts +2 -2
  180. package/src/core/network/DeferredRequestRegistry.ts +4 -4
  181. package/src/core/runtime/runtime.ts +25 -20
  182. package/src/core/static/virtual-file-tracker.ts +5 -5
  183. package/src/core/wasm/__tests__/bridge.test.ts +2 -2
  184. package/src/core/wasm/bridge.ts +130 -126
  185. package/src/core/wasm/router.ts +5 -5
  186. package/src/core/wasm/store.ts +4 -4
  187. package/src/core/wasm/worker/bootstrap.ts +8 -5
  188. package/src/core/wasm/worker/message-buffer.ts +3 -3
  189. package/src/core/websocket/transports/__tests__/ws.test.ts +8 -8
  190. package/src/core/websocket/transports/basic.ts +15 -8
  191. package/src/core/websocket/transports/sse.ts +7 -7
  192. package/src/core/websocket/transports/transport.ts +3 -3
  193. package/src/core/websocket/transports/ws.ts +9 -7
  194. package/src/css/globals.css +18 -21
  195. package/src/css/katex.min.css +260 -241
  196. package/src/hooks/__tests__/useOverflowDetection.test.tsx +5 -5
  197. package/src/hooks/__tests__/useResizeObserver.test.tsx +12 -12
  198. package/src/plugins/core/registerReactComponent.tsx +5 -5
  199. package/src/plugins/core/sidebar-element.tsx +2 -2
  200. package/src/plugins/impl/ButtonPlugin.tsx +3 -3
  201. package/src/plugins/impl/CheckboxPlugin.tsx +3 -3
  202. package/src/plugins/impl/CodeEditorPlugin.tsx +3 -3
  203. package/src/plugins/impl/DatePickerPlugin.tsx +3 -3
  204. package/src/plugins/impl/DateRangePlugin.tsx +3 -3
  205. package/src/plugins/impl/DateTimePickerPlugin.tsx +3 -3
  206. package/src/plugins/impl/DictPlugin.tsx +3 -3
  207. package/src/plugins/impl/DropdownPlugin.tsx +3 -3
  208. package/src/plugins/impl/FileUploadPlugin.tsx +3 -3
  209. package/src/plugins/impl/MatrixPlugin.tsx +4 -4
  210. package/src/plugins/impl/MicrophonePlugin.tsx +3 -3
  211. package/src/plugins/impl/MultiselectPlugin.tsx +3 -3
  212. package/src/plugins/impl/NumberPlugin.tsx +3 -3
  213. package/src/plugins/impl/RadioPlugin.tsx +9 -5
  214. package/src/plugins/impl/RangeSliderPlugin.tsx +3 -3
  215. package/src/plugins/impl/RefreshPlugin.tsx +3 -3
  216. package/src/plugins/impl/SliderPlugin.tsx +3 -3
  217. package/src/plugins/impl/SwitchPlugin.tsx +3 -3
  218. package/src/plugins/impl/TabsPlugin.tsx +3 -3
  219. package/src/plugins/impl/TextAreaPlugin.tsx +3 -3
  220. package/src/plugins/impl/TextInputPlugin.tsx +3 -3
  221. package/src/plugins/impl/__tests__/MatrixPlugin.test.tsx +2 -2
  222. package/src/plugins/impl/anywidget/model.ts +10 -10
  223. package/src/plugins/impl/anywidget/registry.ts +12 -9
  224. package/src/plugins/impl/anywidget/runtime.ts +11 -9
  225. package/src/plugins/impl/anywidget/widget-binding.ts +6 -6
  226. package/src/plugins/impl/image-comparison/ImageComparisonComponent.tsx +7 -6
  227. package/src/plugins/impl/matplotlib/MatplotlibPlugin.tsx +3 -3
  228. package/src/plugins/impl/matplotlib/__tests__/matplotlib-renderer.test.ts +2 -2
  229. package/src/plugins/impl/matplotlib/matplotlib-renderer.ts +2 -2
  230. package/src/plugins/impl/mpl-interactive/mpl-websocket-shim.ts +10 -10
  231. package/src/plugins/impl/panel/utils.ts +5 -5
  232. package/src/plugins/impl/plotly/PlotlyPlugin.tsx +3 -3
  233. package/src/plugins/impl/vega/VegaPlugin.tsx +3 -3
  234. package/src/plugins/impl/vega/__tests__/use-vega-container-remeasure.test.ts +7 -7
  235. package/src/plugins/impl/vega/__tests__/utils.test.ts +16 -1
  236. package/src/plugins/impl/vega/__tests__/vega.test.ts +37 -0
  237. package/src/plugins/impl/vega/loader.ts +23 -1
  238. package/src/plugins/impl/vega/utils.ts +5 -4
  239. package/src/plugins/layout/AccordionPlugin.tsx +3 -3
  240. package/src/plugins/layout/CalloutPlugin.tsx +3 -3
  241. package/src/plugins/layout/ImageComparisonPlugin.tsx +5 -3
  242. package/src/plugins/layout/JsonOutputPlugin.tsx +3 -3
  243. package/src/plugins/layout/MimeRenderPlugin.tsx +3 -3
  244. package/src/plugins/layout/NavigationMenuPlugin.tsx +3 -3
  245. package/src/plugins/layout/OutlinePlugin.tsx +3 -3
  246. package/src/plugins/layout/ProgressPlugin.tsx +3 -3
  247. package/src/plugins/layout/RoutesPlugin.tsx +6 -8
  248. package/src/plugins/layout/StatPlugin.tsx +3 -3
  249. package/src/plugins/layout/TexPlugin.tsx +3 -3
  250. package/src/plugins/layout/carousel/CarouselPlugin.tsx +4 -4
  251. package/src/plugins/layout/mermaid/MermaidPlugin.tsx +3 -3
  252. package/src/utils/Deferred.ts +6 -6
  253. package/src/utils/async-capture-tracker.ts +10 -7
  254. package/src/utils/errors.ts +5 -5
  255. package/src/utils/id-tree.tsx +83 -80
  256. package/src/utils/lru.ts +1 -1
  257. package/src/utils/multi-map.ts +14 -12
  258. package/src/utils/paths.ts +6 -6
  259. package/src/utils/pluralize.ts +3 -3
  260. package/src/utils/progress.ts +6 -6
  261. package/src/utils/python-poet/poet.ts +14 -14
  262. package/src/utils/routes.ts +4 -2
  263. package/src/utils/semaphore.ts +6 -6
  264. package/src/utils/storage/storage.ts +6 -6
  265. package/src/utils/storage/typed.ts +16 -12
  266. package/src/utils/time.ts +9 -9
  267. package/src/utils/timed-cache.ts +4 -4
  268. package/src/utils/tracer.ts +9 -6
  269. package/dist/classDiagram-ZZMXUADV-Fe-V14Sc.js +0 -30
  270. package/dist/classDiagram-v2-VYDZK3BY-xTDg7lOs.js +0 -30
  271. package/dist/flowDiagram-HODETNUW-6dMdB8pR.js +0 -16
  272. package/dist/katex-DFBiSucW.js +0 -21840
  273. package/dist/stateDiagram-v2-MP3YSRHH-o05_rJN8.js +0 -30
  274. package/dist/swimlanesDiagram-VR7AAH4N-D_nFQfRc.js +0 -30
@@ -64,11 +64,11 @@ export class Model<T extends ModelState> implements AnyModel<T> {
64
64
  * (`widget_manager.get_model`). Assigned by the registry module at
65
65
  * import time to avoid an import cycle.
66
66
  */
67
- static _modelManager: {
67
+ public static _modelManager: {
68
68
  getModel(model_id: WidgetModelId): Promise<Model<any>>;
69
69
  };
70
70
 
71
- constructor(data: T, comm: MarimoComm<T>, signal?: AbortSignal) {
71
+ public constructor(data: T, comm: MarimoComm<T>, signal?: AbortSignal) {
72
72
  this.#data = data;
73
73
  this.#comm = comm;
74
74
  this.#dirtyFields = new Set();
@@ -84,7 +84,7 @@ export class Model<T extends ModelState> implements AnyModel<T> {
84
84
  * Internal marimo API - not part of AnyWidget AFM.
85
85
  * Access via getMarimoInternal().
86
86
  */
87
- [marimoSymbol]: MarimoInternalApi<T> = {
87
+ public [marimoSymbol]: MarimoInternalApi<T> = {
88
88
  updateAndEmitDiffs: (value: T) => this.#updateAndEmitDiffs(value),
89
89
  emitCustomMessage: (
90
90
  message: CustomMessage,
@@ -92,7 +92,7 @@ export class Model<T extends ModelState> implements AnyModel<T> {
92
92
  ) => this.#emitCustomMessage(message, buffers),
93
93
  };
94
94
 
95
- off(eventName?: string | null, callback?: EventHandler | null): void {
95
+ public off(eventName?: string | null, callback?: EventHandler | null): void {
96
96
  if (!eventName) {
97
97
  this.#listeners = {};
98
98
  return;
@@ -106,7 +106,7 @@ export class Model<T extends ModelState> implements AnyModel<T> {
106
106
  this.#listeners[eventName]?.delete(callback);
107
107
  }
108
108
 
109
- send(
109
+ public send(
110
110
  content: any,
111
111
  callbacks?: any,
112
112
  buffers?: ArrayBuffer[] | ArrayBufferView[],
@@ -121,7 +121,7 @@ export class Model<T extends ModelState> implements AnyModel<T> {
121
121
  .then(() => callbacks?.());
122
122
  }
123
123
 
124
- widget_manager = {
124
+ public widget_manager = {
125
125
  async get_model<TT extends ModelState>(
126
126
  model_id: WidgetModelId,
127
127
  ): Promise<AnyModel<TT>> {
@@ -135,18 +135,18 @@ export class Model<T extends ModelState> implements AnyModel<T> {
135
135
  },
136
136
  };
137
137
 
138
- get<K extends keyof T>(key: K): T[K] {
138
+ public get<K extends keyof T>(key: K): T[K] {
139
139
  return this.#data[key];
140
140
  }
141
141
 
142
- set<K extends keyof T>(key: K, value: T[K]): void {
142
+ public set<K extends keyof T>(key: K, value: T[K]): void {
143
143
  this.#data = { ...this.#data, [key]: value };
144
144
  this.#dirtyFields.add(key);
145
145
  this.#emit(`change:${key as K & string}`, value);
146
146
  this.#emitAnyChange();
147
147
  }
148
148
 
149
- save_changes(): void {
149
+ public save_changes(): void {
150
150
  if (this.#dirtyFields.size === 0) {
151
151
  return;
152
152
  }
@@ -169,7 +169,7 @@ export class Model<T extends ModelState> implements AnyModel<T> {
169
169
  * `addEventListener({ signal })`) and is what `modelProxy` uses to
170
170
  * scope listeners to view / binding lifetimes.
171
171
  */
172
- on(
172
+ public on(
173
173
  eventName: string,
174
174
  callback: EventHandler,
175
175
  options?: { signal?: AbortSignal },
@@ -41,7 +41,10 @@ export class WidgetRegistry implements WidgetResolver {
41
41
  #timeout: number;
42
42
  #isEditMode: () => boolean;
43
43
 
44
- constructor(timeout = 10_000, isEditMode: () => boolean = defaultIsEditMode) {
44
+ public constructor(
45
+ timeout = 10_000,
46
+ isEditMode: () => boolean = defaultIsEditMode,
47
+ ) {
45
48
  this.#timeout = timeout;
46
49
  this.#isEditMode = isEditMode;
47
50
  }
@@ -71,7 +74,7 @@ export class WidgetRegistry implements WidgetResolver {
71
74
  * hasn't arrived yet. Rejects after the registry timeout so a ref to
72
75
  * a model that never opens fails loudly instead of hanging.
73
76
  */
74
- getModel(key: WidgetModelId): Promise<Model<ModelState>> {
77
+ public getModel(key: WidgetModelId): Promise<Model<ModelState>> {
75
78
  return this.#getOrCreateRuntime(key).getModel();
76
79
  }
77
80
 
@@ -79,7 +82,7 @@ export class WidgetRegistry implements WidgetResolver {
79
82
  * Get a model synchronously if it exists and has been resolved.
80
83
  * Returns undefined if the model doesn't exist or is still pending.
81
84
  */
82
- getModelSync(key: WidgetModelId): Model<ModelState> | undefined {
85
+ public getModelSync(key: WidgetModelId): Model<ModelState> | undefined {
83
86
  return this.#runtimes.get(key)?.getModelSync();
84
87
  }
85
88
 
@@ -87,14 +90,14 @@ export class WidgetRegistry implements WidgetResolver {
87
90
  * Create a model with a managed lifecycle signal.
88
91
  * The signal is aborted when the entry is deleted.
89
92
  */
90
- createModel(
93
+ public createModel(
91
94
  key: WidgetModelId,
92
95
  factory: (signal: AbortSignal) => Model<ModelState>,
93
96
  ): void {
94
97
  this.#getOrCreateRuntime(key).createModel(factory);
95
98
  }
96
99
 
97
- setModel(key: WidgetModelId, model: Model<ModelState>): void {
100
+ public setModel(key: WidgetModelId, model: Model<ModelState>): void {
98
101
  this.#getOrCreateRuntime(key).setModel(model);
99
102
  }
100
103
 
@@ -105,15 +108,15 @@ export class WidgetRegistry implements WidgetResolver {
105
108
  * Specs only come from kernel-authored notifications; model state
106
109
  * must never be treated as code (it is client-writable).
107
110
  */
108
- setSpec(key: WidgetModelId, spec: EsmSpec): void {
111
+ public setSpec(key: WidgetModelId, spec: EsmSpec): void {
109
112
  this.#getOrCreateRuntime(key).setSpec(spec);
110
113
  }
111
114
 
112
- getWidget<T = unknown>(key: WidgetModelId) {
115
+ public getWidget<T = unknown>(key: WidgetModelId) {
113
116
  return this.#getOrCreateRuntime(key).getWidget<T>();
114
117
  }
115
118
 
116
- createView(options: {
119
+ public createView(options: {
117
120
  modelId: WidgetModelId;
118
121
  el: HTMLElement;
119
122
  signal: AbortSignal;
@@ -125,7 +128,7 @@ export class WidgetRegistry implements WidgetResolver {
125
128
  * Tear down everything known about `key`: the model's lifecycle
126
129
  * signal and the current generation.
127
130
  */
128
- delete(key: WidgetModelId): void {
131
+ public delete(key: WidgetModelId): void {
129
132
  const runtime = this.#runtimes.get(key);
130
133
  if (!runtime) {
131
134
  return;
@@ -60,7 +60,7 @@ export class WidgetRuntime {
60
60
  #generationCleanup = Promise.resolve();
61
61
  #css = "";
62
62
 
63
- constructor(key: WidgetModelId, options: WidgetRuntimeOptions) {
63
+ public constructor(key: WidgetModelId, options: WidgetRuntimeOptions) {
64
64
  this.#key = key;
65
65
  this.#timeout = options.timeout;
66
66
  this.#isEditMode = options.isEditMode;
@@ -68,7 +68,7 @@ export class WidgetRuntime {
68
68
  this.#onModelTimeout = options.onModelTimeout;
69
69
  }
70
70
 
71
- getModel(): Promise<Model<ModelState>> {
71
+ public getModel(): Promise<Model<ModelState>> {
72
72
  if (this.#model.status === "pending" && !this.#modelTimeout) {
73
73
  this.#modelTimeout = setTimeout(() => {
74
74
  if (this.#model.status === "pending") {
@@ -83,18 +83,20 @@ export class WidgetRuntime {
83
83
  return this.#model.promise;
84
84
  }
85
85
 
86
- getModelSync(): Model<ModelState> | undefined {
86
+ public getModelSync(): Model<ModelState> | undefined {
87
87
  return this.#model.status === "resolved" ? this.#model.value : undefined;
88
88
  }
89
89
 
90
- createModel(factory: (signal: AbortSignal) => Model<ModelState>): void {
90
+ public createModel(
91
+ factory: (signal: AbortSignal) => Model<ModelState>,
92
+ ): void {
91
93
  if (this.#model.status !== "pending") {
92
94
  return;
93
95
  }
94
96
  this.#resolveModel(factory(this.#controller.signal));
95
97
  }
96
98
 
97
- setModel(model: Model<ModelState>): void {
99
+ public setModel(model: Model<ModelState>): void {
98
100
  if (this.#model.status !== "pending") {
99
101
  return;
100
102
  }
@@ -121,7 +123,7 @@ export class WidgetRuntime {
121
123
  );
122
124
  }
123
125
 
124
- setSpec(spec: EsmSpec): void {
126
+ public setSpec(spec: EsmSpec): void {
125
127
  if (!this.#esmSpec) {
126
128
  this.#esmSpec = spec;
127
129
  return;
@@ -138,7 +140,7 @@ export class WidgetRuntime {
138
140
  }
139
141
  }
140
142
 
141
- async getWidget<T = unknown>(): Promise<ResolvedWidget<T>> {
143
+ public async getWidget<T = unknown>(): Promise<ResolvedWidget<T>> {
142
144
  const binding = await this.#getCurrentBinding();
143
145
  return {
144
146
  exports: binding.exports as T,
@@ -151,7 +153,7 @@ export class WidgetRuntime {
151
153
  };
152
154
  }
153
155
 
154
- async createView(options: {
156
+ public async createView(options: {
155
157
  el: HTMLElement;
156
158
  signal: AbortSignal;
157
159
  }): Promise<void> {
@@ -341,7 +343,7 @@ export class WidgetRuntime {
341
343
  view.signal.addEventListener("abort", release, { once: true });
342
344
  }
343
345
 
344
- dispose(): void {
346
+ public dispose(): void {
345
347
  if (this.#controller.signal.aborted) {
346
348
  return;
347
349
  }
@@ -59,7 +59,7 @@ class WidgetDefRegistry {
59
59
  * `kernelAuthored: true` only for URLs from an `EsmSpec`; it widens
60
60
  * the import gate to remote and data URLs.
61
61
  */
62
- getModule(options: {
62
+ public getModule(options: {
63
63
  jsUrl: string;
64
64
  jsHash: string;
65
65
  kernelAuthored?: boolean;
@@ -80,7 +80,7 @@ class WidgetDefRegistry {
80
80
  return promise;
81
81
  }
82
82
 
83
- invalidate(jsHash: string): void {
83
+ public invalidate(jsHash: string): void {
84
84
  this.#cache.delete(jsHash);
85
85
  }
86
86
 
@@ -180,7 +180,7 @@ export class WidgetBinding<T extends ModelState = ModelState> {
180
180
  * `controller`'s signal. Aborting the controller mid-initialize
181
181
  * still runs any legacy cleanup callback, and `create` rejects.
182
182
  */
183
- static async create<T extends ModelState>({
183
+ public static async create<T extends ModelState>({
184
184
  widgetDef,
185
185
  model,
186
186
  createHost,
@@ -261,7 +261,7 @@ export class WidgetBinding<T extends ModelState = ModelState> {
261
261
  * The object returned from `initialize`, or `undefined` if it
262
262
  * returned a cleanup function or nothing.
263
263
  */
264
- get exports(): unknown {
264
+ public get exports(): unknown {
265
265
  return this.#exports;
266
266
  }
267
267
 
@@ -273,7 +273,7 @@ export class WidgetBinding<T extends ModelState = ModelState> {
273
273
  * `render` reads current state via `model.get`; change listeners
274
274
  * observe only subsequent changes, matching Jupyter semantics.
275
275
  */
276
- async createView(
276
+ public async createView(
277
277
  target: { el: HTMLElement },
278
278
  options: { signal: AbortSignal },
279
279
  ): Promise<void> {
@@ -346,7 +346,7 @@ export class WidgetBinding<T extends ModelState = ModelState> {
346
346
  * Destroy this generation, running initialize/render cleanups and
347
347
  * clearing listeners registered through its model proxies.
348
348
  */
349
- async destroy(): Promise<void> {
349
+ public async destroy(): Promise<void> {
350
350
  Logger.debug("[WidgetBinding] Destroying binding generation");
351
351
  this.#controller.abort();
352
352
  await Promise.allSettled(this.#viewTasks);
@@ -19,7 +19,7 @@ function truncateSrc(src: string): string {
19
19
  return src.length > MAX_LENGTH ? `${src.slice(0, MAX_LENGTH)}…` : src;
20
20
  }
21
21
 
22
- const ImageComparisonComponent: React.FC<ImageComparisonData> = ({
22
+ const ImageComparisonContent: React.FC<ImageComparisonData> = ({
23
23
  beforeSrc,
24
24
  afterSrc,
25
25
  value,
@@ -31,12 +31,8 @@ const ImageComparisonComponent: React.FC<ImageComparisonData> = ({
31
31
  () => new Set(),
32
32
  );
33
33
 
34
- React.useEffect(() => {
35
- setFailedSrcs(new Set());
36
- }, [beforeSrc, afterSrc]);
37
-
38
34
  const handleError = React.useCallback((src: string) => {
39
- setFailedSrcs((prev) => new Set(prev).add(src));
35
+ setFailedSrcs((previous) => new Set(previous).add(src));
40
36
  }, []);
41
37
 
42
38
  const containerStyle: React.CSSProperties = {
@@ -106,4 +102,9 @@ const ImageComparisonComponent: React.FC<ImageComparisonData> = ({
106
102
  );
107
103
  };
108
104
 
105
+ const ImageComparisonComponent: React.FC<ImageComparisonData> = (props) => {
106
+ const sourceKey = JSON.stringify([props.beforeSrc, props.afterSrc]);
107
+ return <ImageComparisonContent key={sourceKey} {...props} />;
108
+ };
109
+
109
110
  export default ImageComparisonComponent;
@@ -11,9 +11,9 @@ import {
11
11
  } from "./matplotlib-renderer";
12
12
 
13
13
  export class MatplotlibPlugin implements IPlugin<T, Data> {
14
- tagName = "marimo-matplotlib";
14
+ public tagName = "marimo-matplotlib";
15
15
 
16
- validator = z.object({
16
+ public validator = z.object({
17
17
  chartBase64: z.string(),
18
18
  xBounds: z.tuple([z.number(), z.number()]),
19
19
  yBounds: z.tuple([z.number(), z.number()]),
@@ -28,7 +28,7 @@ export class MatplotlibPlugin implements IPlugin<T, Data> {
28
28
  yScale: z.enum(["linear", "log"]).default("linear"),
29
29
  });
30
30
 
31
- render(props: IPluginProps<T, Data>): JSX.Element {
31
+ public render(props: IPluginProps<T, Data>): JSX.Element {
32
32
  return (
33
33
  <MatplotlibComponent
34
34
  {...props.data}
@@ -228,8 +228,8 @@ function stubSyncImage() {
228
228
  vi.stubGlobal(
229
229
  "Image",
230
230
  class {
231
- onload: (() => void) | null = null;
232
- set src(_value: string) {
231
+ public onload: (() => void) | null = null;
232
+ public set src(_value: string) {
233
233
  this.onload?.();
234
234
  }
235
235
  },
@@ -284,7 +284,7 @@ export class MatplotlibRenderer {
284
284
  /** The devicePixelRatio the canvas buffer was last sized with. */
285
285
  #backingDpr = 1;
286
286
 
287
- constructor(
287
+ public constructor(
288
288
  container: HTMLDivElement,
289
289
  options: { state: MatplotlibState; signal: AbortSignal },
290
290
  ) {
@@ -396,7 +396,7 @@ export class MatplotlibRenderer {
396
396
  mq.addEventListener("change", onChange, { once: true, signal });
397
397
  }
398
398
 
399
- update(state: MatplotlibState): void {
399
+ public update(state: MatplotlibState): void {
400
400
  const prev = this.#state;
401
401
  this.#state = state;
402
402
 
@@ -10,14 +10,14 @@
10
10
  * - onopen / onmessage / onclose callbacks
11
11
  */
12
12
  export class MplCommWebSocket {
13
- readyState: number = WebSocket.OPEN;
13
+ public readyState: number = WebSocket.OPEN;
14
14
  private sendFn: (msg: unknown) => void;
15
15
 
16
- onopen: (() => void) | null = null;
17
- onmessage: ((evt: MessageEvent) => void) | null = null;
18
- onclose: (() => void) | null = null;
16
+ public onopen: (() => void) | null = null;
17
+ public onmessage: ((evt: MessageEvent) => void) | null = null;
18
+ public onclose: (() => void) | null = null;
19
19
 
20
- constructor(sendFn: (msg: unknown) => void) {
20
+ public constructor(sendFn: (msg: unknown) => void) {
21
21
  this.sendFn = sendFn;
22
22
  }
23
23
 
@@ -27,7 +27,7 @@ export class MplCommWebSocket {
27
27
  * socket instance stays bound to mpl.js (which wires `onopen`/`onmessage`
28
28
  * onto it at construction); only the comm behind it changes.
29
29
  */
30
- setSendHandler(sendFn: (msg: unknown) => void): void {
30
+ public setSendHandler(sendFn: (msg: unknown) => void): void {
31
31
  this.sendFn = sendFn;
32
32
  }
33
33
 
@@ -35,14 +35,14 @@ export class MplCommWebSocket {
35
35
  * Called by mpl.js to send a message to the backend.
36
36
  * mpl.js always sends JSON strings.
37
37
  */
38
- send(data: string): void {
38
+ public send(data: string): void {
39
39
  this.sendFn(JSON.parse(data));
40
40
  }
41
41
 
42
42
  /**
43
43
  * Called when the backend pushes a JSON message via the model custom event.
44
44
  */
45
- receiveJson(data: unknown): void {
45
+ public receiveJson(data: unknown): void {
46
46
  this.onmessage?.(
47
47
  new MessageEvent("message", { data: JSON.stringify(data) }),
48
48
  );
@@ -51,7 +51,7 @@ export class MplCommWebSocket {
51
51
  /**
52
52
  * Called when the backend pushes binary data (PNG render) via model custom event.
53
53
  */
54
- receiveBinary(buffer: DataView): void {
54
+ public receiveBinary(buffer: DataView): void {
55
55
  const ab = buffer.buffer.slice(
56
56
  buffer.byteOffset,
57
57
  buffer.byteOffset + buffer.byteLength,
@@ -60,7 +60,7 @@ export class MplCommWebSocket {
60
60
  this.onmessage?.(new MessageEvent("message", { data: blob }));
61
61
  }
62
62
 
63
- close(): void {
63
+ public close(): void {
64
64
  this.readyState = WebSocket.CLOSED;
65
65
  this.onclose?.();
66
66
  }
@@ -60,12 +60,12 @@ export class EventBuffer<T> {
60
60
  private processEvents: () => void;
61
61
  private blockDuration: number;
62
62
 
63
- constructor(processEvents: () => void, blockDuration = 200) {
63
+ public constructor(processEvents: () => void, blockDuration = 200) {
64
64
  this.processEvents = processEvents;
65
65
  this.blockDuration = blockDuration;
66
66
  }
67
67
 
68
- add(event: T) {
68
+ public add(event: T) {
69
69
  this.buffer.push(event);
70
70
  this.flush();
71
71
  }
@@ -90,15 +90,15 @@ export class EventBuffer<T> {
90
90
  }, this.blockDuration);
91
91
  }
92
92
 
93
- size() {
93
+ public size() {
94
94
  return this.buffer.length;
95
95
  }
96
96
 
97
- clear() {
97
+ public clear() {
98
98
  this.buffer = [];
99
99
  }
100
100
 
101
- getAndClear() {
101
+ public getAndClear() {
102
102
  const events = this.buffer;
103
103
  this.buffer = [];
104
104
  return events;
@@ -55,9 +55,9 @@ type T =
55
55
  | undefined;
56
56
 
57
57
  export class PlotlyPlugin implements IPlugin<T, Data> {
58
- tagName = "marimo-plotly";
58
+ public tagName = "marimo-plotly";
59
59
 
60
- validator = z.object({
60
+ public validator = z.object({
61
61
  figure: z
62
62
  .object({})
63
63
  .passthrough()
@@ -65,7 +65,7 @@ export class PlotlyPlugin implements IPlugin<T, Data> {
65
65
  config: z.object({}).passthrough(),
66
66
  });
67
67
 
68
- render(props: IPluginProps<T, Data>): JSX.Element {
68
+ public render(props: IPluginProps<T, Data>): JSX.Element {
69
69
  return (
70
70
  <PlotlyComponent
71
71
  {...props.data}
@@ -12,9 +12,9 @@ import React, { type JSX } from "react";
12
12
  const LazyVegaComponent = React.lazy(() => import("./vega-component"));
13
13
 
14
14
  export class VegaPlugin implements IPlugin<VegaComponentState, Data> {
15
- tagName = "marimo-vega";
15
+ public tagName = "marimo-vega";
16
16
 
17
- validator = z.object({
17
+ public validator = z.object({
18
18
  spec: z
19
19
  .object({})
20
20
  .passthrough()
@@ -26,7 +26,7 @@ export class VegaPlugin implements IPlugin<VegaComponentState, Data> {
26
26
  embedOptions: z.object({}).passthrough().default({}),
27
27
  });
28
28
 
29
- render(props: IPluginProps<VegaComponentState, Data>): JSX.Element {
29
+ public render(props: IPluginProps<VegaComponentState, Data>): JSX.Element {
30
30
  return (
31
31
  <LazyVegaComponent
32
32
  value={props.value}
@@ -10,27 +10,27 @@ describe("useVegaContainerRemeasure", () => {
10
10
  let OriginalResizeObserver: typeof ResizeObserver;
11
11
 
12
12
  class FakeResizeObserver {
13
- callback: ResizeObserverCallback;
14
- el: Element | null = null;
13
+ public callback: ResizeObserverCallback;
14
+ public el: Element | null = null;
15
15
 
16
- constructor(callback: ResizeObserverCallback) {
16
+ public constructor(callback: ResizeObserverCallback) {
17
17
  this.callback = callback;
18
18
  observers.push(this);
19
19
  }
20
20
 
21
- observe(el: Element) {
21
+ public observe(el: Element) {
22
22
  this.el = el;
23
23
  }
24
24
 
25
- disconnect() {
25
+ public disconnect() {
26
26
  this.el = null;
27
27
  }
28
28
 
29
- unobserve() {
29
+ public unobserve() {
30
30
  this.el = null;
31
31
  }
32
32
 
33
- trigger(width: number) {
33
+ public trigger(width: number) {
34
34
  this.callback(
35
35
  [
36
36
  {
@@ -1,7 +1,22 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
3
  import { describe, expect, it } from "vitest";
4
- import { getContainerWidth } from "../utils";
4
+ import { getContainerWidth, getVegaFieldTypes } from "../utils";
5
+
6
+ describe("getVegaFieldTypes", () => {
7
+ it("preserves date strings unless the caller requests date parsing", () => {
8
+ expect(getVegaFieldTypes({ day: "date", timestamp: "datetime" })).toEqual({
9
+ day: "string",
10
+ timestamp: "date",
11
+ });
12
+ expect(
13
+ getVegaFieldTypes(
14
+ { day: "date", timestamp: "datetime" },
15
+ { parseDates: true },
16
+ ),
17
+ ).toEqual({ day: "date", timestamp: "date" });
18
+ });
19
+ });
5
20
 
6
21
  describe("getContainerWidth", () => {
7
22
  it('should return "container" when spec width is "container"', () => {
@@ -13,6 +13,43 @@ const { ZERO_WIDTH_SPACE, replacePeriodsInColumnNames, uniquifyColumnNames } =
13
13
  exportedForTesting;
14
14
 
15
15
  describe("vega loader", () => {
16
+ it("parses infinities only in explicitly numeric CSV fields", async () => {
17
+ vi.spyOn(vegaLoader, "load").mockResolvedValue(
18
+ "value,label,id\ninf,inf,1\n-inf,-inf,2\n+inf,+inf,3\n2.5,002.5,4\n,,5\nNaN,NaN,6\n",
19
+ );
20
+
21
+ const data = await vegaLoadData("chart.csv", {
22
+ type: "csv",
23
+ parse: { value: "number", label: "string", id: "integer" },
24
+ });
25
+
26
+ expect(data).toEqual([
27
+ { value: Infinity, label: "inf", id: 1 },
28
+ { value: -Infinity, label: "-inf", id: 2 },
29
+ { value: Infinity, label: "+inf", id: 3 },
30
+ { value: 2.5, label: "002.5", id: 4 },
31
+ { value: null, label: null, id: 5 },
32
+ { value: Number.NaN, label: "NaN", id: 6 },
33
+ ]);
34
+ });
35
+
36
+ it("preserves the table's large integer and infinity handling", async () => {
37
+ vi.spyOn(vegaLoader, "load").mockResolvedValue(
38
+ "id,value\n9007199254740993,inf\n9007199254740995,-inf\n",
39
+ );
40
+
41
+ const data = await vegaLoadData(
42
+ "table.csv",
43
+ { type: "csv", parse: { id: "integer", value: "number" } },
44
+ { handleBigIntAndNumberLike: true },
45
+ );
46
+
47
+ expect(data).toEqual([
48
+ { id: BigInt("9007199254740993"), value: "inf" },
49
+ { id: BigInt("9007199254740995"), value: "-inf" },
50
+ ]);
51
+ });
52
+
16
53
  it("should parse csv data with dates", async () => {
17
54
  const csvData = `
18
55
  active,username,id
@@ -16,6 +16,26 @@ const previousNumberParser = typeParsers.number;
16
16
  const previousDateParser = typeParsers.date;
17
17
  const previousBooleanParser = typeParsers.boolean;
18
18
 
19
+ const NUMBER_MIDDLEWARE: Middleware = () => {
20
+ const parseNumber = (value: string) => {
21
+ if (value === "inf" || value === "+inf") {
22
+ return Number.POSITIVE_INFINITY;
23
+ }
24
+ if (value === "-inf") {
25
+ return Number.NEGATIVE_INFINITY;
26
+ }
27
+ return previousNumberParser(value);
28
+ };
29
+
30
+ typeParsers.integer = parseNumber;
31
+ typeParsers.number = parseNumber;
32
+
33
+ return () => {
34
+ typeParsers.integer = previousIntegerParser;
35
+ typeParsers.number = previousNumberParser;
36
+ };
37
+ };
38
+
19
39
  const BIG_INT_MIDDLEWARE: Middleware = () => {
20
40
  // Custom parser to:
21
41
  // - handle BigInt
@@ -159,6 +179,8 @@ export async function vegaLoadData<T = object>(
159
179
  const middleware: Middleware[] = [DATE_MIDDLEWARE];
160
180
  if (handleBigIntAndNumberLike) {
161
181
  middleware.push(BIG_INT_MIDDLEWARE);
182
+ } else {
183
+ middleware.push(NUMBER_MIDDLEWARE);
162
184
  }
163
185
 
164
186
  let unsubscribes: Unsubscribe[] = [];
@@ -216,7 +238,7 @@ export async function vegaLoadData<T = object>(
216
238
 
217
239
  // Apply middleware
218
240
  unsubscribes = middleware.map((m) => m());
219
- // Always set parse to auto for csv data, to be able to parse dates and floats
241
+ // CSV defaults to inference when no explicit column types are available.
220
242
  const results = isCsv
221
243
  ? // csv -> json
222
244
  read(csvOrJsonData, {