@marimo-team/frontend 0.16.0 → 0.16.2

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 (284) hide show
  1. package/dist/assets/ConnectedDataExplorerComponent-B5cPvWoQ.js +19 -0
  2. package/dist/assets/{ImageComparisonComponent-fTHv1Ih0.js → ImageComparisonComponent-CqR26LSv.js} +1 -1
  3. package/dist/assets/{VegaLite-Bdi-TyfY.js → VegaLite-DvQDATwI.js} +1 -1
  4. package/dist/assets/_baseEach--KDTwKbG.js +1 -0
  5. package/dist/assets/_baseMap-Cu3o-eyO.js +1 -0
  6. package/dist/assets/{_baseUniq-CCgDNtZb.js → _baseUniq-y7ZXnMo1.js} +1 -1
  7. package/dist/assets/{_createAggregator-DcD0kTA5.js → _createAggregator-ZcHkHPNJ.js} +1 -1
  8. package/dist/assets/{agent-panel-Crv430aI.js → agent-panel-B91RoLct.js} +76 -57
  9. package/dist/assets/{any-language-editor-CQh552Wu.js → any-language-editor-CxfHcm5h.js} +1 -1
  10. package/dist/assets/{architectureDiagram-W76B3OCA-BAJeBxzt.js → architectureDiagram-W76B3OCA-BQsvK8uR.js} +1 -1
  11. package/dist/assets/{between-horizontal-start-Boxgxbt_.js → between-horizontal-start-BmYToIaM.js} +1 -1
  12. package/dist/assets/{blockDiagram-QIGZ2CNN-CL-1svEK.js → blockDiagram-QIGZ2CNN-r3HgCj4w.js} +1 -1
  13. package/dist/assets/{c4Diagram-FPNF74CW-BbEqbCTl.js → c4Diagram-FPNF74CW-BJbPNt41.js} +1 -1
  14. package/dist/assets/channel-DFaEx1fu.js +1 -0
  15. package/dist/assets/chat-panel-IoPMv8e2.js +3 -0
  16. package/dist/assets/{chunk-4BX2VUAB-C--8TXeE.js → chunk-4BX2VUAB-Dv4MZ9Hj.js} +1 -1
  17. package/dist/assets/{chunk-55IACEB6-Bj00HDqq.js → chunk-55IACEB6-CM4AHquB.js} +1 -1
  18. package/dist/assets/{chunk-FMBD7UC4-C-lhB6hN.js → chunk-FMBD7UC4-C_Zz0ENB.js} +1 -1
  19. package/dist/assets/{chunk-K7UQS3LO-B-pGTXPt.js → chunk-K7UQS3LO-DYSmiXYq.js} +1 -1
  20. package/dist/assets/{chunk-QN33PNHL-DqUzGhvm.js → chunk-QN33PNHL-QM4OPuQP.js} +1 -1
  21. package/dist/assets/{chunk-QZHKN3VN-TntJHfSk.js → chunk-QZHKN3VN-CfAsGyeB.js} +1 -1
  22. package/dist/assets/{chunk-TVAH2DTR-HUJb1psV.js → chunk-TVAH2DTR-6j_Cpjsi.js} +1 -1
  23. package/dist/assets/{chunk-TZMSLE5B-BK3C__t3.js → chunk-TZMSLE5B-BHslFJQE.js} +1 -1
  24. package/dist/assets/{circle-play-DBLOv1Yu.js → circle-play-CK3UZRYQ.js} +1 -1
  25. package/dist/assets/classDiagram-KNZD7YFC-BsZtvV5O.js +1 -0
  26. package/dist/assets/classDiagram-v2-RKCZMP56-BsZtvV5O.js +1 -0
  27. package/dist/assets/{clear-button-BeoFbEKH.js → clear-button-C4fDVSv8.js} +1 -1
  28. package/dist/assets/clone-YBEvPE-s.js +1 -0
  29. package/dist/assets/command-palette-D7hOfvf6.js +1 -0
  30. package/dist/assets/{common-C7oJcmCT.js → common-D-lbuUwz.js} +1 -1
  31. package/dist/assets/{compile-7L0MwhyI.js → compile-DVQe1Mzk.js} +1 -1
  32. package/dist/assets/{cose-bilkent-S5V4N54A-BMkGLcVC.js → cose-bilkent-S5V4N54A-D-IS7WC8.js} +1 -1
  33. package/dist/assets/{dagre-5GWH7T2D-BJtRienS.js → dagre-5GWH7T2D-lYu-tEWT.js} +1 -1
  34. package/dist/assets/{data-grid-overlay-editor-DBkmGtNs.js → data-grid-overlay-editor-C5peOCit.js} +1 -1
  35. package/dist/assets/datasources-panel-D3NA20uZ.js +1 -0
  36. package/dist/assets/{dependency-graph-panel-DEdOxp2X.js → dependency-graph-panel-BGVYOfkV.js} +1 -1
  37. package/dist/assets/{diagram-N5W7TBWH-CmECY3nb.js → diagram-N5W7TBWH-BnvIuYUp.js} +1 -1
  38. package/dist/assets/{diagram-QEK2KX5R-DMOVSNKD.js → diagram-QEK2KX5R-DemedRK3.js} +1 -1
  39. package/dist/assets/{diagram-S2PKOQOG-BiJ96PNQ.js → diagram-S2PKOQOG-iiY7AuyH.js} +1 -1
  40. package/dist/assets/{documentation-panel-xULhaEv3.js → documentation-panel-C3dSwOSQ.js} +1 -1
  41. package/dist/assets/edit-page-C5TsEeSo.js +129 -0
  42. package/dist/assets/{ellipsis-vertical-BBqXIlc2.js → ellipsis-vertical-CazJl8M7.js} +1 -1
  43. package/dist/assets/{empty-state-B3dA3G5P.js → empty-state-DW308mFO.js} +1 -1
  44. package/dist/assets/{erDiagram-AWTI2OKA-MP1DiFRo.js → erDiagram-AWTI2OKA-6wQ8Ugg0.js} +1 -1
  45. package/dist/assets/{error-panel-Cc1sv-Ag.js → error-panel-D1VnJ1yP.js} +1 -1
  46. package/dist/assets/file-explorer-panel-0oVd4t-D.js +1 -0
  47. package/dist/assets/{flowDiagram-PVAE7QVJ-BX7caPp7.js → flowDiagram-PVAE7QVJ-C55IUWjm.js} +1 -1
  48. package/dist/assets/{ganttDiagram-OWAHRB6G-B462g4Yf.js → ganttDiagram-OWAHRB6G-DmqCM6ME.js} +4 -4
  49. package/dist/assets/{gitGraphDiagram-NY62KEGX-CGgvZ9-9.js → gitGraphDiagram-NY62KEGX-DBvhAeM_.js} +1 -1
  50. package/dist/assets/{glide-data-editor-C0gUFZON.js → glide-data-editor-CHNuHidQ.js} +4 -4
  51. package/dist/assets/{graph-CHRVBzY5.js → graph-CG6BgUWQ.js} +1 -1
  52. package/dist/assets/home-page-dgivXuSR.js +9 -0
  53. package/dist/assets/{index-Clbi_Yaq.js → index-BTGpssVX.js} +1 -1
  54. package/dist/assets/{index-CQDrxQ0j.js → index-BYVZlBF8.js} +1 -1
  55. package/dist/assets/{index-lYa_leQE.js → index-BelfnXwL.js} +1 -1
  56. package/dist/assets/{index-DRMm6SNo.js → index-BneyUujp.js} +1 -1
  57. package/dist/assets/{index-BY93Ejhl.js → index-C02SqeRj.js} +1 -1
  58. package/dist/assets/{index-C-8WADat.js → index-C7dtgr9A.js} +1 -1
  59. package/dist/assets/{index-D9UKkrr2.js → index-CAQvMTzM.js} +1 -1
  60. package/dist/assets/index-CGDMlQfO.css +1 -0
  61. package/dist/assets/index-CelXfcd8.js +580 -0
  62. package/dist/assets/{index-vmICa5KN.js → index-Csd6QrCV.js} +1 -1
  63. package/dist/assets/{index-DoRmcrKM.js → index-CtPksxf0.js} +1 -1
  64. package/dist/assets/{index-C1v_Z9et.js → index-Cxyk7pt-.js} +1 -1
  65. package/dist/assets/{index-CpTPJo4k.js → index-DAZ-9ri2.js} +1 -1
  66. package/dist/assets/{index-DEQvTChO.js → index-DONRrmA2.js} +1 -1
  67. package/dist/assets/{index-C4Tn5NvJ.js → index-Db36XTG_.js} +1 -1
  68. package/dist/assets/{index-z9bohSQJ.js → index-DdIhdEVw.js} +1 -1
  69. package/dist/assets/{index-C-GhZ7ti.js → index-M_pBKDSe.js} +1 -1
  70. package/dist/assets/{index-C77h_TXN.js → index-_luCZMLM.js} +1 -1
  71. package/dist/assets/{index-D1vmG6DS.js → index-mkubqy9-.js} +1 -1
  72. package/dist/assets/{index-BVgAenPd.js → index-sbO9UaUU.js} +1 -1
  73. package/dist/assets/{index-CWMgowgL.js → index-z4krxQ4j.js} +1 -1
  74. package/dist/assets/infoDiagram-STP46IZ2-wTALjfPc.js +2 -0
  75. package/dist/assets/{isEmpty-DU_ogP_D.js → isEmpty-CqX_YTIf.js} +1 -1
  76. package/dist/assets/{journeyDiagram-BIP6EPQ6-C6EgLP_Q.js → journeyDiagram-BIP6EPQ6-Y5w_Tqe_.js} +1 -1
  77. package/dist/assets/{kanban-definition-6OIFK2YF-BXzYO1yj.js → kanban-definition-6OIFK2YF-DbXs5Rxi.js} +1 -1
  78. package/dist/assets/{layout-jihVw5-i.js → layout-BCNPDACj.js} +1 -1
  79. package/dist/assets/{linear-C4blANlC.js → linear-uO6UVhXt.js} +1 -1
  80. package/dist/assets/links-Drv7cJgN.js +7 -0
  81. package/dist/assets/{logs-panel-D401qzZh.js → logs-panel-BEQ1eRUp.js} +1 -1
  82. package/dist/assets/{markdown-renderer-Cd9eYyaL.js → markdown-renderer-Dmzbb00W.js} +20 -20
  83. package/dist/assets/{mermaid-BEVuRz_O.js → mermaid-qRc4MXIj.js} +1 -1
  84. package/dist/assets/{mermaid.core-CaSnaLH0.js → mermaid.core-CvvJtCRj.js} +4 -4
  85. package/dist/assets/min-DYUOb1RR.js +1 -0
  86. package/dist/assets/{mindmap-definition-Q6HEUPPD-BXUM5MT2.js → mindmap-definition-Q6HEUPPD-G5NognM-.js} +1 -1
  87. package/dist/assets/{number-overlay-editor-4uWXGlPG.js → number-overlay-editor-DPr5sHFu.js} +1 -1
  88. package/dist/assets/outline-panel-gxQXvVi4.js +1 -0
  89. package/dist/assets/{packages-panel-CJL0MVlj.js → packages-panel-B1T0VPlg.js} +1 -1
  90. package/dist/assets/{pieDiagram-ADFJNKIX-Dxt5PVNo.js → pieDiagram-ADFJNKIX-DK9SHkfc.js} +1 -1
  91. package/dist/assets/{quadrantDiagram-LMRXKWRM-D4pUaA31.js → quadrantDiagram-LMRXKWRM-D1DdWF8C.js} +1 -1
  92. package/dist/assets/{react-plotly-cJZ0VWBq.js → react-plotly-CTwajqCb.js} +1 -1
  93. package/dist/assets/{requirementDiagram-4UW4RH46-DVRTjgas.js → requirementDiagram-4UW4RH46-DnjDAypr.js} +1 -1
  94. package/dist/assets/{run-page-BUEnMC9w.js → run-page-CQY9im22.js} +1 -1
  95. package/dist/assets/{sankeyDiagram-GR3RE2ED-CVFnD9C-.js → sankeyDiagram-GR3RE2ED-B67Va-ER.js} +1 -1
  96. package/dist/assets/{scratchpad-panel-BIgRENkI.js → scratchpad-panel-DlDfcDtW.js} +1 -1
  97. package/dist/assets/{secrets-panel-xY5-V_BD.js → secrets-panel-BDGyuGZA.js} +1 -1
  98. package/dist/assets/{sequenceDiagram-C3RYC4MD-_lY4ZN_S.js → sequenceDiagram-C3RYC4MD-DiWgZPtN.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-DhpPRtQp.js} +1 -1
  101. package/dist/assets/snippets-panel-CLkBXhJ2.js +1 -0
  102. package/dist/assets/sortBy-D4OG7w4O.js +1 -0
  103. package/dist/assets/{state-C4NiC9tO.js → state-Dz_3JyED.js} +1 -1
  104. package/dist/assets/{stateDiagram-KXAO66HF-Da0JQWCn.js → stateDiagram-KXAO66HF-ByF2AULw.js} +1 -1
  105. package/dist/assets/stateDiagram-v2-UMBNRL4Z-CtBJqosP.js +1 -0
  106. package/dist/assets/storage-Dr0CC44z.js +26 -0
  107. package/dist/assets/{terminal-BPwTkXae.js → terminal-BtdissBf.js} +1 -1
  108. package/dist/assets/{time-Dv5_Ouz_.js → time-DKdOTnQg.js} +1 -1
  109. package/dist/assets/{timeline-definition-XQNQX7LJ-Dxh5Zu2e.js → timeline-definition-XQNQX7LJ-DzER9bf6.js} +1 -1
  110. package/dist/assets/tracing-Dpx5M-u3.js +2 -0
  111. package/dist/assets/{tracing-panel-DAzrzNmm.js → tracing-panel-hCjBkSER.js} +2 -2
  112. package/dist/assets/{trash-Dc6DSjz_.js → trash-C6Ko-g5q.js} +1 -1
  113. package/dist/assets/{tree-jheoerAX.js → tree-BHN2gcCF.js} +6 -6
  114. package/dist/assets/{treemap-75Q7IDZK-IgpxeGaf.js → treemap-75Q7IDZK-DR79Mhzt.js} +27 -27
  115. package/dist/assets/variable-panel-PFBCFz36.js +1 -0
  116. package/dist/assets/{vega-component-BpfpiPKI.js → vega-component-Db6-uY4C.js} +1 -1
  117. package/dist/assets/worker-fHbtoWvT.js +1 -0
  118. package/dist/assets/{xychartDiagram-6GGTOJPD-CmNigJ31.js → xychartDiagram-6GGTOJPD-DWzBP3tZ.js} +1 -1
  119. package/dist/index.html +2 -2
  120. package/package.json +5 -4
  121. package/src/__mocks__/requests.ts +1 -0
  122. package/src/components/app-config/user-config-form.tsx +46 -1
  123. package/src/components/chat/acp/__tests__/__snapshots__/prompt.test.ts.snap +62 -43
  124. package/src/components/chat/acp/__tests__/atoms.test.ts +1 -1
  125. package/src/components/chat/acp/__tests__/state.test.ts +36 -36
  126. package/src/components/chat/acp/agent-panel.tsx +24 -27
  127. package/src/components/chat/acp/blocks.tsx +6 -6
  128. package/src/components/chat/acp/prompt.ts +62 -43
  129. package/src/components/chat/chat-panel.tsx +5 -1
  130. package/src/components/chat/markdown-renderer.tsx +6 -10
  131. package/src/components/chat/tool-call-accordion.tsx +52 -20
  132. package/src/components/data-table/SearchBar.tsx +8 -7
  133. package/src/components/data-table/__tests__/column_formatting.test.ts +50 -35
  134. package/src/components/data-table/__tests__/columns.test.tsx +38 -0
  135. package/src/components/data-table/__tests__/data-table.test.tsx +39 -1
  136. package/src/components/data-table/cell-hover-template/feature.ts +14 -0
  137. package/src/components/data-table/cell-hover-template/types.ts +11 -0
  138. package/src/components/data-table/charts/components/form-fields.tsx +41 -37
  139. package/src/components/data-table/charts/forms/common-chart.tsx +2 -2
  140. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +5 -2
  141. package/src/components/data-table/column-formatting/feature.ts +62 -29
  142. package/src/components/data-table/column-formatting/types.ts +1 -0
  143. package/src/components/data-table/column-header.tsx +3 -1
  144. package/src/components/data-table/column-summary/chart-spec-model.tsx +24 -7
  145. package/src/components/data-table/column-summary/column-summary.tsx +18 -9
  146. package/src/components/data-table/columns.tsx +63 -20
  147. package/src/components/data-table/data-table.tsx +10 -2
  148. package/src/components/data-table/date-popover.tsx +85 -75
  149. package/src/components/data-table/filter-pills.tsx +14 -9
  150. package/src/components/data-table/header-items.tsx +5 -1
  151. package/src/components/data-table/pagination.tsx +20 -13
  152. package/src/components/data-table/renderers.tsx +36 -0
  153. package/src/components/data-table/row-viewer-panel/row-viewer.tsx +10 -8
  154. package/src/components/data-table/schemas.ts +16 -0
  155. package/src/components/datasources/column-preview.tsx +6 -2
  156. package/src/components/datasources/datasources.tsx +8 -12
  157. package/src/components/editor/Cell.tsx +2 -0
  158. package/src/components/editor/ai/transport/chat-transport.tsx +4 -1
  159. package/src/components/editor/cell/CellStatus.tsx +23 -20
  160. package/src/components/editor/cell/CreateCellButton.tsx +3 -4
  161. package/src/components/editor/cell/code/language-toggle.tsx +3 -4
  162. package/src/components/editor/chrome/wrapper/footer-items/machine-stats.tsx +39 -28
  163. package/src/components/editor/controls/notebook-menu-dropdown.tsx +4 -2
  164. package/src/components/editor/errors/sql-validation-errors.tsx +34 -0
  165. package/src/components/editor/file-tree/requesting-tree.tsx +14 -8
  166. package/src/components/editor/output/ConsoleOutput.tsx +13 -1
  167. package/src/components/editor/output/MarimoErrorOutput.tsx +60 -1
  168. package/src/components/editor/renderers/CellArray.tsx +3 -4
  169. package/src/components/editor/renderers/slides-layout/slides-layout.tsx +3 -3
  170. package/src/components/editor/renderers/slides-layout/types.ts +1 -0
  171. package/src/components/pages/home-page.tsx +4 -1
  172. package/src/components/slides/slides-component.tsx +1 -1
  173. package/src/components/slides/slides.css +6 -0
  174. package/src/components/terminal/theme.tsx +1 -0
  175. package/src/components/tracing/tracing-spec.ts +5 -4
  176. package/src/components/ui/range-slider.tsx +4 -2
  177. package/src/components/ui/slider.tsx +3 -1
  178. package/src/components/variables/variables-table.tsx +3 -0
  179. package/src/core/MarimoApp.tsx +9 -6
  180. package/src/core/ai/context/__tests__/registry.test.ts +6 -4
  181. package/src/core/ai/context/providers/cell-output.ts +4 -20
  182. package/src/core/ai/context/providers/error.ts +3 -1
  183. package/src/core/ai/context/providers/file.ts +7 -2
  184. package/src/core/ai/context/providers/tables.ts +3 -2
  185. package/src/core/ai/context/providers/variable.ts +6 -4
  186. package/src/core/ai/staged-cells.ts +34 -1
  187. package/src/core/cells/__tests__/add-missing-import.test.ts +67 -22
  188. package/src/core/cells/add-missing-import.ts +24 -7
  189. package/src/core/cells/cells.ts +26 -27
  190. package/src/core/cells/logs.ts +1 -1
  191. package/src/core/codemirror/find-replace/search-highlight.ts +3 -1
  192. package/src/core/codemirror/language/LanguageAdapters.ts +9 -3
  193. package/src/core/codemirror/language/__tests__/extension.test.ts +24 -0
  194. package/src/core/codemirror/language/__tests__/sql-validation.test.ts +133 -0
  195. package/src/core/codemirror/language/languages/sql/sql-mode.ts +20 -0
  196. package/src/core/codemirror/language/languages/sql/sql.ts +90 -3
  197. package/src/core/codemirror/language/languages/sql/validation-errors.ts +79 -0
  198. package/src/core/codemirror/language/panel/panel.tsx +8 -2
  199. package/src/core/codemirror/language/panel/sql.tsx +81 -4
  200. package/src/core/codemirror/lsp/notebook-lsp.ts +8 -2
  201. package/src/core/codemirror/readonly/__tests__/extension.test.ts +1 -1
  202. package/src/core/codemirror/rtc/loro/awareness.ts +52 -17
  203. package/src/core/codemirror/rtc/loro/sync.ts +12 -4
  204. package/src/core/config/config-schema.ts +1 -0
  205. package/src/core/config/config.ts +4 -0
  206. package/src/core/config/feature-flag.tsx +3 -1
  207. package/src/core/datasets/request-registry.ts +17 -1
  208. package/src/core/hotkeys/hotkeys.ts +8 -4
  209. package/src/core/i18n/__tests__/locale-provider.test.tsx +176 -0
  210. package/src/core/i18n/locale-provider.tsx +35 -0
  211. package/src/core/i18n/with-locale.tsx +12 -0
  212. package/src/core/islands/bridge.ts +1 -0
  213. package/src/core/islands/components/web-components.tsx +13 -10
  214. package/src/core/islands/main.ts +1 -0
  215. package/src/core/kernel/RuntimeState.ts +4 -1
  216. package/src/core/kernel/messages.ts +3 -2
  217. package/src/core/network/DeferredRequestRegistry.ts +16 -4
  218. package/src/core/network/requests-network.ts +7 -0
  219. package/src/core/network/requests-static.ts +1 -0
  220. package/src/core/network/requests-toasting.ts +1 -0
  221. package/src/core/network/types.ts +2 -0
  222. package/src/core/runtime/runtime.ts +5 -4
  223. package/src/core/wasm/bridge.ts +10 -1
  224. package/src/core/wasm/store.ts +4 -1
  225. package/src/core/wasm/worker/message-buffer.ts +3 -2
  226. package/src/core/websocket/types.ts +22 -16
  227. package/src/core/websocket/useMarimoWebSocket.tsx +4 -0
  228. package/src/hooks/useFormatting.ts +97 -0
  229. package/src/hooks/useTimer.ts +8 -5
  230. package/src/plugins/core/registerReactComponent.tsx +39 -29
  231. package/src/plugins/impl/DataTablePlugin.tsx +15 -4
  232. package/src/plugins/impl/RangeSliderPlugin.tsx +5 -3
  233. package/src/plugins/impl/SliderPlugin.tsx +3 -1
  234. package/src/plugins/impl/anywidget/model.ts +16 -5
  235. package/src/plugins/impl/data-editor/types.ts +7 -5
  236. package/src/plugins/impl/data-explorer/components/column-summary.tsx +20 -13
  237. package/src/plugins/impl/data-frames/DataFramePlugin.tsx +17 -5
  238. package/src/plugins/impl/panel/utils.ts +6 -4
  239. package/src/plugins/layout/OutlinePlugin.tsx +69 -0
  240. package/src/plugins/layout/StatPlugin.tsx +4 -1
  241. package/src/plugins/plugins.ts +2 -0
  242. package/src/stories/dataframe.stories.tsx +2 -0
  243. package/src/utils/__tests__/dates.test.ts +45 -24
  244. package/src/utils/__tests__/dom.test.ts +167 -0
  245. package/src/utils/__tests__/numbers.test.ts +42 -30
  246. package/src/utils/__tests__/once.test.ts +187 -0
  247. package/src/utils/dates.ts +15 -10
  248. package/src/utils/dom.ts +55 -0
  249. package/src/utils/edit-distance.ts +8 -6
  250. package/src/utils/errors.ts +1 -1
  251. package/src/utils/id-tree.tsx +21 -10
  252. package/src/utils/localStorage.ts +13 -4
  253. package/src/utils/numbers.ts +11 -11
  254. package/src/utils/once.ts +32 -0
  255. package/src/utils/paths.ts +4 -1
  256. package/src/utils/pluralize.ts +12 -5
  257. package/src/utils/python-poet/poet.ts +30 -15
  258. package/src/utils/time.ts +5 -1
  259. package/dist/assets/ConnectedDataExplorerComponent-BErMbWvG.js +0 -19
  260. package/dist/assets/_baseEach-CNBxBxvS.js +0 -1
  261. package/dist/assets/_baseMap-D1WHjKrd.js +0 -1
  262. package/dist/assets/channel-_2eNSz0n.js +0 -1
  263. package/dist/assets/chat-panel-CXh5Wl6C.js +0 -3
  264. package/dist/assets/classDiagram-KNZD7YFC-BGmh9POF.js +0 -1
  265. package/dist/assets/classDiagram-v2-RKCZMP56-BGmh9POF.js +0 -1
  266. package/dist/assets/clone-BFDSPAj3.js +0 -1
  267. package/dist/assets/command-palette-CXZiSv0I.js +0 -1
  268. package/dist/assets/datasources-panel-B7FbYLiy.js +0 -1
  269. package/dist/assets/edit-page-BrYda9VE.js +0 -129
  270. package/dist/assets/file-explorer-panel-Bw59Kva1.js +0 -1
  271. package/dist/assets/home-page-Fb2osjys.js +0 -9
  272. package/dist/assets/index-Cx0bsY1w.css +0 -1
  273. package/dist/assets/index-DKEudB02.js +0 -578
  274. package/dist/assets/infoDiagram-STP46IZ2-CVyrdLc8.js +0 -2
  275. package/dist/assets/links-D59GIweI.js +0 -7
  276. package/dist/assets/min-DUMu_zeK.js +0 -1
  277. package/dist/assets/outline-panel-DIzkvm2I.js +0 -1
  278. package/dist/assets/snippets-panel-CTPYW41n.js +0 -1
  279. package/dist/assets/sortBy-BNZKwiq_.js +0 -1
  280. package/dist/assets/stateDiagram-v2-UMBNRL4Z-D5lYZOOt.js +0 -1
  281. package/dist/assets/storage-CMdLzB_c.js +0 -26
  282. package/dist/assets/tracing-BCIurUfa.js +0 -2
  283. package/dist/assets/variable-panel-DYAiLBmF.js +0 -1
  284. package/dist/assets/worker-X5rxzQGQ.js +0 -1
