@marimo-team/frontend 0.16.0 → 0.16.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 (257) hide show
  1. package/dist/assets/ConnectedDataExplorerComponent-2wVcyvDj.js +19 -0
  2. package/dist/assets/{ImageComparisonComponent-fTHv1Ih0.js → ImageComparisonComponent-D2j6i0hv.js} +1 -1
  3. package/dist/assets/{VegaLite-Bdi-TyfY.js → VegaLite-BckFaf2D.js} +1 -1
  4. package/dist/assets/_baseEach-CvTX9w0Y.js +1 -0
  5. package/dist/assets/_baseMap-CtlwA90f.js +1 -0
  6. package/dist/assets/_baseUniq-BKktIGQ1.js +1 -0
  7. package/dist/assets/{_createAggregator-DcD0kTA5.js → _createAggregator-C5CVY-0t.js} +1 -1
  8. package/dist/assets/{agent-panel-Crv430aI.js → agent-panel-RGLNjkYe.js} +76 -57
  9. package/dist/assets/{any-language-editor-CQh552Wu.js → any-language-editor-DjuXwGCA.js} +1 -1
  10. package/dist/assets/{architectureDiagram-W76B3OCA-BAJeBxzt.js → architectureDiagram-W76B3OCA-Dyj4ds_R.js} +1 -1
  11. package/dist/assets/{between-horizontal-start-Boxgxbt_.js → between-horizontal-start-Dt2aKpPf.js} +1 -1
  12. package/dist/assets/{blockDiagram-QIGZ2CNN-CL-1svEK.js → blockDiagram-QIGZ2CNN-o-i7DDvN.js} +1 -1
  13. package/dist/assets/{c4Diagram-FPNF74CW-BbEqbCTl.js → c4Diagram-FPNF74CW-DGHEwWrx.js} +1 -1
  14. package/dist/assets/channel-Co6iMgWq.js +1 -0
  15. package/dist/assets/chat-panel-9alr8FS4.js +3 -0
  16. package/dist/assets/{chunk-4BX2VUAB-C--8TXeE.js → chunk-4BX2VUAB-BJecb-Ri.js} +1 -1
  17. package/dist/assets/{chunk-55IACEB6-Bj00HDqq.js → chunk-55IACEB6-CAATkc4w.js} +1 -1
  18. package/dist/assets/{chunk-FMBD7UC4-C-lhB6hN.js → chunk-FMBD7UC4-DPuNbQ-f.js} +1 -1
  19. package/dist/assets/{chunk-K7UQS3LO-B-pGTXPt.js → chunk-K7UQS3LO-C8TWVLiH.js} +1 -1
  20. package/dist/assets/{chunk-QN33PNHL-DqUzGhvm.js → chunk-QN33PNHL-DiZZ09q4.js} +1 -1
  21. package/dist/assets/{chunk-QZHKN3VN-TntJHfSk.js → chunk-QZHKN3VN-BIUM7usu.js} +1 -1
  22. package/dist/assets/{chunk-TVAH2DTR-HUJb1psV.js → chunk-TVAH2DTR-vGTArPBG.js} +1 -1
  23. package/dist/assets/{chunk-TZMSLE5B-BK3C__t3.js → chunk-TZMSLE5B-D2KRqp_x.js} +1 -1
  24. package/dist/assets/{circle-play-DBLOv1Yu.js → circle-play-cjeNez0N.js} +1 -1
  25. package/dist/assets/classDiagram-KNZD7YFC-BbJ0rY3y.js +1 -0
  26. package/dist/assets/classDiagram-v2-RKCZMP56-BbJ0rY3y.js +1 -0
  27. package/dist/assets/{clear-button-BeoFbEKH.js → clear-button-C97JtAez.js} +1 -1
  28. package/dist/assets/clone-BMP0PsTa.js +1 -0
  29. package/dist/assets/{command-palette-CXZiSv0I.js → command-palette-B93Pjcky.js} +1 -1
  30. package/dist/assets/{common-C7oJcmCT.js → common-Du9rSOwD.js} +1 -1
  31. package/dist/assets/{compile-7L0MwhyI.js → compile-CZXqyOxa.js} +1 -1
  32. package/dist/assets/{cose-bilkent-S5V4N54A-BMkGLcVC.js → cose-bilkent-S5V4N54A-CqUN5Y9b.js} +1 -1
  33. package/dist/assets/{dagre-5GWH7T2D-BJtRienS.js → dagre-5GWH7T2D-RJqTI9DM.js} +1 -1
  34. package/dist/assets/{data-grid-overlay-editor-DBkmGtNs.js → data-grid-overlay-editor-DZN0q1LV.js} +1 -1
  35. package/dist/assets/datasources-panel-v7H3cR0p.js +1 -0
  36. package/dist/assets/{dependency-graph-panel-DEdOxp2X.js → dependency-graph-panel-CEog_O7V.js} +1 -1
  37. package/dist/assets/{diagram-N5W7TBWH-CmECY3nb.js → diagram-N5W7TBWH-D-l4zZ9d.js} +1 -1
  38. package/dist/assets/{diagram-QEK2KX5R-DMOVSNKD.js → diagram-QEK2KX5R-CCOmBUt-.js} +1 -1
  39. package/dist/assets/{diagram-S2PKOQOG-BiJ96PNQ.js → diagram-S2PKOQOG-C_I_9jnZ.js} +1 -1
  40. package/dist/assets/{documentation-panel-xULhaEv3.js → documentation-panel-C1BtMZ3M.js} +1 -1
  41. package/dist/assets/edit-page-B-oevUZ9.js +129 -0
  42. package/dist/assets/{ellipsis-vertical-BBqXIlc2.js → ellipsis-vertical-BEb-J8z6.js} +1 -1
  43. package/dist/assets/{empty-state-B3dA3G5P.js → empty-state-C99UyDE3.js} +1 -1
  44. package/dist/assets/{erDiagram-AWTI2OKA-MP1DiFRo.js → erDiagram-AWTI2OKA-BePOLi5M.js} +1 -1
  45. package/dist/assets/{error-panel-Cc1sv-Ag.js → error-panel-Bs34jXFh.js} +1 -1
  46. package/dist/assets/file-explorer-panel-Ck6UL861.js +1 -0
  47. package/dist/assets/{flowDiagram-PVAE7QVJ-BX7caPp7.js → flowDiagram-PVAE7QVJ-BgjFu5l7.js} +1 -1
  48. package/dist/assets/{ganttDiagram-OWAHRB6G-B462g4Yf.js → ganttDiagram-OWAHRB6G-YOPb3XSV.js} +4 -4
  49. package/dist/assets/{gitGraphDiagram-NY62KEGX-CGgvZ9-9.js → gitGraphDiagram-NY62KEGX-CGhqaDTy.js} +1 -1
  50. package/dist/assets/{glide-data-editor-C0gUFZON.js → glide-data-editor-9QUH6iso.js} +11 -11
  51. package/dist/assets/{graph-CHRVBzY5.js → graph-DQQFGrho.js} +1 -1
  52. package/dist/assets/home-page-DRKpPCrF.js +9 -0
  53. package/dist/assets/{index-C1v_Z9et.js → index-2252nrk6.js} +1 -1
  54. package/dist/assets/{index-CQDrxQ0j.js → index-Aeo6WiK7.js} +1 -1
  55. package/dist/assets/{index-C4Tn5NvJ.js → index-B8jXZ12t.js} +1 -1
  56. package/dist/assets/{index-DoRmcrKM.js → index-BAbIIxHU.js} +1 -1
  57. package/dist/assets/{index-BY93Ejhl.js → index-BJNCMUmG.js} +1 -1
  58. package/dist/assets/{index-CpTPJo4k.js → index-BW3k9Gss.js} +1 -1
  59. package/dist/assets/{index-D1vmG6DS.js → index-BjgnbONl.js} +1 -1
  60. package/dist/assets/{index-z9bohSQJ.js → index-BprjMYH5.js} +1 -1
  61. package/dist/assets/{index-BVgAenPd.js → index-C1ez98sk.js} +1 -1
  62. package/dist/assets/{index-D9UKkrr2.js → index-C2MD0vgD.js} +1 -1
  63. package/dist/assets/index-C7CoaNFb.js +578 -0
  64. package/dist/assets/{index-C-GhZ7ti.js → index-CFKO7WXI.js} +1 -1
  65. package/dist/assets/{index-lYa_leQE.js → index-CUFv_thQ.js} +1 -1
  66. package/dist/assets/{index-vmICa5KN.js → index-C_tkBKNO.js} +1 -1
  67. package/dist/assets/{index-C77h_TXN.js → index-CfaDbEdi.js} +1 -1
  68. package/dist/assets/{index-DEQvTChO.js → index-ClzeQrN7.js} +1 -1
  69. package/dist/assets/index-DadI618h.css +1 -0
  70. package/dist/assets/{index-DRMm6SNo.js → index-DdnKZNxM.js} +1 -1
  71. package/dist/assets/{index-CWMgowgL.js → index-G5QZppK2.js} +1 -1
  72. package/dist/assets/{index-Clbi_Yaq.js → index-SGLNXrGP.js} +1 -1
  73. package/dist/assets/{index-C-8WADat.js → index-aE43R74q.js} +1 -1
  74. package/dist/assets/infoDiagram-STP46IZ2-CJLOpSAf.js +2 -0
  75. package/dist/assets/{isEmpty-DU_ogP_D.js → isEmpty-D-4c7sMv.js} +1 -1
  76. package/dist/assets/{journeyDiagram-BIP6EPQ6-C6EgLP_Q.js → journeyDiagram-BIP6EPQ6-C94u3Mv3.js} +1 -1
  77. package/dist/assets/{kanban-definition-6OIFK2YF-BXzYO1yj.js → kanban-definition-6OIFK2YF-BEXYFzz7.js} +1 -1
  78. package/dist/assets/{layout-jihVw5-i.js → layout-Bz2BJ2ru.js} +1 -1
  79. package/dist/assets/{linear-C4blANlC.js → linear-D8s7K76e.js} +1 -1
  80. package/dist/assets/links-BpXlz1GG.js +7 -0
  81. package/dist/assets/{logs-panel-D401qzZh.js → logs-panel-DC7wpmPz.js} +1 -1
  82. package/dist/assets/{markdown-renderer-Cd9eYyaL.js → markdown-renderer-DRdSWR9X.js} +20 -20
  83. package/dist/assets/{mermaid-BEVuRz_O.js → mermaid-Y3x4hmD0.js} +1 -1
  84. package/dist/assets/{mermaid.core-CaSnaLH0.js → mermaid.core-DzthE35Y.js} +4 -4
  85. package/dist/assets/min-BBO3-1Hg.js +1 -0
  86. package/dist/assets/{mindmap-definition-Q6HEUPPD-BXUM5MT2.js → mindmap-definition-Q6HEUPPD-DktvuLe1.js} +1 -1
  87. package/dist/assets/{number-overlay-editor-4uWXGlPG.js → number-overlay-editor-BEfwI1IT.js} +1 -1
  88. package/dist/assets/outline-panel-CdsnAy2w.js +1 -0
  89. package/dist/assets/{packages-panel-CJL0MVlj.js → packages-panel-DiTA-d_D.js} +1 -1
  90. package/dist/assets/{pieDiagram-ADFJNKIX-Dxt5PVNo.js → pieDiagram-ADFJNKIX-DQDNQ-de.js} +1 -1
  91. package/dist/assets/{quadrantDiagram-LMRXKWRM-D4pUaA31.js → quadrantDiagram-LMRXKWRM-0kgIXc2-.js} +1 -1
  92. package/dist/assets/{react-plotly-cJZ0VWBq.js → react-plotly-DJqqfM7c.js} +1 -1
  93. package/dist/assets/{requirementDiagram-4UW4RH46-DVRTjgas.js → requirementDiagram-4UW4RH46-B5rb0ypd.js} +1 -1
  94. package/dist/assets/{run-page-BUEnMC9w.js → run-page-CFmLrv1R.js} +1 -1
  95. package/dist/assets/{sankeyDiagram-GR3RE2ED-CVFnD9C-.js → sankeyDiagram-GR3RE2ED-Dom7IlnF.js} +1 -1
  96. package/dist/assets/{scratchpad-panel-BIgRENkI.js → scratchpad-panel-CuHWpHO8.js} +1 -1
  97. package/dist/assets/{secrets-panel-xY5-V_BD.js → secrets-panel-CfHc5YD0.js} +1 -1
  98. package/dist/assets/{sequenceDiagram-C3RYC4MD-_lY4ZN_S.js → sequenceDiagram-C3RYC4MD-PNJWXQbw.js} +1 -1
  99. package/dist/assets/{slides-component-DMjQomc3.css → slides-component-C-LoGC1U.css} +1 -1
  100. package/dist/assets/{slides-component-Xjymwj7X.js → slides-component-CJgaTRZ0.js} +1 -1
  101. package/dist/assets/snippets-panel-B2EC1txM.js +1 -0
  102. package/dist/assets/sortBy-DZnlX29-.js +1 -0
  103. package/dist/assets/{state-C4NiC9tO.js → state-CWict9RU.js} +1 -1
  104. package/dist/assets/{stateDiagram-KXAO66HF-Da0JQWCn.js → stateDiagram-KXAO66HF-BE58aJnr.js} +1 -1
  105. package/dist/assets/stateDiagram-v2-UMBNRL4Z-CdThjimL.js +1 -0
  106. package/dist/assets/storage-DRaR04wR.js +26 -0
  107. package/dist/assets/{terminal-BPwTkXae.js → terminal-BX3Su5q7.js} +1 -1
  108. package/dist/assets/{time-Dv5_Ouz_.js → time-hUzZfpNE.js} +1 -1
  109. package/dist/assets/{timeline-definition-XQNQX7LJ-Dxh5Zu2e.js → timeline-definition-XQNQX7LJ-CqQP9t51.js} +1 -1
  110. package/dist/assets/tracing-B10Q1n-L.js +2 -0
  111. package/dist/assets/{tracing-panel-DAzrzNmm.js → tracing-panel-Du8WCnno.js} +2 -2
  112. package/dist/assets/{trash-Dc6DSjz_.js → trash-B81GTiv6.js} +1 -1
  113. package/dist/assets/{tree-jheoerAX.js → tree-6vW2ogkh.js} +1 -1
  114. package/dist/assets/{treemap-75Q7IDZK-IgpxeGaf.js → treemap-75Q7IDZK-CdwDwwsz.js} +27 -27
  115. package/dist/assets/variable-panel-D5qgJI7k.js +1 -0
  116. package/dist/assets/{vega-component-BpfpiPKI.js → vega-component-DJaJWMJM.js} +1 -1
  117. package/dist/assets/worker-fHbtoWvT.js +1 -0
  118. package/dist/assets/{xychartDiagram-6GGTOJPD-CmNigJ31.js → xychartDiagram-6GGTOJPD-WFtXqaM9.js} +1 -1
  119. package/dist/index.html +2 -2
  120. package/package.json +3 -2
  121. package/src/components/app-config/user-config-form.tsx +46 -1
  122. package/src/components/chat/acp/__tests__/__snapshots__/prompt.test.ts.snap +62 -43
  123. package/src/components/chat/acp/__tests__/atoms.test.ts +1 -1
  124. package/src/components/chat/acp/__tests__/state.test.ts +36 -36
  125. package/src/components/chat/acp/agent-panel.tsx +24 -27
  126. package/src/components/chat/acp/blocks.tsx +6 -6
  127. package/src/components/chat/acp/prompt.ts +62 -43
  128. package/src/components/chat/chat-panel.tsx +5 -1
  129. package/src/components/chat/markdown-renderer.tsx +6 -10
  130. package/src/components/chat/tool-call-accordion.tsx +52 -20
  131. package/src/components/data-table/SearchBar.tsx +8 -7
  132. package/src/components/data-table/__tests__/column_formatting.test.ts +50 -35
  133. package/src/components/data-table/__tests__/data-table.test.tsx +39 -1
  134. package/src/components/data-table/cell-hover-template/feature.ts +14 -0
  135. package/src/components/data-table/cell-hover-template/types.ts +11 -0
  136. package/src/components/data-table/charts/components/form-fields.tsx +41 -37
  137. package/src/components/data-table/charts/forms/common-chart.tsx +2 -2
  138. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +5 -2
  139. package/src/components/data-table/column-formatting/feature.ts +62 -29
  140. package/src/components/data-table/column-formatting/types.ts +1 -0
  141. package/src/components/data-table/column-header.tsx +3 -1
  142. package/src/components/data-table/column-summary/chart-spec-model.tsx +24 -7
  143. package/src/components/data-table/column-summary/column-summary.tsx +18 -9
  144. package/src/components/data-table/columns.tsx +42 -18
  145. package/src/components/data-table/data-table.tsx +10 -2
  146. package/src/components/data-table/date-popover.tsx +85 -75
  147. package/src/components/data-table/filter-pills.tsx +14 -9
  148. package/src/components/data-table/header-items.tsx +5 -1
  149. package/src/components/data-table/pagination.tsx +20 -13
  150. package/src/components/data-table/renderers.tsx +28 -0
  151. package/src/components/data-table/row-viewer-panel/row-viewer.tsx +10 -8
  152. package/src/components/datasources/column-preview.tsx +6 -2
  153. package/src/components/datasources/datasources.tsx +8 -12
  154. package/src/components/editor/ai/transport/chat-transport.tsx +4 -1
  155. package/src/components/editor/cell/CellStatus.tsx +23 -20
  156. package/src/components/editor/cell/CreateCellButton.tsx +3 -4
  157. package/src/components/editor/cell/code/language-toggle.tsx +3 -4
  158. package/src/components/editor/chrome/wrapper/footer-items/machine-stats.tsx +39 -28
  159. package/src/components/editor/controls/notebook-menu-dropdown.tsx +4 -2
  160. package/src/components/editor/file-tree/requesting-tree.tsx +14 -8
  161. package/src/components/editor/renderers/CellArray.tsx +3 -4
  162. package/src/components/editor/renderers/slides-layout/slides-layout.tsx +3 -3
  163. package/src/components/editor/renderers/slides-layout/types.ts +1 -0
  164. package/src/components/pages/home-page.tsx +4 -1
  165. package/src/components/slides/slides-component.tsx +1 -1
  166. package/src/components/slides/slides.css +6 -0
  167. package/src/components/terminal/theme.tsx +1 -0
  168. package/src/components/tracing/tracing-spec.ts +5 -4
  169. package/src/components/ui/range-slider.tsx +4 -2
  170. package/src/components/ui/slider.tsx +3 -1
  171. package/src/components/variables/variables-table.tsx +3 -0
  172. package/src/core/MarimoApp.tsx +9 -6
  173. package/src/core/ai/context/__tests__/registry.test.ts +6 -4
  174. package/src/core/ai/context/providers/cell-output.ts +3 -2
  175. package/src/core/ai/context/providers/error.ts +3 -1
  176. package/src/core/ai/context/providers/file.ts +7 -2
  177. package/src/core/ai/context/providers/tables.ts +3 -2
  178. package/src/core/ai/context/providers/variable.ts +6 -4
  179. package/src/core/ai/staged-cells.ts +34 -1
  180. package/src/core/cells/__tests__/add-missing-import.test.ts +67 -22
  181. package/src/core/cells/add-missing-import.ts +24 -7
  182. package/src/core/cells/cells.ts +26 -27
  183. package/src/core/cells/logs.ts +1 -1
  184. package/src/core/codemirror/find-replace/search-highlight.ts +3 -1
  185. package/src/core/codemirror/language/LanguageAdapters.ts +9 -3
  186. package/src/core/codemirror/lsp/notebook-lsp.ts +8 -2
  187. package/src/core/codemirror/readonly/__tests__/extension.test.ts +1 -1
  188. package/src/core/codemirror/rtc/loro/awareness.ts +52 -17
  189. package/src/core/codemirror/rtc/loro/sync.ts +12 -4
  190. package/src/core/config/config-schema.ts +1 -0
  191. package/src/core/config/config.ts +4 -0
  192. package/src/core/hotkeys/hotkeys.ts +8 -4
  193. package/src/core/i18n/__tests__/locale-provider.test.tsx +176 -0
  194. package/src/core/i18n/locale-provider.tsx +35 -0
  195. package/src/core/i18n/with-locale.tsx +12 -0
  196. package/src/core/islands/components/web-components.tsx +13 -10
  197. package/src/core/kernel/RuntimeState.ts +4 -1
  198. package/src/core/kernel/messages.ts +2 -2
  199. package/src/core/network/DeferredRequestRegistry.ts +16 -4
  200. package/src/core/runtime/runtime.ts +5 -4
  201. package/src/core/wasm/bridge.ts +5 -1
  202. package/src/core/wasm/store.ts +4 -1
  203. package/src/core/wasm/worker/message-buffer.ts +3 -2
  204. package/src/core/websocket/types.ts +22 -16
  205. package/src/hooks/useFormatting.ts +97 -0
  206. package/src/hooks/useTimer.ts +8 -5
  207. package/src/plugins/core/registerReactComponent.tsx +16 -10
  208. package/src/plugins/impl/DataTablePlugin.tsx +4 -0
  209. package/src/plugins/impl/RangeSliderPlugin.tsx +5 -3
  210. package/src/plugins/impl/SliderPlugin.tsx +3 -1
  211. package/src/plugins/impl/anywidget/model.ts +16 -5
  212. package/src/plugins/impl/data-editor/types.ts +7 -5
  213. package/src/plugins/impl/data-explorer/components/column-summary.tsx +20 -13
  214. package/src/plugins/impl/panel/utils.ts +6 -4
  215. package/src/plugins/layout/OutlinePlugin.tsx +69 -0
  216. package/src/plugins/layout/StatPlugin.tsx +4 -1
  217. package/src/plugins/plugins.ts +2 -0
  218. package/src/utils/__tests__/dates.test.ts +45 -24
  219. package/src/utils/__tests__/numbers.test.ts +42 -30
  220. package/src/utils/__tests__/once.test.ts +187 -0
  221. package/src/utils/dates.ts +15 -10
  222. package/src/utils/edit-distance.ts +8 -6
  223. package/src/utils/errors.ts +1 -1
  224. package/src/utils/id-tree.tsx +21 -10
  225. package/src/utils/localStorage.ts +13 -4
  226. package/src/utils/numbers.ts +11 -11
  227. package/src/utils/once.ts +32 -0
  228. package/src/utils/paths.ts +4 -1
  229. package/src/utils/pluralize.ts +12 -5
  230. package/src/utils/python-poet/poet.ts +30 -15
  231. package/src/utils/time.ts +5 -1
  232. package/dist/assets/ConnectedDataExplorerComponent-BErMbWvG.js +0 -19
  233. package/dist/assets/_baseEach-CNBxBxvS.js +0 -1
  234. package/dist/assets/_baseMap-D1WHjKrd.js +0 -1
  235. package/dist/assets/_baseUniq-CCgDNtZb.js +0 -1
  236. package/dist/assets/channel-_2eNSz0n.js +0 -1
  237. package/dist/assets/chat-panel-CXh5Wl6C.js +0 -3
  238. package/dist/assets/classDiagram-KNZD7YFC-BGmh9POF.js +0 -1
  239. package/dist/assets/classDiagram-v2-RKCZMP56-BGmh9POF.js +0 -1
  240. package/dist/assets/clone-BFDSPAj3.js +0 -1
  241. package/dist/assets/datasources-panel-B7FbYLiy.js +0 -1
  242. package/dist/assets/edit-page-BrYda9VE.js +0 -129
  243. package/dist/assets/file-explorer-panel-Bw59Kva1.js +0 -1
  244. package/dist/assets/home-page-Fb2osjys.js +0 -9
  245. package/dist/assets/index-Cx0bsY1w.css +0 -1
  246. package/dist/assets/index-DKEudB02.js +0 -578
  247. package/dist/assets/infoDiagram-STP46IZ2-CVyrdLc8.js +0 -2
  248. package/dist/assets/links-D59GIweI.js +0 -7
  249. package/dist/assets/min-DUMu_zeK.js +0 -1
  250. package/dist/assets/outline-panel-DIzkvm2I.js +0 -1
  251. package/dist/assets/snippets-panel-CTPYW41n.js +0 -1
  252. package/dist/assets/sortBy-BNZKwiq_.js +0 -1
  253. package/dist/assets/stateDiagram-v2-UMBNRL4Z-D5lYZOOt.js +0 -1
  254. package/dist/assets/storage-CMdLzB_c.js +0 -26
  255. package/dist/assets/tracing-BCIurUfa.js +0 -2
  256. package/dist/assets/variable-panel-DYAiLBmF.js +0 -1
  257. package/dist/assets/worker-X5rxzQGQ.js +0 -1
