@marimo-team/frontend 0.15.5 → 0.16.0-dev96986

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 (325) hide show
  1. package/dist/assets/ConnectedDataExplorerComponent-CNLoZkWr.js +19 -0
  2. package/dist/assets/{ImageComparisonComponent-CEXMKKA4.js → ImageComparisonComponent-SX7fDaTK.js} +1 -1
  3. package/dist/assets/{VegaLite-Bt14Ds9k.js → VegaLite-MJUW3b7C.js} +6 -6
  4. package/dist/assets/_baseEach-9_logFrf.js +1 -0
  5. package/dist/assets/_baseMap-NzEbKt5c.js +1 -0
  6. package/dist/assets/_baseUniq-C5LFcyNC.js +1 -0
  7. package/dist/assets/_createAggregator-ZRm2b6Zm.js +1 -0
  8. package/dist/assets/agent-panel-BBd11wNX.js +287 -0
  9. package/dist/assets/agent-panel-D92Mfy1i.css +1 -0
  10. package/dist/assets/{any-language-editor-DiwNT6zp.js → any-language-editor-DwAaEQfS.js} +1 -1
  11. package/dist/assets/architectureDiagram-W76B3OCA-BJmVXUoW.js +36 -0
  12. package/dist/assets/{between-horizontal-start-FyewyCGn.js → between-horizontal-start-KiwU-a3C.js} +1 -1
  13. package/dist/assets/{blockDiagram-QIGZ2CNN-BrOkAf_c.js → blockDiagram-QIGZ2CNN-DzxZjE7B.js} +1 -1
  14. package/dist/assets/{c4Diagram-FPNF74CW-BHPzDxE2.js → c4Diagram-FPNF74CW-DjmldG_J.js} +5 -5
  15. package/dist/assets/channel-DHcKBVM4.js +1 -0
  16. package/dist/assets/chat-panel-DgJZr0eS.js +3 -0
  17. package/dist/assets/{chunk-4BX2VUAB-DLxaCNYh.js → chunk-4BX2VUAB-EUTQThiZ.js} +1 -1
  18. package/dist/assets/{chunk-55IACEB6-DdzvO3HR.js → chunk-55IACEB6-DZAiDJxy.js} +1 -1
  19. package/dist/assets/{chunk-FMBD7UC4-R5o-nSiG.js → chunk-FMBD7UC4-Bd0Czs-J.js} +1 -1
  20. package/dist/assets/{chunk-K7UQS3LO-DxaMrGgG.js → chunk-K7UQS3LO-DEKMIknX.js} +1 -1
  21. package/dist/assets/{chunk-QN33PNHL-DqS9-FYm.js → chunk-QN33PNHL-E0jwHU_n.js} +1 -1
  22. package/dist/assets/{chunk-QZHKN3VN-BZ-TzajS.js → chunk-QZHKN3VN-BzaIHJbq.js} +1 -1
  23. package/dist/assets/{chunk-TVAH2DTR-BsgP2dyv.js → chunk-TVAH2DTR-CZFYvqnm.js} +1 -1
  24. package/dist/assets/{chunk-TZMSLE5B-D-h3ahXI.js → chunk-TZMSLE5B-BNqnFjtv.js} +1 -1
  25. package/dist/assets/{circle-play-CQtRZ-rT.js → circle-play-D3J_mYrF.js} +1 -1
  26. package/dist/assets/classDiagram-KNZD7YFC-D-xwLnlX.js +1 -0
  27. package/dist/assets/classDiagram-v2-RKCZMP56-D-xwLnlX.js +1 -0
  28. package/dist/assets/{clear-button-BY6Z_ViL.js → clear-button-ifzRuAR3.js} +1 -1
  29. package/dist/assets/clone-CSxIll62.js +1 -0
  30. package/dist/assets/command-palette-D2fdVSET.js +1 -0
  31. package/dist/assets/common-Ku-cF_2J.js +1 -0
  32. package/dist/assets/{compile-Ct_jzdKr.js → compile-BgZlHW1c.js} +1 -1
  33. package/dist/assets/cose-bilkent-S5V4N54A-CVM83SqK.js +1 -0
  34. package/dist/assets/dagre-5GWH7T2D-ouQPkxT3.js +4 -0
  35. package/dist/assets/{data-grid-overlay-editor-BN_wulc3.js → data-grid-overlay-editor-B47j5GJJ.js} +1 -1
  36. package/dist/assets/datasources-panel-Bt41Zir-.js +1 -0
  37. package/dist/assets/{dependency-graph-panel-BOmSCZf7.js → dependency-graph-panel-CZC_B7pK.js} +4 -4
  38. package/dist/assets/diagram-N5W7TBWH-CQ817ZdR.js +24 -0
  39. package/dist/assets/diagram-QEK2KX5R-DOK_psUO.js +43 -0
  40. package/dist/assets/diagram-S2PKOQOG-CVljmOW8.js +24 -0
  41. package/dist/assets/{documentation-panel-BxjJO_Gw.js → documentation-panel-C7yIvGg1.js} +1 -1
  42. package/dist/assets/edit-page-CyTMQV2u.js +129 -0
  43. package/dist/assets/{ellipsis-vertical-UHbmjI2n.js → ellipsis-vertical-C7FjlUsY.js} +1 -1
  44. package/dist/assets/{empty-state-BIBXzY_0.js → empty-state-DIOGM_CU.js} +1 -1
  45. package/dist/assets/{erDiagram-AWTI2OKA-E84mAle_.js → erDiagram-AWTI2OKA-DYu8cEdc.js} +1 -1
  46. package/dist/assets/{error-panel-MEvQ6K7h.js → error-panel-Ddb8RkFG.js} +1 -1
  47. package/dist/assets/file-explorer-panel-Oy9DbyFP.js +1 -0
  48. package/dist/assets/{flowDiagram-PVAE7QVJ-DfbIRSAW.js → flowDiagram-PVAE7QVJ-CmvW5iTb.js} +1 -1
  49. package/dist/assets/{ganttDiagram-OWAHRB6G-DR4HZ1z_.js → ganttDiagram-OWAHRB6G-BaKQlCaT.js} +4 -4
  50. package/dist/assets/gitGraphDiagram-NY62KEGX-CWO24eP6.js +65 -0
  51. package/dist/assets/{glide-data-editor-nNmo1lPq.js → glide-data-editor-CNDLEJ9a.js} +11 -11
  52. package/dist/assets/graph-BZKTtxsc.js +1 -0
  53. package/dist/assets/home-page-Bvwppn9N.js +9 -0
  54. package/dist/assets/{index-VPWqq2Pg.js → index-0XOUPdwT.js} +1 -1
  55. package/dist/assets/{index-uacyUula.js → index-BH7f3aiU.js} +1 -1
  56. package/dist/assets/{index-Dt9UWeWn.js → index-BJVyzkx5.js} +1 -1
  57. package/dist/assets/{index-BAH034Ue.js → index-B_d_JZGI.js} +1 -1
  58. package/dist/assets/{index-CB2pnVQG.js → index-BgXbBA39.js} +1 -1
  59. package/dist/assets/{index-B8llrTSo.js → index-Brf2DwUM.js} +1 -1
  60. package/dist/assets/{index-BLu5CX6z.js → index-CXrWwFX6.js} +1 -1
  61. package/dist/assets/{index-DyLSuOH1.js → index-CZaurnA9.js} +1 -1
  62. package/dist/assets/{index-BFSnz7iM.js → index-CerjupfZ.js} +1 -1
  63. package/dist/assets/{index-B7yXbrLa.js → index-D-tZfElD.js} +1 -1
  64. package/dist/assets/{index-c6If577Q.js → index-D3PqGupX.js} +1 -1
  65. package/dist/assets/{index-CSgxTUzD.js → index-DCkzth56.js} +1 -1
  66. package/dist/assets/{index-DWOaniGT.js → index-DFrGFNW1.js} +1 -1
  67. package/dist/assets/{index-CPN7TRA1.js → index-DZhOPkOB.js} +1 -1
  68. package/dist/assets/index-DadI618h.css +1 -0
  69. package/dist/assets/{index-DqzMPAC8.js → index-DkntzpX4.js} +2 -2
  70. package/dist/assets/{index-B1_GXGaP.js → index-DmgwT3sx.js} +1 -1
  71. package/dist/assets/index-PmY0x4Zd.js +578 -0
  72. package/dist/assets/{index-Bq516OmX.js → index-WXJFkQHg.js} +1 -1
  73. package/dist/assets/{index-DSU75csX.js → index-qE8lHQ-N.js} +1 -1
  74. package/dist/assets/{index-DMomwMcN.js → index-zrSUQXha.js} +1 -1
  75. package/dist/assets/infoDiagram-STP46IZ2-CAuVVehw.js +2 -0
  76. package/dist/assets/isEmpty-D1t7Gran.js +1 -0
  77. package/dist/assets/{journeyDiagram-BIP6EPQ6-BBiFyygf.js → journeyDiagram-BIP6EPQ6-D4Rp6H_h.js} +1 -1
  78. package/dist/assets/{kanban-definition-6OIFK2YF-DhgA6Nt6.js → kanban-definition-6OIFK2YF-DFt9DftA.js} +4 -4
  79. package/dist/assets/layout-D8WXi2_g.js +1 -0
  80. package/dist/assets/linear-BwY8e5hA.js +1 -0
  81. package/dist/assets/links-4B6ldZ5P.js +7 -0
  82. package/dist/assets/{logs-panel-B9SmTZAW.js → logs-panel-Dxiyt7dO.js} +1 -1
  83. package/dist/assets/{agent-panel-DpQ6muj-.css → markdown-renderer-ClyzDMmG.css} +1 -1
  84. package/dist/assets/markdown-renderer-VDu-NBKB.js +263 -0
  85. package/dist/assets/mermaid-B-O-Puyi.js +1 -0
  86. package/dist/assets/{mermaid.core-4nVOEVX3.js → mermaid.core-BFFCqfOn.js} +41 -41
  87. package/dist/assets/min-DtVSfYKl.js +1 -0
  88. package/dist/assets/{mindmap-definition-Q6HEUPPD-CVLQNn1q.js → mindmap-definition-Q6HEUPPD-kyvIY8Dg.js} +2 -2
  89. package/dist/assets/{number-overlay-editor-CzRzXLcd.js → number-overlay-editor-GjLB2UK4.js} +1 -1
  90. package/dist/assets/outline-panel-CMJjOoN7.js +1 -0
  91. package/dist/assets/packages-panel-nfXB-bKW.js +1 -0
  92. package/dist/assets/{pieDiagram-ADFJNKIX-C5IQ5DBZ.js → pieDiagram-ADFJNKIX-D8JFQcWR.js} +3 -3
  93. package/dist/assets/{quadrantDiagram-LMRXKWRM-CFXFnQxx.js → quadrantDiagram-LMRXKWRM-Nf8GzxXG.js} +1 -1
  94. package/dist/assets/{react-plotly-mzdv02_Y.js → react-plotly-CnW9p7ZA.js} +1 -1
  95. package/dist/assets/{requirementDiagram-4UW4RH46-D9bPC89T.js → requirementDiagram-4UW4RH46-CCUxF8BZ.js} +1 -1
  96. package/dist/assets/run-page-Bl4p3AbZ.js +1 -0
  97. package/dist/assets/sankeyDiagram-GR3RE2ED-Sr8kDwP1.js +10 -0
  98. package/dist/assets/scratchpad-panel-Ja1Mu-W3.js +1 -0
  99. package/dist/assets/secrets-panel-B-3fcSyP.js +1 -0
  100. package/dist/assets/{sequenceDiagram-C3RYC4MD-6N7_hY4k.js → sequenceDiagram-C3RYC4MD-CBJ152Q3.js} +4 -4
  101. package/dist/assets/{slides-component-DMjQomc3.css → slides-component-C-LoGC1U.css} +1 -1
  102. package/dist/assets/{slides-component-EcjC8sDK.js → slides-component-DGtsVP5o.js} +1 -1
  103. package/dist/assets/snippets-panel-ClNnwKBM.js +1 -0
  104. package/dist/assets/sortBy-D47H6Vyl.js +1 -0
  105. package/dist/assets/state-B_RCHTH5.js +1 -0
  106. package/dist/assets/stateDiagram-KXAO66HF-BlBFSAZr.js +1 -0
  107. package/dist/assets/stateDiagram-v2-UMBNRL4Z-DbA-iToo.js +1 -0
  108. package/dist/assets/storage-BNcWOH3-.js +26 -0
  109. package/dist/assets/terminal-CATzv5Hd.js +10 -0
  110. package/dist/assets/time-CsYqILfB.js +1 -0
  111. package/dist/assets/{timeline-definition-XQNQX7LJ-BEaynAiY.js → timeline-definition-XQNQX7LJ-CGrhjuAs.js} +1 -1
  112. package/dist/assets/tracing-DUbJtOyq.js +2 -0
  113. package/dist/assets/{tracing-panel-BmuHLPrY.js → tracing-panel-DmzqPUtc.js} +2 -2
  114. package/dist/assets/{trash-UBqfK4mR.js → trash-rxdjLzkf.js} +1 -1
  115. package/dist/assets/{tree-XiEycetl.js → tree-C2Ul1h1C.js} +1 -1
  116. package/dist/assets/{treemap-75Q7IDZK-CnuVFbBG.js → treemap-75Q7IDZK-N9hyUpyj.js} +20 -20
  117. package/dist/assets/{ts-tags-CloPe9IY.js → ts-tags-DxCDHihD.js} +1 -1
  118. package/dist/assets/variable-panel-BbgupOdG.js +1 -0
  119. package/dist/assets/{vega-component-DsTH4tuX.js → vega-component-CR_MHOBT.js} +1 -1
  120. package/dist/assets/worker-fHbtoWvT.js +1 -0
  121. package/dist/assets/{xychartDiagram-6GGTOJPD-Dcz3O-A3.js → xychartDiagram-6GGTOJPD-jdLZsMb2.js} +1 -1
  122. package/dist/index.html +2 -2
  123. package/package.json +10 -5
  124. package/src/__tests__/mocks.ts +43 -0
  125. package/src/components/app-config/user-config-form.tsx +78 -1
  126. package/src/components/chat/acp/__tests__/__snapshots__/prompt.test.ts.snap +116 -65
  127. package/src/components/chat/acp/__tests__/atoms.test.ts +1 -1
  128. package/src/components/chat/acp/__tests__/context-utils.test.ts +222 -0
  129. package/src/components/chat/acp/__tests__/prompt.test.ts +1 -1
  130. package/src/components/chat/acp/__tests__/state.test.ts +38 -42
  131. package/src/components/chat/acp/agent-docs.tsx +33 -6
  132. package/src/components/chat/acp/agent-panel.css +0 -18
  133. package/src/components/chat/acp/agent-panel.tsx +394 -72
  134. package/src/components/chat/acp/agent-selector.tsx +7 -1
  135. package/src/components/chat/acp/blocks.tsx +40 -10
  136. package/src/components/chat/acp/common.tsx +10 -2
  137. package/src/components/chat/acp/context-utils.ts +127 -0
  138. package/src/components/chat/acp/prompt.ts +96 -53
  139. package/src/components/chat/acp/state.ts +1 -1
  140. package/src/components/chat/acp/types.ts +8 -0
  141. package/src/components/chat/chat-panel.tsx +28 -89
  142. package/src/components/chat/chat-utils.ts +127 -1
  143. package/src/components/chat/markdown-renderer.css +39 -0
  144. package/src/components/chat/markdown-renderer.tsx +12 -47
  145. package/src/components/chat/tool-call-accordion.tsx +148 -26
  146. package/src/components/data-table/SearchBar.tsx +8 -7
  147. package/src/components/data-table/__tests__/column_formatting.test.ts +50 -35
  148. package/src/components/data-table/__tests__/data-table.test.tsx +39 -1
  149. package/src/components/data-table/cell-hover-template/feature.ts +14 -0
  150. package/src/components/data-table/cell-hover-template/types.ts +11 -0
  151. package/src/components/data-table/charts/components/form-fields.tsx +41 -37
  152. package/src/components/data-table/charts/forms/common-chart.tsx +2 -2
  153. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +5 -2
  154. package/src/components/data-table/column-formatting/feature.ts +62 -29
  155. package/src/components/data-table/column-formatting/types.ts +1 -0
  156. package/src/components/data-table/column-header.tsx +3 -1
  157. package/src/components/data-table/column-summary/chart-spec-model.tsx +24 -7
  158. package/src/components/data-table/column-summary/column-summary.tsx +18 -9
  159. package/src/components/data-table/columns.tsx +42 -18
  160. package/src/components/data-table/data-table.tsx +10 -2
  161. package/src/components/data-table/date-popover.tsx +85 -75
  162. package/src/components/data-table/filter-pills.tsx +14 -9
  163. package/src/components/data-table/header-items.tsx +5 -1
  164. package/src/components/data-table/pagination.tsx +20 -13
  165. package/src/components/data-table/renderers.tsx +28 -0
  166. package/src/components/data-table/row-viewer-panel/row-viewer.tsx +10 -8
  167. package/src/components/datasources/column-preview.tsx +6 -2
  168. package/src/components/datasources/datasources.tsx +8 -12
  169. package/src/components/editor/Cell.tsx +6 -0
  170. package/src/components/editor/actions/name-cell-input.tsx +6 -1
  171. package/src/components/editor/actions/useCellActionButton.tsx +3 -1
  172. package/src/components/editor/ai/__tests__/completion-utils.test.ts +178 -1
  173. package/src/components/editor/ai/add-cell-with-ai.tsx +68 -66
  174. package/src/components/editor/ai/ai-completion-editor.tsx +29 -26
  175. package/src/components/editor/ai/completion-handlers.tsx +44 -6
  176. package/src/components/editor/ai/completion-utils.ts +92 -0
  177. package/src/components/editor/ai/transport/chat-transport.tsx +39 -0
  178. package/src/components/editor/cell/CellStatus.tsx +23 -20
  179. package/src/components/editor/cell/CreateCellButton.tsx +3 -4
  180. package/src/components/editor/cell/StagedAICell.tsx +51 -0
  181. package/src/components/editor/cell/cell-actions.tsx +2 -1
  182. package/src/components/editor/cell/code/language-toggle.tsx +3 -4
  183. package/src/components/editor/chrome/wrapper/footer-items/machine-stats.tsx +39 -28
  184. package/src/components/editor/controls/notebook-menu-dropdown.tsx +4 -2
  185. package/src/components/editor/file-tree/requesting-tree.tsx +14 -8
  186. package/src/components/editor/renderers/CellArray.tsx +3 -4
  187. package/src/components/editor/renderers/slides-layout/slides-layout.tsx +3 -3
  188. package/src/components/editor/renderers/slides-layout/types.ts +1 -0
  189. package/src/components/pages/home-page.tsx +4 -1
  190. package/src/components/slides/slides-component.tsx +1 -1
  191. package/src/components/slides/slides.css +6 -0
  192. package/src/components/terminal/__tests__/state.test.ts +207 -0
  193. package/src/components/terminal/hooks.ts +41 -0
  194. package/src/components/terminal/state.ts +75 -0
  195. package/src/components/terminal/terminal.tsx +334 -13
  196. package/src/components/terminal/theme.tsx +57 -0
  197. package/src/components/tracing/tracing-spec.ts +5 -4
  198. package/src/components/ui/range-slider.tsx +4 -2
  199. package/src/components/ui/slider.tsx +3 -1
  200. package/src/components/variables/variables-table.tsx +3 -0
  201. package/src/core/MarimoApp.tsx +9 -6
  202. package/src/core/ai/__tests__/staged-cells.test.ts +356 -0
  203. package/src/core/ai/context/__tests__/registry.test.ts +6 -4
  204. package/src/core/ai/context/providers/cell-output.ts +3 -2
  205. package/src/core/ai/context/providers/error.ts +3 -1
  206. package/src/core/ai/context/providers/file.ts +7 -2
  207. package/src/core/ai/context/providers/tables.ts +3 -2
  208. package/src/core/ai/context/providers/variable.ts +6 -4
  209. package/src/core/ai/staged-cells.ts +208 -0
  210. package/src/core/cells/cells.ts +1 -1
  211. package/src/core/cells/logs.ts +1 -1
  212. package/src/core/codemirror/find-replace/search-highlight.ts +3 -1
  213. package/src/core/codemirror/language/LanguageAdapters.ts +9 -3
  214. package/src/core/codemirror/lsp/federated-lsp.ts +1 -1
  215. package/src/core/codemirror/lsp/notebook-lsp.ts +8 -2
  216. package/src/core/codemirror/readonly/__tests__/extension.test.ts +1 -1
  217. package/src/core/codemirror/rtc/loro/awareness.ts +52 -17
  218. package/src/core/codemirror/rtc/loro/sync.ts +12 -4
  219. package/src/core/config/config-schema.ts +1 -0
  220. package/src/core/config/config.ts +4 -0
  221. package/src/core/hotkeys/hotkeys.ts +8 -4
  222. package/src/core/i18n/__tests__/locale-provider.test.tsx +176 -0
  223. package/src/core/i18n/locale-provider.tsx +35 -0
  224. package/src/core/i18n/with-locale.tsx +12 -0
  225. package/src/core/islands/components/web-components.tsx +13 -10
  226. package/src/core/islands/main.ts +2 -2
  227. package/src/core/kernel/RuntimeState.ts +4 -1
  228. package/src/core/kernel/messages.ts +8 -12
  229. package/src/core/network/DeferredRequestRegistry.ts +16 -4
  230. package/src/core/runtime/runtime.ts +5 -4
  231. package/src/core/saving/__tests__/filename.test.ts +37 -0
  232. package/src/core/static/__tests__/download-html.test.ts +43 -1
  233. package/src/core/wasm/bridge.ts +5 -1
  234. package/src/core/wasm/store.ts +4 -1
  235. package/src/core/wasm/worker/message-buffer.ts +3 -2
  236. package/src/core/websocket/types.ts +22 -16
  237. package/src/core/websocket/useMarimoWebSocket.tsx +2 -2
  238. package/src/css/app/Cell.css +11 -0
  239. package/src/hooks/useFormatting.ts +97 -0
  240. package/src/hooks/useTimer.ts +8 -5
  241. package/src/plugins/core/RenderHTML.tsx +36 -2
  242. package/src/plugins/core/__test__/RenderHTML.test.ts +72 -0
  243. package/src/plugins/core/registerReactComponent.tsx +44 -10
  244. package/src/plugins/impl/DataTablePlugin.tsx +4 -0
  245. package/src/plugins/impl/FileBrowserPlugin.tsx +8 -2
  246. package/src/plugins/impl/RangeSliderPlugin.tsx +5 -3
  247. package/src/plugins/impl/SliderPlugin.tsx +3 -1
  248. package/src/plugins/impl/anywidget/model.ts +16 -5
  249. package/src/plugins/impl/data-editor/types.ts +7 -5
  250. package/src/plugins/impl/data-explorer/components/column-summary.tsx +20 -13
  251. package/src/plugins/impl/panel/utils.ts +6 -4
  252. package/src/plugins/layout/OutlinePlugin.tsx +69 -0
  253. package/src/plugins/layout/StatPlugin.tsx +4 -1
  254. package/src/plugins/plugins.ts +2 -0
  255. package/src/stories/cell.stories.tsx +1 -1
  256. package/src/stories/layout/vertical/one-column.stories.tsx +1 -1
  257. package/src/utils/__tests__/cell-urls.test.ts +29 -0
  258. package/src/utils/__tests__/dates.test.ts +45 -24
  259. package/src/utils/__tests__/filenames.test.ts +18 -0
  260. package/src/utils/__tests__/numbers.test.ts +42 -30
  261. package/src/utils/__tests__/once.test.ts +187 -0
  262. package/src/utils/__tests__/path.test.ts +38 -0
  263. package/src/utils/__tests__/urls.test.ts +56 -1
  264. package/src/utils/dates.ts +15 -10
  265. package/src/utils/edit-distance.ts +8 -6
  266. package/src/utils/errors.ts +9 -0
  267. package/src/utils/id-tree.tsx +21 -10
  268. package/src/utils/localStorage.ts +13 -4
  269. package/src/utils/numbers.ts +11 -11
  270. package/src/utils/once.ts +32 -0
  271. package/src/utils/paths.ts +4 -1
  272. package/src/utils/pluralize.ts +12 -5
  273. package/src/utils/python-poet/poet.ts +30 -15
  274. package/src/utils/time.ts +5 -1
  275. package/dist/assets/ConnectedDataExplorerComponent-Cn5-l2X1.js +0 -19
  276. package/dist/assets/_baseEach-C1FLm7WW.js +0 -1
  277. package/dist/assets/_baseMap-DBVArUYD.js +0 -1
  278. package/dist/assets/_baseUniq-Dk7ZPJ3N.js +0 -1
  279. package/dist/assets/_createAggregator-Bn38fDd3.js +0 -1
  280. package/dist/assets/agent-panel-COUYnuIK.js +0 -475
  281. package/dist/assets/architectureDiagram-W76B3OCA-DBzWQKKu.js +0 -36
  282. package/dist/assets/channel-CjhbjOv4.js +0 -1
  283. package/dist/assets/chat-panel-BPXKoTnZ.js +0 -7
  284. package/dist/assets/chat-panel-Brrs_eeH.css +0 -1
  285. package/dist/assets/classDiagram-KNZD7YFC-DHs5cFzy.js +0 -1
  286. package/dist/assets/classDiagram-v2-RKCZMP56-DHs5cFzy.js +0 -1
  287. package/dist/assets/clone-DM1YNjEn.js +0 -1
  288. package/dist/assets/command-palette-S0bzQp7v.js +0 -1
  289. package/dist/assets/common-B8U9k2Ly.js +0 -1
  290. package/dist/assets/cose-bilkent-S5V4N54A-wz1Sfx7j.js +0 -1
  291. package/dist/assets/dagre-5GWH7T2D-BfpcVBgq.js +0 -4
  292. package/dist/assets/datasources-panel-DfuURLJw.js +0 -1
  293. package/dist/assets/diagram-N5W7TBWH-Bf0oqqQh.js +0 -24
  294. package/dist/assets/diagram-QEK2KX5R-ZTc3qikh.js +0 -43
  295. package/dist/assets/diagram-S2PKOQOG-tLScBy7Z.js +0 -24
  296. package/dist/assets/edit-page-DJ8kJZ9w.js +0 -129
  297. package/dist/assets/file-explorer-panel-CzNUJ63G.js +0 -1
  298. package/dist/assets/gitGraphDiagram-NY62KEGX-C1t6QtVa.js +0 -65
  299. package/dist/assets/graph-CssCVWIq.js +0 -1
  300. package/dist/assets/home-page-9eW6qida.js +0 -9
  301. package/dist/assets/index-CknhX2Vy.css +0 -1
  302. package/dist/assets/index-DcCIe7np.js +0 -28
  303. package/dist/assets/index-OC46250R.js +0 -570
  304. package/dist/assets/infoDiagram-STP46IZ2-CwiAoz9f.js +0 -2
  305. package/dist/assets/layout-DpQrxGW-.js +0 -1
  306. package/dist/assets/linear-NsreOeBF.js +0 -1
  307. package/dist/assets/links-CbvGxbsJ.js +0 -7
  308. package/dist/assets/mermaid-DSt0r6IQ.js +0 -1
  309. package/dist/assets/min-D259kI3t.js +0 -1
  310. package/dist/assets/outline-panel-uvsS-YEQ.js +0 -1
  311. package/dist/assets/packages-panel-xMz9W2hW.js +0 -1
  312. package/dist/assets/run-page-Bb68qdhQ.js +0 -1
  313. package/dist/assets/sankeyDiagram-GR3RE2ED-BSJOau8E.js +0 -10
  314. package/dist/assets/scratchpad-panel-BF4BO-U4.js +0 -1
  315. package/dist/assets/secrets-panel-CdIX44dQ.js +0 -1
  316. package/dist/assets/snippets-panel-Dco9h0rb.js +0 -1
  317. package/dist/assets/sortBy-aLGA-PGK.js +0 -1
  318. package/dist/assets/stateDiagram-KXAO66HF-Bd68WT3b.js +0 -1
  319. package/dist/assets/stateDiagram-v2-UMBNRL4Z-BXz_GSwb.js +0 -1
  320. package/dist/assets/storage-CGlP4lCF.js +0 -26
  321. package/dist/assets/terminal-CxkHubcu.js +0 -9
  322. package/dist/assets/time-D2nr1UgQ.js +0 -1
  323. package/dist/assets/tracing-kTqHxa7q.js +0 -2
  324. package/dist/assets/variable-panel-noTnH-AQ.js +0 -1
  325. package/dist/assets/worker-X5rxzQGQ.js +0 -1