@@ -1,6 +1,6 @@
1
1
  /* Copyright 2024 Marimo. All rights reserved. */
2
2
  import type { ColumnDef, RowSelectionState } from "@tanstack/react-table";
3
- import { render } from "@testing-library/react";
3
+ import { render, screen } from "@testing-library/react";
4
4
  import { describe, expect, it, vi } from "vitest";
5
5
  import { TooltipProvider } from "@/components/ui/tooltip";
6
6
  import { DataTable } from "../data-table";
@@ -57,4 +57,42 @@ describe("DataTable", () => {
57
57
  // Verify the rowSelection prop is maintained
58
58
  expect(commonProps.rowSelection).toEqual(initialRowSelection);
59
59
  });
60
+
61
+ it("applies hoverTemplate to the row title using row values", () => {
62
+ interface RowData {
63
+ id: number;
64
+ first: string;
65
+ last: string;
66
+ }
67
+
68
+ const testData: RowData[] = [
69
+ { id: 1, first: "Michael", last: "Scott" },
70
+ { id: 2, first: "Jim", last: "Halpert" },
71
+ ];
72
+
73
+ const columns: Array<ColumnDef<RowData>> = [
74
+ { accessorKey: "first", header: "First" },
75
+ { accessorKey: "last", header: "Last" },
76
+ ];
77
+
78
+ render(
79
+ <TooltipProvider>
80
+ <DataTable
81
+ data={testData}
82
+ columns={columns}
83
+ selection={null}
84
+ totalRows={2}
85
+ totalColumns={2}
86
+ pagination={false}
87
+ hoverTemplate={"{{first}} {{last}}"}
88
+ />
89
+ </TooltipProvider>,
90
+ );
91
+
92
+ // Grab all rows and assert title attribute computed from template
93
+ const rows = screen.getAllByRole("row");
94
+ // The first row is header; subsequent rows correspond to data
95
+ expect(rows[1]).toHaveAttribute("title", "Michael Scott");
96
+ expect(rows[2]).toHaveAttribute("title", "Jim Halpert");
97
+ });
60
98
  });