@@ -0,0 +1,176 @@
1
+ /* Copyright 2024 Marimo. All rights reserved. */
2
+
3
+ import { cleanup, render } from "@testing-library/react";
4
+ import { createStore, Provider } from "jotai";
5
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
6
+ import { userConfigAtom } from "@/core/config/config";
7
+ import { parseUserConfig } from "@/core/config/config-schema";
8
+ import { LocaleProvider } from "../locale-provider";
9
+
10
+ // Mock navigator.language with a getter
11
+ let mockNavigatorLanguage: string | undefined;
12
+
13
+ Object.defineProperty(window, "navigator", {
14
+ value: {
15
+ get language() {
16
+ return mockNavigatorLanguage;
17
+ },
18
+ },
19
+ writable: true,
20
+ });
21
+
22
+ // Mock react-aria-components I18nProvider
23
+ vi.mock("react-aria-components", () => ({
24
+ I18nProvider: ({
25
+ children,
26
+ locale,
27
+ }: {
28
+ children: React.ReactNode;
29
+ locale: string;
30
+ }) => (
31
+ <div data-testid="i18n-provider" data-locale={locale}>
32
+ {children}
33
+ </div>
34
+ ),
35
+ }));
36
+
37
+ describe("LocaleProvider", () => {
38
+ beforeEach(() => {
39
+ // Reset the mock before each test
40
+ mockNavigatorLanguage = undefined;
41
+ });
42
+
43
+ afterEach(() => {
44
+ cleanup();
45
+ // Clear all mocks after each test
46
+ mockNavigatorLanguage = undefined;
47
+ vi.clearAllMocks();
48
+ });
49
+
50
+ it("should render I18nProvider without locale when locale is null", () => {
51
+ const store = createStore();
52
+ const config = parseUserConfig({ display: { locale: null } });
53
+ store.set(userConfigAtom, config);
54
+
55
+ const { getByTestId } = render(
56
+ <Provider store={store}>
57
+ <LocaleProvider>
58
+ <div>Test content</div>
59
+ </LocaleProvider>
60
+ </Provider>,
61
+ );
62
+
63
+ const i18nProvider = getByTestId("i18n-provider");
64
+ expect(i18nProvider).toBeInTheDocument();
65
+ expect(i18nProvider.dataset.locale).toBe(undefined);
66
+ expect(i18nProvider).toHaveTextContent("Test content");
67
+ });
68
+
69
+ it("should render I18nProvider without locale when locale is undefined", () => {
70
+ const store = createStore();
71
+ const config = parseUserConfig({ display: { locale: undefined } });
72
+ store.set(userConfigAtom, config);
73
+
74
+ const { getByTestId } = render(
75
+ <Provider store={store}>
76
+ <LocaleProvider>
77
+ <div>Test content</div>
78
+ </LocaleProvider>
79
+ </Provider>,
80
+ );
81
+
82
+ const i18nProvider = getByTestId("i18n-provider");
83
+ expect(i18nProvider).toBeInTheDocument();
84
+ expect(i18nProvider.dataset.locale).toBe(undefined);
85
+ expect(i18nProvider).toHaveTextContent("Test content");
86
+ });
87
+
88
+ it("should render I18nProvider with locale when locale is provided", () => {
89
+ const store = createStore();
90
+ const testLocale = "es-ES";
91
+ const config = parseUserConfig({ display: { locale: testLocale } });
92
+ store.set(userConfigAtom, config);
93
+
94
+ const { getByTestId } = render(
95
+ <Provider store={store}>
96
+ <LocaleProvider>
97
+ <div>Test content</div>
98
+ </LocaleProvider>
99
+ </Provider>,
100
+ );
101
+
102
+ const i18nProvider = getByTestId("i18n-provider");
103
+ expect(i18nProvider).toBeInTheDocument();
104
+ expect(i18nProvider.dataset.locale).toBe(testLocale);
105
+ expect(i18nProvider).toHaveTextContent("Test content");
106
+ });
107
+
108
+ it("should render I18nProvider with different locale values", () => {
109
+ const testCases = ["en-US", "fr-FR", "de-DE", "ja-JP"];
110
+
111
+ testCases.forEach((locale) => {
112
+ const store = createStore();
113
+ const config = parseUserConfig({ display: { locale } });
114
+ store.set(userConfigAtom, config);
115
+
116
+ const { getByTestId } = render(
117
+ <Provider store={store}>
118
+ <LocaleProvider>
119
+ <div>Test content for {locale}</div>
120
+ </LocaleProvider>
121
+ </Provider>,
122
+ );
123
+
124
+ const i18nProvider = getByTestId("i18n-provider");
125
+ expect(i18nProvider.dataset.locale).toBe(locale);
126
+ expect(i18nProvider).toHaveTextContent(`Test content for ${locale}`);
127
+
128
+ // Clean up after each iteration
129
+ cleanup();
130
+ });
131
+ });
132
+
133
+ it("should render children correctly", () => {
134
+ const store = createStore();
135
+ const config = parseUserConfig({ display: { locale: "en-US" } });
136
+ store.set(userConfigAtom, config);
137
+
138
+ const { getByText, getByRole } = render(
139
+ <Provider store={store}>
140
+ <LocaleProvider>
141
+ <div>
142
+ <h1>Test Heading</h1>
143
+ <p>Test paragraph</p>
144
+ <button type="button">Test Button</button>
145
+ </div>
146
+ </LocaleProvider>
147
+ </Provider>,
148
+ );
149
+
150
+ expect(getByText("Test Heading")).toBeInTheDocument();
151
+ expect(getByText("Test paragraph")).toBeInTheDocument();
152
+ expect(getByRole("button", { name: "Test Button" })).toBeInTheDocument();
153
+ });
154
+
155
+ it("should auto-detect locale when no locale is set in config", () => {
156
+ mockNavigatorLanguage = "de-DE";
157
+
158
+ const store = createStore();
159
+ const config = parseUserConfig({});
160
+ store.set(userConfigAtom, config);
161
+
162
+ const { getByTestId } = render(
163
+ <Provider store={store}>
164
+ <LocaleProvider>
165
+ <div>Test content</div>
166
+ </LocaleProvider>
167
+ </Provider>,
168
+ );
169
+
170
+ const i18nProvider = getByTestId("i18n-provider");
171
+ expect(i18nProvider).toBeInTheDocument();
172
+ // When no locale is specified in config, it should use navigator.language
173
+ expect(i18nProvider.dataset.locale).toBe("de-DE");
174
+ expect(i18nProvider).toHaveTextContent("Test content");
175
+ });
176
+ });
@@ -0,0 +1,35 @@
1
+ /* Copyright 2024 Marimo. All rights reserved. */
2
+
3
+ import { useAtomValue } from "jotai";
4
+ import type { ReactNode } from "react";
5
+ import { I18nProvider } from "react-aria-components";
6
+ import { localeAtom } from "@/core/config/config";
7
+
8
+ interface LocaleProviderProps {
9
+ children: ReactNode;
10
+ }
11
+
12
+ export const LocaleProvider = ({ children }: LocaleProviderProps) => {
13
+ const locale = useAtomValue(localeAtom);
14
+
15
+ return <I18nProvider locale={safeLocale(locale)}>{children}</I18nProvider>;
16
+ };
17
+
18
+ function safeLocale(locale: string | null | undefined) {
19
+ if (!locale) {
20
+ return navigator.language;
21
+ }
22
+ if (isValidLocale(locale)) {
23
+ return locale;
24
+ }
25
+ return navigator.language;
26
+ }
27
+
28
+ function isValidLocale(locale: string) {
29
+ try {
30
+ new Intl.NumberFormat(locale);
31
+ return true;
32
+ } catch {
33
+ return false;
34
+ }
35
+ }
@@ -0,0 +1,12 @@
1
+ /* Copyright 2024 Marimo. All rights reserved. */
2
+
3
+ import { useLocale } from "react-aria";
4
+
5
+ export const WithLocale = ({
6
+ children,
7
+ }: {
8
+ children: (locale: string) => React.ReactNode;
9
+ }) => {
10
+ const { locale } = useLocale();
11
+ return children(locale);
12
+ };
@@ -7,6 +7,7 @@ import { ErrorBoundary } from "@/components/editor/boundary/ErrorBoundary";
7
7
  import { TooltipProvider } from "@/components/ui/tooltip";