@@ -1,5 +1,8 @@
1
1
  /* Copyright 2024 Marimo. All rights reserved. */
2
- import { describe, expect, it } from "vitest";
2
+ import { describe, expect, it, vi } from "vitest";
3
+ import { EDGE_CASE_FILENAMES } from "../../../__tests__/mocks";
4
+ import { Filenames } from "../../../utils/filenames";
5
+ import { Paths } from "../../../utils/paths";
3
6
  import { visibleForTesting } from "../download-html";
4
7
 
5
8
  const { updateAssetUrl } = visibleForTesting;
@@ -39,3 +42,42 @@ describe("updateAssetUrl", () => {
39
42
  expect(updateAssetUrl(existingUrl, assetBaseUrl)).toBe(existingUrl);
40
43
  });
41
44
  });
45
+
46
+ describe("filename handling for downloads", () => {
47
+ it.each(EDGE_CASE_FILENAMES)(
48
+ "should handle edge case filenames in download operations: %s",
49
+ (filename) => {
50
+ // Test that basename extraction works correctly for downloads
51
+ const basename = Paths.basename(filename);
52
+ expect(basename).toBe(filename);
53
+
54
+ // Test filename conversion for HTML downloads
55
+ const htmlFilename = Filenames.toHTML(filename);
56
+ expect(htmlFilename).toMatch(/\.html$/);
57
+ expect(htmlFilename).toContain(Filenames.withoutExtension(filename));
58
+
59
+ // Ensure unicode and spaces are preserved in basename
60
+ const withoutExt = Filenames.withoutExtension(filename);
61
+ expect(withoutExt).not.toBe("");
62
+ expect(typeof withoutExt).toBe("string");
63
+ },
64
+ );
65
+
66
+ it("should handle blob download filename generation", () => {
67
+ // Mock URL.createObjectURL for blob testing
68
+ const mockCreateObjectURL = vi.fn().mockReturnValue("blob:mock-url");
69
+ global.URL.createObjectURL = mockCreateObjectURL;
70
+
71
+ EDGE_CASE_FILENAMES.forEach((filename) => {
72
+ const htmlFilename = Filenames.toHTML(filename);
73
+
74
+ // Verify blob can be created with unicode filenames
75
+ expect(() => new Blob(["test"], { type: "text/html" })).not.toThrow();
76
+ expect(htmlFilename).toMatch(/\.html$/);
77
+
78
+ // Verify filename maintains unicode characters
79
+ const baseName = Filenames.withoutExtension(filename);
80
+ expect(htmlFilename).toContain(baseName);
81
+ });
82
+ });
83
+ });
@@ -576,7 +576,11 @@ export class PyodideWebsocket implements IReconnectingWebSocket {
576
576
  messageSubscriptions = new Set<(event: MessageEvent) => void>();
577
577
  errorSubscriptions = new Set<(event: Event) => void>();
578
578
 
579
- constructor(private bridge: Pick<PyodideBridge, "consumeMessages">) {}
579
+ private bridge: Pick<PyodideBridge, "consumeMessages">;
580
+
581
+ constructor(bridge: Pick<PyodideBridge, "consumeMessages">) {
582
+ this.bridge = bridge;
583
+ }
580
584
 
581
585
  private consumeMessages() {
582
586
  this.bridge.consumeMessages((message) => {
@@ -87,7 +87,10 @@ const emptyFileStore: FileStore = {
87
87
  };
88
88
 
89
89
  export class CompositeFileStore implements FileStore {
90
- constructor(private stores: FileStore[]) {}
90
+ private stores: FileStore[];
91
+ constructor(stores: FileStore[]) {
92
+ this.stores = stores;
93
+ }
91
94
 
92
95
  insert(index: number, store: FileStore) {
93
96
  this.stores.splice(index, 0, store);
@@ -7,8 +7,9 @@
7
7
  export class MessageBuffer<T> {
8
8
  private buffer: T[];
9
9
  private started = false;
10
-
11
- constructor(private onMessage: (data: T) => void) {
10
+ private onMessage: (data: T) => void;
11
+ constructor(onMessage: (data: T) => void) {
12
+ this.onMessage = onMessage;
12
13
  this.buffer = [];
13
14
  }
14
15
 
@@ -2,22 +2,28 @@
2
2
 
3
3
  import type ReconnectingWebSocket from "partysocket/ws";
4
4
 
5
- export enum WebSocketState {
6
- CONNECTING = "CONNECTING",
7
- OPEN = "CONNECTED",
8
- CLOSING = "CLOSING",
9
- CLOSED = "CLOSED",
10
- }
11
-
12
- export enum WebSocketClosedReason {
13
- KERNEL_DISCONNECTED = "KERNEL_DISCONNECTED",
14
- ALREADY_RUNNING = "ALREADY_RUNNING",
15
- MALFORMED_QUERY = "MALFORMED_QUERY",
16
- }
5
+ export const WebSocketState = {
6
+ CONNECTING: "CONNECTING",
7
+ OPEN: "OPEN",
8
+ CLOSING: "CLOSING",
9
+ CLOSED: "CLOSED",
10
+ } as const;
11
+
12
+ export type WebSocketState =
13
+ (typeof WebSocketState)[keyof typeof WebSocketState];
14
+
15
+ export const WebSocketClosedReason = {
16
+ KERNEL_DISCONNECTED: "KERNEL_DISCONNECTED",
17
+ ALREADY_RUNNING: "ALREADY_RUNNING",
18
+ MALFORMED_QUERY: "MALFORMED_QUERY",
19
+ } as const;
20
+
21
+ export type WebSocketClosedReason =
22
+ (typeof WebSocketClosedReason)[keyof typeof WebSocketClosedReason];
17
23
 
18
24
  export type ConnectionStatus =
19
25
  | {
20
- state: WebSocketState.CLOSED;
26
+ state: typeof WebSocketState.CLOSED;
21
27
  code: WebSocketClosedReason;
22
28
  /**
23
29
  * Human-readable reason for closing the connection.
@@ -31,9 +37,9 @@ export type ConnectionStatus =
31
37
  }
32
38
  | {
33
39
  state:
34
- | WebSocketState.CONNECTING
35
- | WebSocketState.OPEN
36
- | WebSocketState.CLOSING;
40
+ | typeof WebSocketState.CONNECTING
41
+ | typeof WebSocketState.OPEN
42
+ | typeof WebSocketState.CLOSING;
37
43
  };
38
44
 
39
45
  type PublicInterface<T> = {
@@ -86,7 +86,7 @@ export function useMarimoWebSocket(opts: {
86
86
 
87
87
  const handleMessage = (e: MessageEvent<JsonString<OperationMessage>>) => {
88
88
  const msg = jsonParseWithSpecialChar(e.data);
89
- switch (msg.op) {
89
+ switch (msg.data.op) {
90
90
  case "reload":
91
91
  reloadSafe();
92
92
  return;
@@ -267,7 +267,7 @@ export function useMarimoWebSocket(opts: {
267
267
  setCellIds({ cellIds: msg.data.cell_ids as CellId[] });
268
268
  return;
269
269
  default:
270
- logNever(msg);
270
+ logNever(msg.data);
271
271
  }
272
272
  };
273
273
 
@@ -23,6 +23,17 @@
23
23
  outline: none;
24
24
  }
25
25
 
26
+ &:has(.mo-ai-generated-cell)::before {
27
+ content: "";
28
+ position: absolute;
29
+ inset: 0;
30
+ border-radius: 10px;
31
+ pointer-events: none;
32
+ opacity: 0.5;
33
+ box-shadow: 0px 0px 10px 0px var(--cyan-9);
34
+ z-index: 1;
35
+ }
36
+
26
37
  &:focus-within {
27
38
  z-index: 20;
28
39
  }
@@ -0,0 +1,97 @@
1
+ /* Copyright 2024 Marimo. All rights reserved. */
2
+
3
+ import { useCallback } from "react";
4
+ import { useLocale } from "react-aria";
5
+ import { getShortTimeZone, prettyDate, timeAgo } from "@/utils/dates";
6
+ import {
7
+ prettyEngineeringNumber,
8
+ prettyNumber,
9
+ prettyScientificNumber,
10
+ } from "@/utils/numbers";
11
+
12
+ /**
13
+ * Hook that provides locale-aware number formatting using the prettyNumber utility
14
+ */
15
+ export function usePrettyNumber() {
16
+ const { locale } = useLocale();
17
+
18
+ return useCallback(
19
+ (value: unknown): string => {
20
+ return prettyNumber(value, locale);
21
+ },
22
+ [locale],
23
+ );
24
+ }
25
+
26
+ /**
27
+ * Hook that provides locale-aware scientific number formatting
28
+ */
29
+ export function usePrettyScientificNumber() {
30
+ const { locale } = useLocale();
31
+
32
+ return useCallback(
33
+ (value: number, opts: { shouldRound?: boolean } = {}): string => {
34
+ return prettyScientificNumber(value, { ...opts, locale });
35
+ },
36
+ [locale],
37
+ );
38
+ }
39
+
40
+ /**
41
+ * Hook that provides locale-aware engineering number formatting
42
+ */
43
+ export function usePrettyEngineeringNumber() {
44
+ const { locale } = useLocale();
45
+
46
+ return useCallback(
47
+ (value: number): string => {
48
+ return prettyEngineeringNumber(value, locale);
49
+ },
50
+ [locale],
51
+ );
52
+ }
53
+
54
+ /**
55
+ * Hook that provides locale-aware date formatting
56
+ */
57
+ export function usePrettyDate() {
58
+ const { locale } = useLocale();
59
+
60
+ return useCallback(
61
+ (
62
+ value: string | number | null | undefined,
63
+ type: "date" | "datetime",
64
+ ): string => {
65
+ return prettyDate(value, type, locale);
66
+ },
67
+ [locale],
68
+ );
69
+ }
70
+
71
+ /**
72
+ * Hook that provides locale-aware relative time formatting
73
+ */
74
+ export function useTimeAgo() {
75
+ const { locale } = useLocale();
76
+
77
+ return useCallback(
78
+ (value: string | number | null | undefined): string => {
79
+ return timeAgo(value, locale);
80
+ },
81
+ [locale],
82
+ );
83
+ }
84
+
85
+ /**
86
+ * Hook that provides locale-aware timezone abbreviation
87
+ */
88
+ export function useShortTimeZone() {
89
+ const { locale } = useLocale();
90
+
91
+ return useCallback(
92
+ (timezone: string): string => {
93
+ return getShortTimeZone(timezone, locale);
94
+ },
95
+ [locale],
96
+ );
97
+ }
@@ -1,6 +1,7 @@
1
1
  /* Copyright 2024 Marimo. All rights reserved. */
2
2
 
3
3
  import { useEffect, useRef, useState } from "react";
4
+ import { useNumberFormatter } from "react-aria";
4
5
  import useEvent from "react-use-event-hook";
5
6
 
6
7
  /**
@@ -11,6 +12,12 @@ export function useTimer() {
11
12
  const [time, setTime] = useState(0);
12
13
  const interval = useRef<number>(undefined);
13
14
 
15
+ // one decimal place, exactly
16
+ const numberFormatter = useNumberFormatter({
17
+ minimumFractionDigits: 1,
18
+ maximumFractionDigits: 1,
19
+ });
20
+
14
21
  const start = useEvent(() => {
15
22
  interval.current = window.setInterval(() => {
16
23
  setTime((time) => time + 0.1);
@@ -36,11 +43,7 @@ export function useTimer() {
36
43
  }, []);
37
44
 
38
45
  return {
39
- // one decimal place, exactly
40
- time: new Intl.NumberFormat("en-US", {
41
- minimumFractionDigits: 1,
42
- maximumFractionDigits: 1,
43
- }).format(time),
46
+ time: numberFormatter.format(time),
44
47
  start,
45
48
  stop,
46
49
  clear,
@@ -5,7 +5,7 @@ import parse, {
5
5
  Element,
6
6
  type HTMLReactParserOptions,
7
7
  } from "html-react-parser";
8
- import React, { type JSX, type ReactNode, useId } from "react";
8
+ import React, { isValidElement, type JSX, type ReactNode, useId } from "react";
9
9
  import { CopyClipboardIcon } from "@/components/icons/copy-icon";
10
10
 
11
11
  type ReplacementFn = NonNullable<HTMLReactParserOptions["replace"]>;
@@ -23,6 +23,36 @@ const replaceValidTags = (domNode: DOMNode) => {
23
23
  }
24
24
  };
25
25
 
26
+ const removeWrappingBodyTags: TransformFn = (
27
+ reactNode: ReactNode,
28
+ domNode: DOMNode,
29
+ ) => {
30
+ // Remove body tags and just render their children
31
+ if (domNode instanceof Element && domNode.name === "body") {
32
+ if (isValidElement(reactNode) && "props" in reactNode) {
33
+ const props = reactNode.props as { children?: ReactNode };
34
+ const children = props.children;
35
+ return <>{children}</>; // eslint-disable-line react/jsx-no-useless-fragment
36
+ }
37
+ return;
38
+ }
39
+ };
40
+
41
+ const removeWrappingHtmlTags: TransformFn = (
42
+ reactNode: ReactNode,
43
+ domNode: DOMNode,
44
+ ) => {
45
+ // Remove html tags and just render their children
46
+ if (domNode instanceof Element && domNode.name === "html") {
47
+ if (isValidElement(reactNode) && "props" in reactNode) {
48
+ const props = reactNode.props as { children?: ReactNode };
49
+ const children = props.children;
50
+ return <>{children}</>; // eslint-disable-line react/jsx-no-useless-fragment
51
+ }
52
+ return;
53
+ }
54
+ };
55
+
26
56
  const replaceValidIframes = (domNode: DOMNode) => {
27
57
  // For iframe, we just want to use dangerouslySetInnerHTML so:
28
58
  // 1) we can remount the iframe when the src changes
@@ -110,7 +140,11 @@ export const renderHTML = ({ html, additionalReplacements = [] }: Options) => {
110
140
  ...additionalReplacements,
111
141
  ];
112
142
 
113
- const transformFunctions: TransformFn[] = [addCopyButtonToCodehilite];
143
+ const transformFunctions: TransformFn[] = [
144
+ addCopyButtonToCodehilite,
145
+ removeWrappingBodyTags,
146
+ removeWrappingHtmlTags,
147
+ ];
114
148
 
115
149
  return parse(html, {
116
150
  replace: (domNode: DOMNode, index: number) => {
@@ -121,6 +121,78 @@ describe("RenderHTML", () => {
121
121
  </p>
122
122
  `);
123
123
  });
124
+
125
+ test("removes body tags but preserves children", () => {
126
+ const html = "<body><h1>Hello</h1><p>World</p></body>";
127
+ expect(renderHTML({ html })).toMatchInlineSnapshot(`
128
+ <React.Fragment>
129
+ <h1>
130
+ Hello
131
+ </h1>
132
+ <p>
133
+ World
134
+ </p>
135
+ </React.Fragment>
136
+ `);
137
+ });
138
+
139
+ test("removes nested body tags", () => {
140
+ const html = "<div><body><span>Content</span></body></div>";
141
+ expect(renderHTML({ html })).toMatchInlineSnapshot(`
142
+ <div>
143
+ <React.Fragment>
144
+ <span>
145
+ Content
146
+ </span>
147
+ </React.Fragment>
148
+ </div>
149
+ `);
150
+ });
151
+
152
+ test("removes html tags but preserves children", () => {
153
+ const html =
154
+ "<html><head><title>Test</title></head><body><p>Content</p></body></html>";
155
+ expect(renderHTML({ html })).toMatchInlineSnapshot(`
156
+ <React.Fragment>
157
+ <head>
158
+ <title>
159
+ Test
160
+ </title>
161
+ </head>
162
+ <React.Fragment>
163
+ <p>
164
+ Content
165
+ </p>
166
+ </React.Fragment>
167
+ </React.Fragment>
168
+ `);
169
+ });
170
+
171
+ test("removes nested html tags", () => {
172
+ const html = "<div><html><span>Content</span></html></div>";
173
+ expect(renderHTML({ html })).toMatchInlineSnapshot(`
174
+ <div>
175
+ <React.Fragment>
176
+ <span>
177
+ Content
178
+ </span>
179
+ </React.Fragment>
180
+ </div>
181
+ `);
182
+ });
183
+
184
+ test("remove nested body in html", () => {
185
+ const html = "<html><body><span>Content</span></body></html>";
186
+ expect(renderHTML({ html })).toMatchInlineSnapshot(`
187
+ <React.Fragment>
188
+ <React.Fragment>
189
+ <span>
190
+ Content
191
+ </span>
192
+ </React.Fragment>
193
+ </React.Fragment>
194
+ `);
195
+ });
124
196
  });
125
197
 
126
198
  describe("RenderHTML with < nad >", () => {
@@ -1,4 +1,5 @@
1
1
  /* Copyright 2024 Marimo. All rights reserved. */
2
+
2
3
  /* eslint-disable unicorn/prefer-spread */
3
4
  /**
4
5
  * WebComponent Factory for React Components
@@ -7,6 +8,7 @@
7
8
  * component. The factory handles the logic of communicating UI element values
8
9
  * to and from the rest of marimo.
9
10
  */
11
+ import { Provider } from "jotai";
10
12
  import React, {
11
13
  createRef,
12
14
  type JSX,
@@ -21,16 +23,22 @@ import React, {
21
23
  import ReactDOM, { type Root } from "react-dom/client";
22
24
  import useEvent from "react-use-event-hook";
23
25
  import type { ZodSchema } from "zod";
26
+ import { notebookAtom } from "@/core/cells/cells.ts";
27
+ import { findCellId } from "@/core/cells/ids.ts";
28
+ import { isUninstantiated } from "@/core/cells/utils";
24
29
  import { createInputEvent, MarimoValueUpdateEvent } from "@/core/dom/events";
25
30
  import { getUIElementObjectId } from "@/core/dom/ui-element";
26
31
  import { UIElementRegistry } from "@/core/dom/uiregistry";
27
32
  import { FUNCTIONS_REGISTRY } from "@/core/functions/FunctionRegistry";
33
+ import { LocaleProvider } from "@/core/i18n/locale-provider";
34
+ import { store } from "@/core/state/jotai";
28
35
  import {
29
36
  type HTMLElementNotDerivedFromRef,
30
37
  useEventListener,
31
38
  } from "@/hooks/useEventListener";
32
39
  import { StyleNamespace } from "@/theme/namespace";
33
40
  import { useTheme } from "@/theme/useTheme";
41
+ import { CellNotInitializedError } from "@/utils/errors.ts";
34
42
  import { Functions } from "@/utils/functions";
35
43
  import { shallowCompare } from "@/utils/shallow-compare";
36
44
  import { defineCustomElement } from "../../core/dom/defineCustomElement";
@@ -78,6 +86,7 @@ interface PluginSlotProps<T> {
78
86
  }
79
87
 
80
88
  /* Handles synchronization of value on behalf of the component */
89
+
81
90
  // eslint-disable-next-line react/function-component-definition
82
91
  function PluginSlotInternal<T>(
83
92
  { hostElement, plugin, children, getInitialValue }: PluginSlotProps<T>,
@@ -172,6 +181,27 @@ function PluginSlotInternal<T>(
172
181
  );
173
182
  const objectId = getUIElementObjectId(hostElement);
174
183
  invariant(objectId, "Object ID should exist");
184
+
185
+ const cellId = findCellId(hostElement);
186
+ invariant(cellId, "Cell ID should exist");
187
+
188
+ const notebookState = store.get(notebookAtom);
189
+ const cellRuntime = notebookState.cellRuntime[cellId];
190
+ const cellData = notebookState.cellData[cellId];
191
+
192
+ const cellNotInitialized = isUninstantiated({
193
+ executionTime:
194
+ cellRuntime.runElapsedTimeMs ?? cellData.lastExecutionTime,
195
+ status: cellRuntime.status,
196
+ errored: cellRuntime.errored,
197
+ interrupted: cellRuntime.interrupted,
198
+ stopped: cellRuntime.stopped,
199
+ });
200
+
201
+ if (cellNotInitialized) {
202
+ throw new CellNotInitializedError();
203
+ }
204
+
175
205
  const response = await FUNCTIONS_REGISTRY.request({
176
206
  args: prettyParse(input, args[0]),
177
207
  functionName: key,
@@ -335,16 +365,20 @@ export function registerReactComponent<T>(plugin: IPlugin<T, unknown>): void {
335
365
 
336
366
  invariant(this.root, "Root must be defined");
337
367
  this.root.render(
338
- <PluginSlot
339
- hostElement={this}
340
- plugin={plugin}
341
- ref={this.pluginRef}
342
- getInitialValue={() => {
343
- return parseInitialValue(this, UIElementRegistry.INSTANCE);
344
- }}
345
- >
346
- {this.getChildren()}
347
- </PluginSlot>,
368
+ <Provider store={store}>
369
+ <LocaleProvider>
370
+ <PluginSlot
371
+ hostElement={this}
372
+ plugin={plugin}
373
+ ref={this.pluginRef}
374
+ getInitialValue={() => {
375
+ return parseInitialValue(this, UIElementRegistry.INSTANCE);
376
+ }}
377
+ >
378
+ {this.getChildren()}
379
+ </PluginSlot>
380
+ </LocaleProvider>
381
+ </Provider>,
348
382
  );
349
383
  }
350
384
 
@@ -254,6 +254,7 @@ export const DataTablePlugin = createPlugin<S>("marimo-table")
254
254
  maxColumns: z.union([z.number(), z.literal("all")]).default("all"),
255
255
  hasStableRowId: z.boolean().default(false),
256
256
  cellStyles: z.record(z.record(z.object({}).passthrough())).optional(),
257
+ hoverTemplate: z.string().optional(),
257
258
  // Whether to load the data lazily.
258
259
  lazy: z.boolean().default(false),
259
260
  // If lazy, this will preload the first page of data
@@ -385,6 +386,7 @@ interface DataTableProps<T> extends Data<T>, DataTableFunctions {
385
386
  // Filters
386
387
  enableFilters?: boolean;
387
388
  cellStyles?: CellStyleState | null;
389
+ hoverTemplate?: string | null;
388
390
  toggleDisplayHeader?: () => void;
389
391
  host: HTMLElement;
390
392
  cellId?: CellId | null;
@@ -707,6 +709,7 @@ const DataTableComponent = ({
707
709
  totalColumns,
708
710
  get_row_ids,
709
711
  cellStyles,
712
+ hoverTemplate,
710
713
  toggleDisplayHeader,
711
714
  calculate_top_k_rows,
712
715
  preview_column,
@@ -904,6 +907,7 @@ const DataTableComponent = ({
904
907
  rowSelection={rowSelection}
905
908
  cellSelection={cellSelection}
906
909
  cellStyling={cellStyles}
910
+ hoverTemplate={hoverTemplate}
907
911
  downloadAs={showDownload ? downloadAs : undefined}
908
912
  enableSearch={enableSearch}
909
913
  searchQuery={searchQuery}
@@ -12,7 +12,7 @@ import { Button } from "@/components/ui/button";
12
12
  import { Checkbox } from "@/components/ui/checkbox";
13
13
  import { Label } from "@/components/ui/label";
14
14
  import { NativeSelect } from "@/components/ui/native-select";
15
- import { Table, TableCell, TableRow } from "@/components/ui/table";
15
+ import { Table, TableBody, TableCell, TableRow } from "@/components/ui/table";
16
16
  import { toast } from "@/components/ui/use-toast";
17
17
  import { useAsyncData } from "@/hooks/useAsyncData";
18
18
  import { useInternalStateWithSync } from "@/hooks/useInternalStateWithSync";
@@ -158,6 +158,10 @@ export const FileBrowser = ({
158
158
  return null;
159
159
  }
160
160
 
161
+ if (!data && error) {
162
+ return <Banner kind="danger">{error.message}</Banner>;
163
+ }
164
+
161
165
  let { files } = data || {};
162
166
  if (files === undefined) {
163
167
  files = [];
@@ -458,7 +462,9 @@ export const FileBrowser = ({
458
462
  className="mt-3 overflow-y-auto w-full border"
459
463
  style={{ height: "14rem" }}
460
464
  >
461
- <Table className="cursor-pointer table-fixed">{fileRows}</Table>
465
+ <Table className="cursor-pointer table-fixed">
466
+ <TableBody>{fileRows}</TableBody>
467
+ </Table>
462
468
  </div>
463
469
  <div className="mt-4">
464
470
  {value.length > 0 && (
@@ -2,6 +2,7 @@
2
2
 
3
3
  import { isEqual } from "lodash-es";
4
4
  import { type JSX, useEffect, useId, useState } from "react";
5
+ import { useLocale } from "react-aria";
5
6
  import { z } from "zod";
6
7
  import { cn } from "@/utils/cn";
7
8
  import { prettyScientificNumber } from "@/utils/numbers";
@@ -82,6 +83,7 @@ const RangeSliderComponent = ({
82
83
  valueMap,
83
84
  }: RangeSliderProps): JSX.Element => {
84
85
  const id = useId();
86
+ const { locale } = useLocale();
85
87
 
86
88
  // Hold internal value
87
89
  const [internalValue, setInternalValue] = useState(value);
@@ -150,9 +152,9 @@ const RangeSliderComponent = ({
150
152
  />
151
153
  {showValue && (
152
154
  <div className="text-xs text-muted-foreground min-w-[16px]">
153
- {`${prettyScientificNumber(
154
- valueMap(internalValue[0]),
155
- )}, ${prettyScientificNumber(valueMap(internalValue[1]))}`}
155
+ {`${prettyScientificNumber(valueMap(internalValue[0]), {
156
+ locale,
157
+ })}, ${prettyScientificNumber(valueMap(internalValue[1]), { locale })}`}
156
158
  </div>
157
159
  )}
158
160
  </div>
@@ -1,5 +1,6 @@
1
1
  /* Copyright 2024 Marimo. All rights reserved. */
2
2
  import { type JSX, useEffect, useId, useState } from "react";
3
+ import { useLocale } from "react-aria";
3
4
  import { z } from "zod";
4
5
  import { NumberField } from "@/components/ui/number-field";
5
6
  import { cn } from "@/utils/cn";
@@ -85,6 +86,7 @@ const SliderComponent = ({
85
86
  disabled,
86
87
  }: SliderProps): JSX.Element => {
87
88
  const id = useId();
89
+ const { locale } = useLocale();
88
90
 
89
91
  // Hold internal value
90
92
  const [internalValue, setInternalValue] = useState(value);
@@ -138,7 +140,7 @@ const SliderComponent = ({
138
140
  />
139
141
  {showValue && (
140
142
  <div className="text-xs text-muted-foreground min-w-[16px]">
141
- {prettyScientificNumber(valueMap(internalValue))}
143
+ {prettyScientificNumber(valueMap(internalValue), { locale })}
142
144
  </div>
143
145
  )}
144
146
  {includeInput && (