@@ -0,0 +1,14 @@
1
+ /* Copyright 2024 Marimo. All rights reserved. */
2
+ "use no memo";
3
+
4
+ import type { InitialTableState, TableFeature } from "@tanstack/react-table";
5
+ import type { CellHoverTemplateTableState } from "./types";
6
+
7
+ export const CellHoverTemplateFeature: TableFeature = {
8
+ getInitialState: (state?: InitialTableState): CellHoverTemplateTableState => {
9
+ return {
10
+ ...state,
11
+ cellHoverTemplate: null,
12
+ };
13
+ },
14
+ };
@@ -0,0 +1,11 @@
1
+ /* Copyright 2024 Marimo. All rights reserved. */
2
+ /* eslint-disable @typescript-eslint/no-empty-interface */
3
+
4
+ export interface CellHoverTemplateTableState {
5
+ cellHoverTemplate: string | null;
6
+ }
7
+
8
+ // Use declaration merging to add our new feature APIs
9
+ declare module "@tanstack/react-table" {
10
+ interface TableState extends CellHoverTemplateTableState {}
11
+ }
@@ -342,7 +342,7 @@ interface SliderFieldProps {
342
342
  fieldName: FieldName;
343
343
  label: string;
344
344
  className?: string;
345
- value: number;
345
+ defaultValue: number;
346
346
  start: number;
347
347
  stop: number;
348
348
  step?: number;
@@ -351,53 +351,57 @@ interface SliderFieldProps {
351
351
  export const SliderField = ({
352
352
  fieldName,
353
353
  label,
354
- value,
354
+ defaultValue,
355
355
  start,
356
356
  stop,
357
357
  step,
358
358
  className,
359
359
  }: SliderFieldProps) => {
360
- const [internalValue, setInternalValue] = React.useState(value);
361
360
  const form = useFormContext();
362
361
 
363
- // Update internal value on prop change
364
- React.useEffect(() => {
365
- setInternalValue(value);
366
- }, [value]);
367
-
368
362
  return (
369
363
  <FormField
370
364
  control={form.control}
371
365
  name={fieldName}
372
- render={({ field }) => (
373
- <FormItem
374
- className={cn("flex flex-row items-center gap-2 w-1/2", className)}
375
- >
376
- <FormLabel>{label}</FormLabel>
377
- <FormControl>
378
- <Slider
379
- {...field}
380
- id={fieldName}
381
- className="relative flex items-center select-none"
382
- value={[internalValue]}
383
- min={start}
384
- max={stop}
385
- step={step}
386
- // Triggered on slider drag
387
- onValueChange={([nextValue]) => {
388
- setInternalValue(nextValue);
389
- field.onChange(nextValue);
390
- }}
391
- // Triggered on mouse up
392
- onValueCommit={([nextValue]) => {
393
- field.onChange(nextValue);
394
- form.setValue(fieldName, nextValue);
395
- }}
396
- valueMap={(value) => value}
397
- />
398
- </FormControl>
399
- </FormItem>
400
- )}
366
+ render={({ field }) => {
367
+ const currentValue = field.value ?? defaultValue;
368
+ const numericValue = Number(currentValue);
369
+
370
+ const saveValue = (value: number | string) => {
371
+ if (typeof value === "string") {
372
+ value = Number(value);
373
+ }
374
+ field.onChange(value);
375
+ };
376
+
377
+ return (
378
+ <FormItem
379
+ className={cn("flex flex-row items-center gap-2 w-1/2", className)}
380
+ >
381
+ <FormLabel>{label}</FormLabel>
382
+ <FormControl>
383
+ <Slider
384
+ {...field}
385
+ id={fieldName}
386
+ className="relative flex items-center select-none"
387
+ value={[numericValue]}
388
+ min={start}
389
+ max={stop}
390
+ step={step}
391
+ // Triggered on slider drag
392
+ onValueChange={([nextValue]) => {
393
+ saveValue(nextValue);
394
+ }}
395
+ // Triggered on mouse up
396
+ onValueCommit={([nextValue]) => {
397
+ saveValue(nextValue);
398
+ }}
399
+ valueMap={(value) => value}
400
+ />
401
+ </FormControl>
402
+ </FormItem>
403
+ );
404
+ }}
401
405
  />
402
406
  );
403
407
  };
@@ -102,7 +102,7 @@ export const StyleForm: React.FC = () => {
102
102
  <SliderField
103
103
  fieldName="xAxis.width"
104
104
  label="Width"
105
- value={400}
105
+ defaultValue={400}
106
106
  start={200}
107
107
  stop={800}
108
108
  />
@@ -118,7 +118,7 @@ export const StyleForm: React.FC = () => {
118
118
  <SliderField
119
119
  fieldName="yAxis.height"
120
120
  label="Height"
121
- value={300}
121
+ defaultValue={300}
122
122
  start={150}
123
123
  stop={600}
124
124
  />
@@ -1,6 +1,7 @@
1
1
  /* Copyright 2024 Marimo. All rights reserved. */
2
2
 
3
3
  import { useState } from "react";
4
+ import { useLocale } from "react-aria";
4
5
  import {
5
6
  AddDataframeChart,
6
7
  renderChart,
@@ -53,6 +54,7 @@ export const ColumnExplorerPanel = ({
53
54
  tableId,
54
55
  }: ColumnExplorerPanelProps) => {
55
56
  const [searchValue, setSearchValue] = useState("");
57
+ const { locale } = useLocale();
56
58
  const columns = fieldTypes?.filter(([columnName]) => {
57
59
  if (
58
60
  columnName === SELECT_COLUMN_ID ||
@@ -71,7 +73,7 @@ export const ColumnExplorerPanel = ({
71
73
  return (
72
74
  <div className="mt-5 mb-3">
73
75
  <span className="text-xs font-semibold ml-2 flex">
74
- {prettifyRowColumnCount(totalRows, totalColumns)}
76
+ {prettifyRowColumnCount(totalRows, totalColumns, locale)}
75
77
  <CopyClipboardIcon
76
78
  tooltip="Copy column names"
77
79
  value={columns?.map(([columnName]) => columnName).join(",\n") || ""}
@@ -169,6 +171,7 @@ const ColumnPreview = ({
169
171
  dataType: DataType;
170
172
  }) => {
171
173
  const { theme } = useTheme();
174
+ const { locale } = useLocale();
172
175
 
173
176
  const {
174
177
  data,
@@ -208,7 +211,7 @@ const ColumnPreview = ({
208
211
  refetchPreview,
209
212
  });
210
213
 
211
- const previewStats = stats && renderStats(stats, dataType);
214
+ const previewStats = stats && renderStats(stats, dataType, locale);
212
215
 
213
216
  const chart = chart_spec && renderChart(chart_spec, theme);
214
217
 
@@ -16,6 +16,7 @@ import {
16
16
  prettyNumber,
17
17
  prettyScientificNumber,
18
18
  } from "@/utils/numbers";
19
+ import { memoizeLastValue } from "@/utils/once";
19
20
  import type {
20
21
  ColumnFormattingOptions,
21
22
  ColumnFormattingState,
@@ -39,6 +40,7 @@ export const ColumnFormattingFeature: TableFeature = {
39
40
  return {
40
41
  enableColumnFormatting: true,
41
42
  onColumnFormattingChange: makeStateUpdater("columnFormatting", table),
43
+ locale: navigator.language,
42
44
  } as ColumnFormattingOptions;
43
45
  },
44
46
 
@@ -74,36 +76,50 @@ export const ColumnFormattingFeature: TableFeature = {
74
76
  const dataType = column.columnDef.meta?.dataType;
75
77
  const format = column.getColumnFormatting?.();
76
78
  if (format) {
77
- return applyFormat(value, { format, dataType });
79
+ return applyFormat(value, {
80
+ format,
81
+ dataType,
82
+ locale: table.options.locale,
83
+ });
78
84
  }
79
85
  return value;
80
86
  };
81
87
  },
82
88
  };
83
89
 
84
- const percentFormatter = new Intl.NumberFormat(undefined, {
85
- style: "percent",
86
- minimumFractionDigits: 0,
87
- maximumFractionDigits: 2,
88
- });
90
+ export const getFormatters = memoizeLastValue((locale: string) => {
91
+ const percentFormatter = new Intl.NumberFormat(locale, {
92
+ style: "percent",
93
+ minimumFractionDigits: 0,
94
+ maximumFractionDigits: 2,
95
+ });
89
96
 
90
- const dateFormatter = new Intl.DateTimeFormat(undefined, {
91
- dateStyle: "short", // 3/4/2024
92
- });
97
+ const dateFormatter = new Intl.DateTimeFormat(locale, {
98
+ dateStyle: "short", // 3/4/2024
99
+ });
93
100
 
94
- const dateTimeFormatter = new Intl.DateTimeFormat(undefined, {
95
- dateStyle: "short", // 3/4/2024
96
- timeStyle: "long", // 3:04:05 PM
97
- timeZone: "UTC",
98
- });
101
+ const dateTimeFormatter = new Intl.DateTimeFormat(locale, {
102
+ dateStyle: "short", // 3/4/2024
103
+ timeStyle: "long", // 3:04:05 PM
104
+ timeZone: "UTC",
105
+ });
99
106
 
100
- const timeFormatter = new Intl.DateTimeFormat(undefined, {
101
- timeStyle: "long", // 3:04:05 PM
102
- timeZone: "UTC",
103
- });
107
+ const timeFormatter = new Intl.DateTimeFormat(locale, {
108
+ timeStyle: "long", // 3:04:05 PM
109
+ timeZone: "UTC",
110
+ });
104
111
 
105
- const integerFormatter = new Intl.NumberFormat(undefined, {
106
- maximumFractionDigits: 0, // 1,000,000
112
+ const integerFormatter = new Intl.NumberFormat(locale, {
113
+ maximumFractionDigits: 0, // 1,000,000
114
+ });
115
+
116
+ return {
117
+ percentFormatter,
118
+ dateFormatter,
119
+ dateTimeFormatter,
120
+ timeFormatter,
121
+ integerFormatter,
122
+ };
107
123
  });
108
124
 
109
125
  // Apply formatting to a value given a format and data type
@@ -112,9 +128,18 @@ export const applyFormat = (
112
128
  options: {
113
129
  format: FormatOption;
114
130
  dataType: DataType | undefined;
131
+ locale: string;
115
132
  },
116
133
  ) => {
117
- const { format, dataType } = options;
134
+ const { format, dataType, locale } = options;
135
+ const {
136
+ percentFormatter,
137
+ dateFormatter,
138
+ dateTimeFormatter,
139
+ timeFormatter,
140
+ integerFormatter,
141
+ } = getFormatters(locale);
142
+
118
143
  // If the value is null, return an empty string
119
144
  if (value === null || value === undefined || value === "") {
120
145
  return "";
@@ -143,13 +168,13 @@ export const applyFormat = (
143
168
  const num = Number.parseFloat(value as string);
144
169
  switch (format) {
145
170
  case "Auto":
146
- return prettyNumber(num);
171
+ return prettyNumber(num, locale);
147
172
  case "Percent":
148
173
  return percentFormatter.format(num);
149
174
  case "Scientific":
150
- return prettyScientificNumber(num, { shouldRound: true });
175
+ return prettyScientificNumber(num, { shouldRound: true, locale });
151
176
  case "Engineering":
152
- return prettyEngineeringNumber(num);
177
+ return prettyEngineeringNumber(num, locale);
153
178
  case "Integer":
154
179
  return integerFormatter.format(num);
155
180
  default:
@@ -198,32 +223,35 @@ export const applyFormat = (
198
223
 
199
224
  export function formattingExample(
200
225
  format: FormatOption,
226
+ locale: string,
201
227
  ): string | number | undefined | null {
202
228
  switch (format) {
203
229
  case "Date":
204
230
  return String(
205
- applyFormat(new Date(), { format: "Date", dataType: "date" }),
231
+ applyFormat(new Date(), { format: "Date", dataType: "date", locale }),
206
232
  );
207
233
  case "Datetime":
208
234
  return String(
209
235
  applyFormat(new Date(), {
210
236
  format: "Datetime",
211
237
  dataType: "date",
238
+ locale,
212
239
  }),
213
240
  );
214
241
  case "Time":
215
242
  return String(
216
- applyFormat(new Date(), { format: "Time", dataType: "date" }),
243
+ applyFormat(new Date(), { format: "Time", dataType: "date", locale }),
217
244
  );
218
245
  case "Percent":
219
246
  return String(
220
- applyFormat(0.1234, { format: "Percent", dataType: "number" }),
247
+ applyFormat(0.1234, { format: "Percent", dataType: "number", locale }),
221
248
  );
222
249
  case "Scientific":
223
250
  return String(
224
251
  applyFormat(12_345_678_910, {
225
252
  format: "Scientific",
226
253
  dataType: "number",
254
+ locale,
227
255
  }),
228
256
  );
229
257
  case "Engineering":
@@ -231,15 +259,20 @@ export function formattingExample(
231
259
  applyFormat(12_345_678_910, {
232
260
  format: "Engineering",
233
261
  dataType: "number",
262
+ locale,
234
263
  }),
235
264
  );
236
265
  case "Integer":
237
266
  return String(
238
- applyFormat(1234.567, { format: "Integer", dataType: "number" }),
267
+ applyFormat(1234.567, {
268
+ format: "Integer",
269
+ dataType: "number",
270
+ locale,
271
+ }),
239
272
  );
240
273
  case "Auto":
241
274
  return String(
242
- applyFormat(1234.567, { format: "Auto", dataType: "number" }),
275
+ applyFormat(1234.567, { format: "Auto", dataType: "number", locale }),
243
276
  );
244
277
  default:
245
278
  return null;
@@ -28,6 +28,7 @@ export interface ColumnFormattingTableState {
28
28
 
29
29
  // define types for column formatting's table options
30
30
  export interface ColumnFormattingOptions {
31
+ locale: string;
31
32
  enableColumnFormatting?: boolean;
32
33
  onColumnFormattingChange?: OnChangeFn<ColumnFormattingState>;
33
34
  }
@@ -5,6 +5,7 @@ import type { Column } from "@tanstack/react-table";
5
5
  import { capitalize } from "lodash-es";
6
6
  import { FilterIcon, MinusIcon, TextIcon, XIcon } from "lucide-react";
7
7
  import { useMemo, useRef, useState } from "react";
8
+ import { useLocale } from "react-aria";
8
9
  import {
9
10
  DropdownMenu,
10
11
  DropdownMenuContent,
@@ -76,6 +77,7 @@ export const DataTableColumnHeader = <TData, TValue>({
76
77
  calculateTopKRows,
77
78
  }: DataTableColumnHeaderProps<TData, TValue>) => {
78
79
  const [isFilterValueOpen, setIsFilterValueOpen] = useState(false);
80
+ const { locale } = useLocale();
79
81
 
80
82
  // No header
81
83
  if (!header) {
@@ -119,7 +121,7 @@ export const DataTableColumnHeader = <TData, TValue>({
119
121
  {renderCopyColumn(column)}
120
122
  {renderColumnPinning(column)}
121
123
  {renderColumnWrapping(column)}
122
- {renderFormatOptions(column)}
124
+ {renderFormatOptions(column, locale)}
123
125
  <DropdownMenuSeparator />
124
126
  {renderMenuItemFilter(column)}
125
127
  {renderFilterByValues(column, setIsFilterValueOpen)}
@@ -64,17 +64,34 @@ export class ColumnChartSpecModel<T> {
64
64
  private dataSpec: TopLevelSpec["data"];
65
65
  private sourceName: "data_0" | "source_0";
66
66
 
67
+ private readonly data: T[] | string;
68
+ private readonly fieldTypes: FieldTypes;
69
+ readonly stats: Record<ColumnName, Partial<ColumnHeaderStats>>;
70
+ readonly binValues: Record<ColumnName, BinValues>;
71
+ readonly valueCounts: Record<ColumnName, ValueCounts>;
72
+ private readonly opts: {
73
+ includeCharts: boolean;
74
+ usePreComputedValues?: boolean;
75
+ };
76
+
67
77
  constructor(
68
- private readonly data: T[] | string,
69
- private readonly fieldTypes: FieldTypes,
70
- readonly stats: Record<ColumnName, Partial<ColumnHeaderStats>>,
71
- readonly binValues: Record<ColumnName, BinValues>,
72
- readonly valueCounts: Record<ColumnName, ValueCounts>,
73
- private readonly opts: {
78
+ data: T[] | string,
79
+ fieldTypes: FieldTypes,
80
+ stats: Record<ColumnName, Partial<ColumnHeaderStats>>,
81
+ binValues: Record<ColumnName, BinValues>,
82
+ valueCounts: Record<ColumnName, ValueCounts>,
83
+ opts: {
74
84
  includeCharts: boolean;
75
85
  usePreComputedValues?: boolean;
76
86
  },
77
87
  ) {
88
+ this.data = data;
89
+ this.fieldTypes = fieldTypes;
90
+ this.stats = stats;
91
+ this.binValues = binValues;
92
+ this.valueCounts = valueCounts;
93
+ this.opts = opts;
94
+
78
95
  // Data may come in from a few different sources:
79
96
  // - A URL
80
97
  // - A CSV data URI (e.g. "data:text/csv;base64,...")
@@ -93,9 +110,9 @@ export class ColumnChartSpecModel<T> {
93
110
  const decoded = typedAtob(base64);
94
111
 
95
112
  if (decoded.startsWith(ARROW_MAGIC_NUMBER)) {
113
+ // @ts-expect-error vega-typings does not include arrow format
96
114
  this.dataSpec = {
97
115
  values: byteStringToBinary(decoded),
98
- // @ts-expect-error vega-typings does not include arrow format
99
116
  format: { type: "arrow" },
100
117
  };
101
118
  } else {
@@ -1,5 +1,6 @@
1
1
  /* Copyright 2024 Marimo. All rights reserved. */
2
2
  import React, { Suspense } from "react";
3
+ import { useLocale } from "react-aria";
3
4
  import { createBatchedLoader } from "@/plugins/impl/vega/batched";
4
5
  import { useTheme } from "@/theme/useTheme";
5
6
  import { logNever } from "@/utils/assertNever";
@@ -29,6 +30,8 @@ const batchedLoader = createBatchedLoader();
29
30
  export const TableColumnSummary = <TData, TValue>({
30
31
  columnId,
31
32
  }: Props<TData, TValue>) => {
33
+ const { locale } = useLocale();
34
+
32
35
  const chartSpecModel = React.use(ColumnChartContext);
33
36
  const { theme } = useTheme();
34
37
  const { spec, type, stats } = chartSpecModel.getHeaderSummary(columnId);
@@ -65,7 +68,7 @@ export const TableColumnSummary = <TData, TValue>({
65
68
  ) => {
66
69
  return (
67
70
  <DatePopover date={date} type={type}>
68
- {prettyDate(date, type)}
71
+ {prettyDate(date, type, locale)}
69
72
  </DatePopover>
70
73
  );
71
74
  };
@@ -84,7 +87,7 @@ export const TableColumnSummary = <TData, TValue>({
84
87
  <div className="flex flex-col whitespace-pre">
85
88
  <span>min: {renderDate(stats.min, type)}</span>
86
89
  <span>max: {renderDate(stats.max, type)}</span>
87
- <span>unique: {prettyNumber(stats.unique)}</span>
90
+ <span>unique: {prettyNumber(stats.unique, locale)}</span>
88
91
  </div>
89
92
  );
90
93
  }
@@ -106,16 +109,22 @@ export const TableColumnSummary = <TData, TValue>({
106
109
  <span>
107
110
  min:{" "}
108
111
  {typeof stats.min === "number"
109
- ? prettyScientificNumber(stats.min, { shouldRound: true })
112
+ ? prettyScientificNumber(stats.min, {
113
+ shouldRound: true,
114
+ locale,
115
+ })
110
116
  : stats.min}
111
117
  </span>
112
118
  <span>
113
119
  max:{" "}
114
120
  {typeof stats.max === "number"
115
- ? prettyScientificNumber(stats.max, { shouldRound: true })
121
+ ? prettyScientificNumber(stats.max, {
122
+ shouldRound: true,
123
+ locale,
124
+ })
116
125
  : stats.max}
117
126
  </span>
118
- <span>unique: {prettyNumber(stats.unique)}</span>
127
+ <span>unique: {prettyNumber(stats.unique, locale)}</span>
119
128
  </div>
120
129
  );
121
130
  }
@@ -127,8 +136,8 @@ export const TableColumnSummary = <TData, TValue>({
127
136
  if (!spec) {
128
137
  return (
129
138
  <div className="flex flex-col whitespace-pre">
130
- <span>true: {prettyNumber(stats.true)}</span>
131
- <span>false: {prettyNumber(stats.false)}</span>
139
+ <span>true: {prettyNumber(stats.true, locale)}</span>
140
+ <span>false: {prettyNumber(stats.false, locale)}</span>
132
141
  </div>
133
142
  );
134
143
  }
@@ -140,7 +149,7 @@ export const TableColumnSummary = <TData, TValue>({
140
149
  if (!spec) {
141
150
  return (
142
151
  <div className="flex flex-col whitespace-pre">
143
- <span>unique: {prettyNumber(stats.unique)}</span>
152
+ <span>unique: {prettyNumber(stats.unique, locale)}</span>
144
153
  </div>
145
154
  );
146
155
  }
@@ -148,7 +157,7 @@ export const TableColumnSummary = <TData, TValue>({
148
157
  case "unknown":
149
158
  return (
150
159
  <div className="flex flex-col whitespace-pre">
151
- <span>nulls: {prettyNumber(stats.nulls)}</span>
160
+ <span>nulls: {prettyNumber(stats.nulls, locale)}</span>
152
161
  </div>
153
162
  );
154
163
  default: