@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.
- package/dist/assets/ConnectedDataExplorerComponent-2wVcyvDj.js +19 -0
- package/dist/assets/{ImageComparisonComponent-fTHv1Ih0.js → ImageComparisonComponent-D2j6i0hv.js} +1 -1
- package/dist/assets/{VegaLite-Bdi-TyfY.js → VegaLite-BckFaf2D.js} +1 -1
- package/dist/assets/_baseEach-CvTX9w0Y.js +1 -0
- package/dist/assets/_baseMap-CtlwA90f.js +1 -0
- package/dist/assets/_baseUniq-BKktIGQ1.js +1 -0
- package/dist/assets/{_createAggregator-DcD0kTA5.js → _createAggregator-C5CVY-0t.js} +1 -1
- package/dist/assets/{agent-panel-Crv430aI.js → agent-panel-RGLNjkYe.js} +76 -57
- package/dist/assets/{any-language-editor-CQh552Wu.js → any-language-editor-DjuXwGCA.js} +1 -1
- package/dist/assets/{architectureDiagram-W76B3OCA-BAJeBxzt.js → architectureDiagram-W76B3OCA-Dyj4ds_R.js} +1 -1
- package/dist/assets/{between-horizontal-start-Boxgxbt_.js → between-horizontal-start-Dt2aKpPf.js} +1 -1
- package/dist/assets/{blockDiagram-QIGZ2CNN-CL-1svEK.js → blockDiagram-QIGZ2CNN-o-i7DDvN.js} +1 -1
- package/dist/assets/{c4Diagram-FPNF74CW-BbEqbCTl.js → c4Diagram-FPNF74CW-DGHEwWrx.js} +1 -1
- package/dist/assets/channel-Co6iMgWq.js +1 -0
- package/dist/assets/chat-panel-9alr8FS4.js +3 -0
- package/dist/assets/{chunk-4BX2VUAB-C--8TXeE.js → chunk-4BX2VUAB-BJecb-Ri.js} +1 -1
- package/dist/assets/{chunk-55IACEB6-Bj00HDqq.js → chunk-55IACEB6-CAATkc4w.js} +1 -1
- package/dist/assets/{chunk-FMBD7UC4-C-lhB6hN.js → chunk-FMBD7UC4-DPuNbQ-f.js} +1 -1
- package/dist/assets/{chunk-K7UQS3LO-B-pGTXPt.js → chunk-K7UQS3LO-C8TWVLiH.js} +1 -1
- package/dist/assets/{chunk-QN33PNHL-DqUzGhvm.js → chunk-QN33PNHL-DiZZ09q4.js} +1 -1
- package/dist/assets/{chunk-QZHKN3VN-TntJHfSk.js → chunk-QZHKN3VN-BIUM7usu.js} +1 -1
- package/dist/assets/{chunk-TVAH2DTR-HUJb1psV.js → chunk-TVAH2DTR-vGTArPBG.js} +1 -1
- package/dist/assets/{chunk-TZMSLE5B-BK3C__t3.js → chunk-TZMSLE5B-D2KRqp_x.js} +1 -1
- package/dist/assets/{circle-play-DBLOv1Yu.js → circle-play-cjeNez0N.js} +1 -1
- package/dist/assets/classDiagram-KNZD7YFC-BbJ0rY3y.js +1 -0
- package/dist/assets/classDiagram-v2-RKCZMP56-BbJ0rY3y.js +1 -0
- package/dist/assets/{clear-button-BeoFbEKH.js → clear-button-C97JtAez.js} +1 -1
- package/dist/assets/clone-BMP0PsTa.js +1 -0
- package/dist/assets/{command-palette-CXZiSv0I.js → command-palette-B93Pjcky.js} +1 -1
- package/dist/assets/{common-C7oJcmCT.js → common-Du9rSOwD.js} +1 -1
- package/dist/assets/{compile-7L0MwhyI.js → compile-CZXqyOxa.js} +1 -1
- package/dist/assets/{cose-bilkent-S5V4N54A-BMkGLcVC.js → cose-bilkent-S5V4N54A-CqUN5Y9b.js} +1 -1
- package/dist/assets/{dagre-5GWH7T2D-BJtRienS.js → dagre-5GWH7T2D-RJqTI9DM.js} +1 -1
- package/dist/assets/{data-grid-overlay-editor-DBkmGtNs.js → data-grid-overlay-editor-DZN0q1LV.js} +1 -1
- package/dist/assets/datasources-panel-v7H3cR0p.js +1 -0
- package/dist/assets/{dependency-graph-panel-DEdOxp2X.js → dependency-graph-panel-CEog_O7V.js} +1 -1
- package/dist/assets/{diagram-N5W7TBWH-CmECY3nb.js → diagram-N5W7TBWH-D-l4zZ9d.js} +1 -1
- package/dist/assets/{diagram-QEK2KX5R-DMOVSNKD.js → diagram-QEK2KX5R-CCOmBUt-.js} +1 -1
- package/dist/assets/{diagram-S2PKOQOG-BiJ96PNQ.js → diagram-S2PKOQOG-C_I_9jnZ.js} +1 -1
- package/dist/assets/{documentation-panel-xULhaEv3.js → documentation-panel-C1BtMZ3M.js} +1 -1
- package/dist/assets/edit-page-B-oevUZ9.js +129 -0
- package/dist/assets/{ellipsis-vertical-BBqXIlc2.js → ellipsis-vertical-BEb-J8z6.js} +1 -1
- package/dist/assets/{empty-state-B3dA3G5P.js → empty-state-C99UyDE3.js} +1 -1
- package/dist/assets/{erDiagram-AWTI2OKA-MP1DiFRo.js → erDiagram-AWTI2OKA-BePOLi5M.js} +1 -1
- package/dist/assets/{error-panel-Cc1sv-Ag.js → error-panel-Bs34jXFh.js} +1 -1
- package/dist/assets/file-explorer-panel-Ck6UL861.js +1 -0
- package/dist/assets/{flowDiagram-PVAE7QVJ-BX7caPp7.js → flowDiagram-PVAE7QVJ-BgjFu5l7.js} +1 -1
- package/dist/assets/{ganttDiagram-OWAHRB6G-B462g4Yf.js → ganttDiagram-OWAHRB6G-YOPb3XSV.js} +4 -4
- package/dist/assets/{gitGraphDiagram-NY62KEGX-CGgvZ9-9.js → gitGraphDiagram-NY62KEGX-CGhqaDTy.js} +1 -1
- package/dist/assets/{glide-data-editor-C0gUFZON.js → glide-data-editor-9QUH6iso.js} +11 -11
- package/dist/assets/{graph-CHRVBzY5.js → graph-DQQFGrho.js} +1 -1
- package/dist/assets/home-page-DRKpPCrF.js +9 -0
- package/dist/assets/{index-C1v_Z9et.js → index-2252nrk6.js} +1 -1
- package/dist/assets/{index-CQDrxQ0j.js → index-Aeo6WiK7.js} +1 -1
- package/dist/assets/{index-C4Tn5NvJ.js → index-B8jXZ12t.js} +1 -1
- package/dist/assets/{index-DoRmcrKM.js → index-BAbIIxHU.js} +1 -1
- package/dist/assets/{index-BY93Ejhl.js → index-BJNCMUmG.js} +1 -1
- package/dist/assets/{index-CpTPJo4k.js → index-BW3k9Gss.js} +1 -1
- package/dist/assets/{index-D1vmG6DS.js → index-BjgnbONl.js} +1 -1
- package/dist/assets/{index-z9bohSQJ.js → index-BprjMYH5.js} +1 -1
- package/dist/assets/{index-BVgAenPd.js → index-C1ez98sk.js} +1 -1
- package/dist/assets/{index-D9UKkrr2.js → index-C2MD0vgD.js} +1 -1
- package/dist/assets/index-C7CoaNFb.js +578 -0
- package/dist/assets/{index-C-GhZ7ti.js → index-CFKO7WXI.js} +1 -1
- package/dist/assets/{index-lYa_leQE.js → index-CUFv_thQ.js} +1 -1
- package/dist/assets/{index-vmICa5KN.js → index-C_tkBKNO.js} +1 -1
- package/dist/assets/{index-C77h_TXN.js → index-CfaDbEdi.js} +1 -1
- package/dist/assets/{index-DEQvTChO.js → index-ClzeQrN7.js} +1 -1
- package/dist/assets/index-DadI618h.css +1 -0
- package/dist/assets/{index-DRMm6SNo.js → index-DdnKZNxM.js} +1 -1
- package/dist/assets/{index-CWMgowgL.js → index-G5QZppK2.js} +1 -1
- package/dist/assets/{index-Clbi_Yaq.js → index-SGLNXrGP.js} +1 -1
- package/dist/assets/{index-C-8WADat.js → index-aE43R74q.js} +1 -1
- package/dist/assets/infoDiagram-STP46IZ2-CJLOpSAf.js +2 -0
- package/dist/assets/{isEmpty-DU_ogP_D.js → isEmpty-D-4c7sMv.js} +1 -1
- package/dist/assets/{journeyDiagram-BIP6EPQ6-C6EgLP_Q.js → journeyDiagram-BIP6EPQ6-C94u3Mv3.js} +1 -1
- package/dist/assets/{kanban-definition-6OIFK2YF-BXzYO1yj.js → kanban-definition-6OIFK2YF-BEXYFzz7.js} +1 -1
- package/dist/assets/{layout-jihVw5-i.js → layout-Bz2BJ2ru.js} +1 -1
- package/dist/assets/{linear-C4blANlC.js → linear-D8s7K76e.js} +1 -1
- package/dist/assets/links-BpXlz1GG.js +7 -0
- package/dist/assets/{logs-panel-D401qzZh.js → logs-panel-DC7wpmPz.js} +1 -1
- package/dist/assets/{markdown-renderer-Cd9eYyaL.js → markdown-renderer-DRdSWR9X.js} +20 -20
- package/dist/assets/{mermaid-BEVuRz_O.js → mermaid-Y3x4hmD0.js} +1 -1
- package/dist/assets/{mermaid.core-CaSnaLH0.js → mermaid.core-DzthE35Y.js} +4 -4
- package/dist/assets/min-BBO3-1Hg.js +1 -0
- package/dist/assets/{mindmap-definition-Q6HEUPPD-BXUM5MT2.js → mindmap-definition-Q6HEUPPD-DktvuLe1.js} +1 -1
- package/dist/assets/{number-overlay-editor-4uWXGlPG.js → number-overlay-editor-BEfwI1IT.js} +1 -1
- package/dist/assets/outline-panel-CdsnAy2w.js +1 -0
- package/dist/assets/{packages-panel-CJL0MVlj.js → packages-panel-DiTA-d_D.js} +1 -1
- package/dist/assets/{pieDiagram-ADFJNKIX-Dxt5PVNo.js → pieDiagram-ADFJNKIX-DQDNQ-de.js} +1 -1
- package/dist/assets/{quadrantDiagram-LMRXKWRM-D4pUaA31.js → quadrantDiagram-LMRXKWRM-0kgIXc2-.js} +1 -1
- package/dist/assets/{react-plotly-cJZ0VWBq.js → react-plotly-DJqqfM7c.js} +1 -1
- package/dist/assets/{requirementDiagram-4UW4RH46-DVRTjgas.js → requirementDiagram-4UW4RH46-B5rb0ypd.js} +1 -1
- package/dist/assets/{run-page-BUEnMC9w.js → run-page-CFmLrv1R.js} +1 -1
- package/dist/assets/{sankeyDiagram-GR3RE2ED-CVFnD9C-.js → sankeyDiagram-GR3RE2ED-Dom7IlnF.js} +1 -1
- package/dist/assets/{scratchpad-panel-BIgRENkI.js → scratchpad-panel-CuHWpHO8.js} +1 -1
- package/dist/assets/{secrets-panel-xY5-V_BD.js → secrets-panel-CfHc5YD0.js} +1 -1
- package/dist/assets/{sequenceDiagram-C3RYC4MD-_lY4ZN_S.js → sequenceDiagram-C3RYC4MD-PNJWXQbw.js} +1 -1
- package/dist/assets/{slides-component-DMjQomc3.css → slides-component-C-LoGC1U.css} +1 -1
- package/dist/assets/{slides-component-Xjymwj7X.js → slides-component-CJgaTRZ0.js} +1 -1
- package/dist/assets/snippets-panel-B2EC1txM.js +1 -0
- package/dist/assets/sortBy-DZnlX29-.js +1 -0
- package/dist/assets/{state-C4NiC9tO.js → state-CWict9RU.js} +1 -1
- package/dist/assets/{stateDiagram-KXAO66HF-Da0JQWCn.js → stateDiagram-KXAO66HF-BE58aJnr.js} +1 -1
- package/dist/assets/stateDiagram-v2-UMBNRL4Z-CdThjimL.js +1 -0
- package/dist/assets/storage-DRaR04wR.js +26 -0
- package/dist/assets/{terminal-BPwTkXae.js → terminal-BX3Su5q7.js} +1 -1
- package/dist/assets/{time-Dv5_Ouz_.js → time-hUzZfpNE.js} +1 -1
- package/dist/assets/{timeline-definition-XQNQX7LJ-Dxh5Zu2e.js → timeline-definition-XQNQX7LJ-CqQP9t51.js} +1 -1
- package/dist/assets/tracing-B10Q1n-L.js +2 -0
- package/dist/assets/{tracing-panel-DAzrzNmm.js → tracing-panel-Du8WCnno.js} +2 -2
- package/dist/assets/{trash-Dc6DSjz_.js → trash-B81GTiv6.js} +1 -1
- package/dist/assets/{tree-jheoerAX.js → tree-6vW2ogkh.js} +1 -1
- package/dist/assets/{treemap-75Q7IDZK-IgpxeGaf.js → treemap-75Q7IDZK-CdwDwwsz.js} +27 -27
- package/dist/assets/variable-panel-D5qgJI7k.js +1 -0
- package/dist/assets/{vega-component-BpfpiPKI.js → vega-component-DJaJWMJM.js} +1 -1
- package/dist/assets/worker-fHbtoWvT.js +1 -0
- package/dist/assets/{xychartDiagram-6GGTOJPD-CmNigJ31.js → xychartDiagram-6GGTOJPD-WFtXqaM9.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +3 -2
- package/src/components/app-config/user-config-form.tsx +46 -1
- package/src/components/chat/acp/__tests__/__snapshots__/prompt.test.ts.snap +62 -43
- package/src/components/chat/acp/__tests__/atoms.test.ts +1 -1
- package/src/components/chat/acp/__tests__/state.test.ts +36 -36
- package/src/components/chat/acp/agent-panel.tsx +24 -27
- package/src/components/chat/acp/blocks.tsx +6 -6
- package/src/components/chat/acp/prompt.ts +62 -43
- package/src/components/chat/chat-panel.tsx +5 -1
- package/src/components/chat/markdown-renderer.tsx +6 -10
- package/src/components/chat/tool-call-accordion.tsx +52 -20
- package/src/components/data-table/SearchBar.tsx +8 -7
- package/src/components/data-table/__tests__/column_formatting.test.ts +50 -35
- package/src/components/data-table/__tests__/data-table.test.tsx +39 -1
- package/src/components/data-table/cell-hover-template/feature.ts +14 -0
- package/src/components/data-table/cell-hover-template/types.ts +11 -0
- package/src/components/data-table/charts/components/form-fields.tsx +41 -37
- package/src/components/data-table/charts/forms/common-chart.tsx +2 -2
- package/src/components/data-table/column-explorer-panel/column-explorer.tsx +5 -2
- package/src/components/data-table/column-formatting/feature.ts +62 -29
- package/src/components/data-table/column-formatting/types.ts +1 -0
- package/src/components/data-table/column-header.tsx +3 -1
- package/src/components/data-table/column-summary/chart-spec-model.tsx +24 -7
- package/src/components/data-table/column-summary/column-summary.tsx +18 -9
- package/src/components/data-table/columns.tsx +42 -18
- package/src/components/data-table/data-table.tsx +10 -2
- package/src/components/data-table/date-popover.tsx +85 -75
- package/src/components/data-table/filter-pills.tsx +14 -9
- package/src/components/data-table/header-items.tsx +5 -1
- package/src/components/data-table/pagination.tsx +20 -13
- package/src/components/data-table/renderers.tsx +28 -0
- package/src/components/data-table/row-viewer-panel/row-viewer.tsx +10 -8
- package/src/components/datasources/column-preview.tsx +6 -2
- package/src/components/datasources/datasources.tsx +8 -12
- package/src/components/editor/ai/transport/chat-transport.tsx +4 -1
- package/src/components/editor/cell/CellStatus.tsx +23 -20
- package/src/components/editor/cell/CreateCellButton.tsx +3 -4
- package/src/components/editor/cell/code/language-toggle.tsx +3 -4
- package/src/components/editor/chrome/wrapper/footer-items/machine-stats.tsx +39 -28
- package/src/components/editor/controls/notebook-menu-dropdown.tsx +4 -2
- package/src/components/editor/file-tree/requesting-tree.tsx +14 -8
- package/src/components/editor/renderers/CellArray.tsx +3 -4
- package/src/components/editor/renderers/slides-layout/slides-layout.tsx +3 -3
- package/src/components/editor/renderers/slides-layout/types.ts +1 -0
- package/src/components/pages/home-page.tsx +4 -1
- package/src/components/slides/slides-component.tsx +1 -1
- package/src/components/slides/slides.css +6 -0
- package/src/components/terminal/theme.tsx +1 -0
- package/src/components/tracing/tracing-spec.ts +5 -4
- package/src/components/ui/range-slider.tsx +4 -2
- package/src/components/ui/slider.tsx +3 -1
- package/src/components/variables/variables-table.tsx +3 -0
- package/src/core/MarimoApp.tsx +9 -6
- package/src/core/ai/context/__tests__/registry.test.ts +6 -4
- package/src/core/ai/context/providers/cell-output.ts +3 -2
- package/src/core/ai/context/providers/error.ts +3 -1
- package/src/core/ai/context/providers/file.ts +7 -2
- package/src/core/ai/context/providers/tables.ts +3 -2
- package/src/core/ai/context/providers/variable.ts +6 -4
- package/src/core/ai/staged-cells.ts +34 -1
- package/src/core/cells/__tests__/add-missing-import.test.ts +67 -22
- package/src/core/cells/add-missing-import.ts +24 -7
- package/src/core/cells/cells.ts +26 -27
- package/src/core/cells/logs.ts +1 -1
- package/src/core/codemirror/find-replace/search-highlight.ts +3 -1
- package/src/core/codemirror/language/LanguageAdapters.ts +9 -3
- package/src/core/codemirror/lsp/notebook-lsp.ts +8 -2
- package/src/core/codemirror/readonly/__tests__/extension.test.ts +1 -1
- package/src/core/codemirror/rtc/loro/awareness.ts +52 -17
- package/src/core/codemirror/rtc/loro/sync.ts +12 -4
- package/src/core/config/config-schema.ts +1 -0
- package/src/core/config/config.ts +4 -0
- package/src/core/hotkeys/hotkeys.ts +8 -4
- package/src/core/i18n/__tests__/locale-provider.test.tsx +176 -0
- package/src/core/i18n/locale-provider.tsx +35 -0
- package/src/core/i18n/with-locale.tsx +12 -0
- package/src/core/islands/components/web-components.tsx +13 -10
- package/src/core/kernel/RuntimeState.ts +4 -1
- package/src/core/kernel/messages.ts +2 -2
- package/src/core/network/DeferredRequestRegistry.ts +16 -4
- package/src/core/runtime/runtime.ts +5 -4
- package/src/core/wasm/bridge.ts +5 -1
- package/src/core/wasm/store.ts +4 -1
- package/src/core/wasm/worker/message-buffer.ts +3 -2
- package/src/core/websocket/types.ts +22 -16
- package/src/hooks/useFormatting.ts +97 -0
- package/src/hooks/useTimer.ts +8 -5
- package/src/plugins/core/registerReactComponent.tsx +16 -10
- package/src/plugins/impl/DataTablePlugin.tsx +4 -0
- package/src/plugins/impl/RangeSliderPlugin.tsx +5 -3
- package/src/plugins/impl/SliderPlugin.tsx +3 -1
- package/src/plugins/impl/anywidget/model.ts +16 -5
- package/src/plugins/impl/data-editor/types.ts +7 -5
- package/src/plugins/impl/data-explorer/components/column-summary.tsx +20 -13
- package/src/plugins/impl/panel/utils.ts +6 -4
- package/src/plugins/layout/OutlinePlugin.tsx +69 -0
- package/src/plugins/layout/StatPlugin.tsx +4 -1
- package/src/plugins/plugins.ts +2 -0
- package/src/utils/__tests__/dates.test.ts +45 -24
- package/src/utils/__tests__/numbers.test.ts +42 -30
- package/src/utils/__tests__/once.test.ts +187 -0
- package/src/utils/dates.ts +15 -10
- package/src/utils/edit-distance.ts +8 -6
- package/src/utils/errors.ts +1 -1
- package/src/utils/id-tree.tsx +21 -10
- package/src/utils/localStorage.ts +13 -4
- package/src/utils/numbers.ts +11 -11
- package/src/utils/once.ts +32 -0
- package/src/utils/paths.ts +4 -1
- package/src/utils/pluralize.ts +12 -5
- package/src/utils/python-poet/poet.ts +30 -15
- package/src/utils/time.ts +5 -1
- package/dist/assets/ConnectedDataExplorerComponent-BErMbWvG.js +0 -19
- package/dist/assets/_baseEach-CNBxBxvS.js +0 -1
- package/dist/assets/_baseMap-D1WHjKrd.js +0 -1
- package/dist/assets/_baseUniq-CCgDNtZb.js +0 -1
- package/dist/assets/channel-_2eNSz0n.js +0 -1
- package/dist/assets/chat-panel-CXh5Wl6C.js +0 -3
- package/dist/assets/classDiagram-KNZD7YFC-BGmh9POF.js +0 -1
- package/dist/assets/classDiagram-v2-RKCZMP56-BGmh9POF.js +0 -1
- package/dist/assets/clone-BFDSPAj3.js +0 -1
- package/dist/assets/datasources-panel-B7FbYLiy.js +0 -1
- package/dist/assets/edit-page-BrYda9VE.js +0 -129
- package/dist/assets/file-explorer-panel-Bw59Kva1.js +0 -1
- package/dist/assets/home-page-Fb2osjys.js +0 -9
- package/dist/assets/index-Cx0bsY1w.css +0 -1
- package/dist/assets/index-DKEudB02.js +0 -578
- package/dist/assets/infoDiagram-STP46IZ2-CVyrdLc8.js +0 -2
- package/dist/assets/links-D59GIweI.js +0 -7
- package/dist/assets/min-DUMu_zeK.js +0 -1
- package/dist/assets/outline-panel-DIzkvm2I.js +0 -1
- package/dist/assets/snippets-panel-CTPYW41n.js +0 -1
- package/dist/assets/sortBy-BNZKwiq_.js +0 -1
- package/dist/assets/stateDiagram-v2-UMBNRL4Z-D5lYZOOt.js +0 -1
- package/dist/assets/storage-CMdLzB_c.js +0 -26
- package/dist/assets/tracing-BCIurUfa.js +0 -2
- package/dist/assets/variable-panel-DYAiLBmF.js +0 -1
- 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
|
-
<
|
|
84
|
-
<
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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(
|
|
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
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
|
|
16
|
-
|
|
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);
|
package/src/core/wasm/bridge.ts
CHANGED
|
@@ -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
|
-
|
|
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) => {
|
package/src/core/wasm/store.ts
CHANGED
|
@@ -87,7 +87,10 @@ const emptyFileStore: FileStore = {
|
|
|
87
87
|
};
|
|
88
88
|
|
|
89
89
|
export class CompositeFileStore implements FileStore {
|
|
90
|
-
|
|
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(
|
|
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
|
|
6
|
-
CONNECTING
|
|
7
|
-
OPEN
|
|
8
|
-
CLOSING
|
|
9
|
-
CLOSED
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
+
}
|
package/src/hooks/useTimer.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
<
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
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
|
-
|
|
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>
|