8
8
  import { notebookAtom } from "@/core/cells/cells";
9
9
  import { UI_ELEMENT_REGISTRY } from "@/core/dom/uiregistry";
10
+ import { LocaleProvider } from "@/core/i18n/locale-provider";
10
11
  import { renderHTML } from "@/plugins/core/RenderHTML";
11
12
  import { invariant } from "@/utils/invariant";
12
13
  import type { CellId } from "../../cells/ids";
@@ -80,16 +81,18 @@ export class MarimoIslandElement extends HTMLElement {
80
81
  this.root?.render(
81
82
  <ErrorBoundary>
82
83
  <Provider store={store}>
83
- <TooltipProvider>
84
- <MarimoOutputWrapper
85
- cellId={this.cellId}
86
- codeCallback={codeCallback}
87
- alwaysShowRun={alwaysShowRun}
88
- >
89
- {initialHtml}
90
- </MarimoOutputWrapper>
91
- {editor}
92
- </TooltipProvider>
84
+ <LocaleProvider>
85
+ <TooltipProvider>
86
+ <MarimoOutputWrapper
87
+ cellId={this.cellId}
88
+ codeCallback={codeCallback}
89
+ alwaysShowRun={alwaysShowRun}
90
+ >
91
+ {initialHtml}
92
+ </MarimoOutputWrapper>
93
+ {editor}
94
+ </TooltipProvider>
95
+ </LocaleProvider>
93
96
  </Provider>
94
97
  </ErrorBoundary>,
95
98
  );
@@ -29,8 +29,11 @@ export class RuntimeState {
29
29
  * ObjectIds of UIElements whose values need to be updated in the kernel
30
30
  */
31
31
  private _sendComponentValues: RunRequests["sendComponentValues"] | undefined;
32
+ private uiElementRegistry: UIElementRegistry;
32
33
 
33
- constructor(private uiElementRegistry: UIElementRegistry) {}
34
+ constructor(uiElementRegistry: UIElementRegistry) {
35
+ this.uiElementRegistry = uiElementRegistry;
36
+ }
34
37
 
35
38
  private get sendComponentValues(): RunRequests["sendComponentValues"] {
36
39
  if (!this._sendComponentValues) {
@@ -46,9 +46,9 @@ export type Capabilities = OperationMessageData<"kernel-ready">["capabilities"];
46
46
  export type MessageOperationUnion = schemas["KnownUnions"]["operation"];
47
47
 
48
48
  export type OperationMessageType = MessageOperationUnion["op"];
49
- export type OperationMessage = {
49
+ export interface OperationMessage {
50
50
  data: MessageOperationUnion;
51
- };
51
+ }
52
52
 
53
53
  export type OperationMessageData<T extends OperationMessageType> = Omit<
54
54
  Extract<MessageOperationUnion, { op: T }>,
@@ -18,17 +18,29 @@ export const RequestId = {
18
18
  */
19
19
  export class DeferredRequestRegistry<REQ, RES> {
20
20
  public requests = new Map<RequestId, Deferred<RES>>();
21
+ public operation: string;
22
+ private makeRequest: (id: RequestId, req: REQ) => Promise<void>;
23
+ private opts: {
24
+ /**
25
+ * Resolve existing requests with an empty response.
26
+ */
27
+ resolveExistingRequests?: () => RES;
28
+ };
21
29
 
22
30
  constructor(
23
- public operation: string,
24
- private makeRequest: (id: RequestId, req: REQ) => Promise<void>,
25
- private opts: {
31
+ operation: string,
32
+ makeRequest: (id: RequestId, req: REQ) => Promise<void>,
33
+ opts: {
26
34
  /**
27
35
  * Resolve existing requests with an empty response.
28
36
  */
29
37
  resolveExistingRequests?: () => RES;
30
38
  } = {},
31
- ) {}
39
+ ) {
40
+ this.operation = operation;
41
+ this.makeRequest = makeRequest;
42
+ this.opts = opts;
43
+ }
32
44
 
33
45
  async request(opts: REQ): Promise<RES> {
34
46
  if (this.opts.resolveExistingRequests) {
@@ -10,11 +10,12 @@ import type { RuntimeConfig } from "./types";
10
10
 
11
11
  export class RuntimeManager {
12
12
  private initialHealthyCheck = new Deferred<void>();
13
+ private config: RuntimeConfig;
14
+ private lazy: boolean;
13
15
 
14
- constructor(
15
- private config: RuntimeConfig,
16
- private lazy = false,
17
- ) {
16
+ constructor(config: RuntimeConfig, lazy = false) {
17
+ this.config = config;
18
+ this.lazy = lazy;
18
19
  // Validate the URL on construction
19
20
  try {
20
21
  new URL(this.config.url);
@@ -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> = {
@@ -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,
@@ -8,6 +8,7 @@
8
8
  * component. The factory handles the logic of communicating UI element values
9
9
  * to and from the rest of marimo.
10
10
  */
11
+ import { Provider } from "jotai";
11
12
  import React, {
12
13
  createRef,
13
14
  type JSX,
@@ -29,6 +30,7 @@ import { createInputEvent, MarimoValueUpdateEvent } from "@/core/dom/events";
29
30
  import { getUIElementObjectId } from "@/core/dom/ui-element";
30
31
  import { UIElementRegistry } from "@/core/dom/uiregistry";
31
32
  import { FUNCTIONS_REGISTRY } from "@/core/functions/FunctionRegistry";
33
+ import { LocaleProvider } from "@/core/i18n/locale-provider";
32
34
  import { store } from "@/core/state/jotai";
33
35
  import {
34
36
  type HTMLElementNotDerivedFromRef,
@@ -363,16 +365,20 @@ export function registerReactComponent<T>(plugin: IPlugin<T, unknown>): void {
363
365
 
364
366
  invariant(this.root, "Root must be defined");
365
367
  this.root.render(
366
- <PluginSlot
367
- hostElement={this}
368
- plugin={plugin}
369
- ref={this.pluginRef}
370
- getInitialValue={() => {
371
- return parseInitialValue(this, UIElementRegistry.INSTANCE);
372
- }}
373
- >
374
- {this.getChildren()}
375
- </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>,
376
382
  );
377
383
  }
378
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}
@@ -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>