@marimo-team/islands 0.25.3-dev16 → 0.25.3-dev162
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/{ConnectedDataExplorerComponent-CNMliVzw.js → ConnectedDataExplorerComponent-BbDrlHvG.js} +17 -15
- package/dist/{ErrorBoundary-BEmYzeHb.js → ErrorBoundary-D6GPQ8dk.js} +16 -16
- package/dist/{abnfDiagram-VCTEODGH-D-Ez91gV.js → abnfDiagram-VCTEODGH-Dr-fo8_z.js} +2 -2
- package/dist/any-language-editor-3E24SnCV.js +75 -0
- package/dist/{architectureDiagram-5GKGNRK7-CTpcNtO8.js → architectureDiagram-5GKGNRK7-ByKIl9GG.js} +1 -1
- package/dist/{arrays-CN1djC4k.js → arrays-R6JsImiT.js} +8 -0
- package/dist/assets/__vite-browser-external-DVeFf2e7.js +1 -0
- package/dist/assets/worker-C1pfNBsx.js +113 -0
- package/dist/{button-CvjkwdSk.js → button-BQRdqQi1.js} +199 -192
- package/dist/{capabilities-CQ5IjhzL.js → capabilities-CI4xUPsp.js} +2 -2
- package/dist/{chat-ui-DaHynk8g.js → chat-ui-BsV2WH-4.js} +1143 -1142
- package/dist/{check-EDwSwP89.js → check-SpOMoCLP.js} +1 -1
- package/dist/{chunk-IMKFNOWR-DGxi-zeo.js → chunk-IMKFNOWR-IKDP18MQ.js} +1 -1
- package/dist/{chunk-SHT3W25Y-CV9J3rAB.js → chunk-SHT3W25Y-LkIgegwh.js} +1 -1
- package/dist/{chunk-SVP7TREG-BL-9Fqgg.js → chunk-SVP7TREG-DReBYtnB.js} +1 -1
- package/dist/{chunk-TICWLB2K-Cu_XMjDM.js → chunk-TICWLB2K-DQ0A0-1D.js} +1 -1
- package/dist/{chunk-YOKDWASO-DPZk8vhS.js → chunk-YOKDWASO-DKplTrBY.js} +20 -20
- package/dist/{classDiagram-ZZMXUADV-BXXV13Hq.js → classDiagram-ZZMXUADV-CwvXdCNE.js} +2 -2
- package/dist/{classDiagram-v2-VYDZK3BY-B7FXJ1Cp.js → classDiagram-v2-VYDZK3BY-D0XAxDsc.js} +2 -2
- package/dist/{code-visibility-D75HwL4W.js → code-visibility-DEIiTBMH.js} +6 -6
- package/dist/{common-hR234FGW.js → common-BmlT-bPP.js} +6828 -6648
- package/dist/{copy-icon-Ft7t9bqz.js → copy-icon-C1trdvVt.js} +3 -3
- package/dist/{cynefinDiagram-5FMLGOSQ-CH96rwba.js → cynefinDiagram-5FMLGOSQ-BFN68nHr.js} +1 -1
- package/dist/{dagre-GXQ25YYZ-BD3PmpFY.js → dagre-GXQ25YYZ-CZt4rtLq.js} +1 -1
- package/dist/{data-grid-overlay-editor-D-NMDtk0.js → data-grid-overlay-editor-20Ge8ID1.js} +5 -5
- package/dist/{data-grid-types-BH_r7g7l.js → data-grid-types-0PJ-9N5n.js} +1 -1
- package/dist/{diagram-S7CK7UJ4-BsSJJldB.js → diagram-S7CK7UJ4-D5cOz47_.js} +1 -1
- package/dist/{diagram-UQ7AKVKN-muQtNZc4.js → diagram-UQ7AKVKN-Qgdppb4a.js} +1 -1
- package/dist/{diagram-VX7I27RA-CdhuZAqR.js → diagram-VX7I27RA-BsDCvily.js} +1 -1
- package/dist/{diagram-Z3DM3KII-BD8mXjOj.js → diagram-Z3DM3KII-igTkGjKI.js} +1 -1
- package/dist/{dialog-CEBFZNyc.js → dialog-DgeqyrEZ.js} +3 -3
- package/dist/{dist-DpBpA_n1.js → dist-Lm-D-Vr6.js} +3 -3
- package/dist/{dropdown-menu-CP_qCYHC.js → dropdown-menu-BWnnAstC.js} +1277 -1229
- package/dist/{ebnfDiagram-PWID7BFC-BIN1sweE.js → ebnfDiagram-PWID7BFC-BHuZGjIr.js} +2 -2
- package/dist/{erDiagram-RLTQ6QDP-Ctp5cfoN.js → erDiagram-RLTQ6QDP-DKObXTVE.js} +1 -1
- package/dist/{error-banner-D-WCIiMt.js → error-banner-D40pmfQQ.js} +83 -83
- package/dist/{error-entries-Bv6bZPF3.js → error-entries-BpUJSLUZ.js} +1019 -978
- package/dist/{feedback-button-B3sliPJj.js → feedback-button-zWcCfXEI.js} +23 -23
- package/dist/{flowDiagram-HODETNUW-3EfLrlFb.js → flowDiagram-HODETNUW-DZI_kit0.js} +2 -2
- package/dist/{formats-27CW_UP4.js → formats-CwJHWasD.js} +3 -3
- package/dist/{ganttDiagram-EL5Y4UJY-BQT16JSc.js → ganttDiagram-EL5Y4UJY-Dh_4cBJZ.js} +2 -2
- package/dist/{glide-data-editor-Dufy2ePW.js → glide-data-editor-Dn1Ekucb.js} +370 -368
- package/dist/{glide-utils-DJyqh0EM.js → glide-utils-Dz_F4pAY.js} +16 -16
- package/dist/{globals-B02fTTAH.js → globals-D_fhTQMd.js} +3 -3
- package/dist/{highlighted-body-KPVGNVTW-zwjq21tf.js → highlighted-body-KPVGNVTW-3Ziwfz-V.js} +2 -2
- package/dist/{html-to-image-Bf8QMGi4.js → html-to-image-CQr2-IDA.js} +632 -595
- package/dist/{infoDiagram-27XIBGKW-DipQoHxl.js → infoDiagram-27XIBGKW-DdPl-7-n.js} +1 -1
- package/dist/{ishikawaDiagram-5VMMS53U-DgFMjSGz.js → ishikawaDiagram-5VMMS53U-DbyW6l59.js} +1 -1
- package/dist/{kanban-definition-UXKFOSKX-w1ACVjgl.js → kanban-definition-UXKFOSKX-BMX9SyBS.js} +1 -1
- package/dist/{label-BDKF3Afc.js → label-D9_-zSg-.js} +3 -3
- package/dist/{linear-Cnaq3Tfb.js → linear-DWERh7eI.js} +121 -73
- package/dist/{loader-BQOfjTIJ.js → loader-DOVB0Syl.js} +12 -12
- package/dist/main.js +7568 -7246
- package/dist/{mermaid-CHo49Yv-.js → mermaid-C8W8mTbA.js} +38 -38
- package/dist/mermaid-HWGCJPDP-Du3-HPQA.js +2 -0
- package/dist/{mindmap-definition-YA3MSWOX-CrT0KSfX.js → mindmap-definition-YA3MSWOX-Zd_tAxWL.js} +1 -1
- package/dist/{number-overlay-editor-EF8mCVoy.js → number-overlay-editor-ELtg9k3M.js} +3 -3
- package/dist/{objects-CzUgoMIF.js → objects-DCmMvZtn.js} +1 -3
- package/dist/{once-BtE-wKRL.js → once-eG8Vmvjd.js} +1 -1
- package/dist/{pegDiagram-XKGWAZYB-BqvywNJA.js → pegDiagram-XKGWAZYB-DjYydPdo.js} +2 -2
- package/dist/{pieDiagram-E7YTZNPT-BfxJ_XCc.js → pieDiagram-E7YTZNPT-R5LKjO2n.js} +1 -1
- package/dist/precisionRound-DhAzeRcm.js +49 -0
- package/dist/{process-output-BZg56CCb.js → process-output-Uw-VJE5V.js} +5 -5
- package/dist/{quadrantDiagram-AXDQQJYC-Ccw0xMjN.js → quadrantDiagram-AXDQQJYC-Blrm7V7_.js} +1 -1
- package/dist/{railroadDiagram-O6MQD6OU-8vFLVTPu.js → railroadDiagram-O6MQD6OU-C7uNKtfm.js} +2 -2
- package/dist/{react-vega-BED0DjiB.js → react-vega-C4T9Rb_w.js} +12284 -12270
- package/dist/{requirementDiagram-BXWQKSXE-a_MxGvxe.js → requirementDiagram-BXWQKSXE-CxAIzQfl.js} +1 -1
- package/dist/{reveal-component-Boolki8h.js → reveal-component-CduO3VgT.js} +14 -14
- package/dist/{select-BButFi-d.js → select-CkF_GBxO.js} +537 -458
- package/dist/{sequenceDiagram-WJ2MYXX4-CXFMnxGh.js → sequenceDiagram-WJ2MYXX4-B5tmlPd5.js} +1 -1
- package/dist/{spec-BwarBpUJ.js → spec-45FnujvG.js} +41 -11
- package/dist/{stateDiagram-D77RDMKH-DQeA_CwI.js → stateDiagram-D77RDMKH-C1hc5H7Y.js} +2 -2
- package/dist/{stateDiagram-v2-MP3YSRHH-BxxQucm1.js → stateDiagram-v2-MP3YSRHH-DRWeqQTn.js} +2 -2
- package/dist/style.css +1 -1
- package/dist/{swimlanes-42K2YHIH-Do6L-cYg.js → swimlanes-42K2YHIH-NTLas--s.js} +1 -1
- package/dist/{swimlanesDiagram-VR7AAH4N-DUzPvSVU.js → swimlanesDiagram-VR7AAH4N-ChPggljD.js} +2 -2
- package/dist/{swiper-component-DKntyn8p.js → swiper-component-BkCm-kLg.js} +2 -2
- package/dist/{time-BieKwdYS.js → time-BaMbJs4z.js} +18 -18
- package/dist/{timeline-definition-24CTP7MA-D3c46WM5.js → timeline-definition-24CTP7MA-B4CZ9srJ.js} +1 -1
- package/dist/{toDate-UtiwmnH2.js → toDate-rySyYxqk.js} +19 -18
- package/dist/{toast-B9UMEi8u.js → toast-Btbve3Lm.js} +231 -213
- package/dist/{tooltip-BO1REbqs.js → tooltip-CJ4Rqasp.js} +327 -303
- package/dist/{use-restore-focus-BEM7sFWl.js → use-restore-focus-CmGwRNId.js} +1482 -1433
- package/dist/{useAsyncData-Deh5kszT.js → useAsyncData-B7MiltyV.js} +15 -14
- package/dist/{useDateFormatter-D8XruNGG.js → useDateFormatter-eCL_SdeG.js} +2 -2
- package/dist/{useDeepCompareMemoize-DXwzRINI.js → useDeepCompareMemoize-DZmHBD_1.js} +1 -1
- package/dist/{useIframeCapabilities-DBETvvPl.js → useIframeCapabilities-CSdWn6NP.js} +1 -1
- package/dist/{useLifecycle-j7D9uD1o.js → useLifecycle-DRbRhzxg.js} +3 -3
- package/dist/{useTheme-CRnjkku0.js → useTheme-TLkqJsvo.js} +57 -54
- package/dist/{vega-component-BeF9dfyO.js → vega-component-DC6P127L.js} +148 -148
- package/dist/{vega-embed-container-BNHE18G9.js → vega-embed-container--LYZqguO.js} +2 -2
- package/dist/{vega-loader.browser-DNST6uVf.js → vega-loader.browser-B9Pz0EGP.js} +298 -507
- package/dist/{vennDiagram-4TSXK5OY-BSZD8JcZ.js → vennDiagram-4TSXK5OY-DJIvMt44.js} +1 -1
- package/dist/{wardleyDiagram-VM6X3IG4-48cUWkfA.js → wardleyDiagram-VM6X3IG4-45H0zg0u.js} +1 -1
- package/dist/{xychartDiagram-S5SC5T6Z-CswYgYeu.js → xychartDiagram-S5SC5T6Z-ZT-XzcPN.js} +2 -2
- package/package.json +16 -16
- package/src/__tests__/module-entry.test.ts +44 -0
- package/src/__tests__/mount.test.ts +1 -21
- package/src/__tests__/{host-imports.test.ts → replica-imports.test.ts} +12 -11
- package/src/components/ai/__tests__/ai-model-dropdown.test.tsx +63 -0
- package/src/components/ai/ai-model-dropdown.tsx +11 -6
- package/src/components/app-config/ai-config.tsx +7 -2
- package/src/components/app-config/user-config-form.tsx +35 -0
- package/src/components/chat/__tests__/message-queue.test.tsx +17 -0
- package/src/components/chat/acp/__tests__/session-tabs.test.tsx +43 -0
- package/src/components/chat/acp/__tests__/state.test.ts +2 -2
- package/src/components/chat/acp/blocks.tsx +3 -2
- package/src/components/chat/acp/session-tabs.tsx +8 -3
- package/src/components/chat/chat-components.tsx +2 -0
- package/src/components/chat/chat-panel.tsx +9 -8
- package/src/components/chat/chat-utils.ts +4 -8
- package/src/components/data-table/TableTopBar.tsx +2 -0
- package/src/components/data-table/__tests__/chart-spec-model.test.ts +195 -195
- package/src/components/data-table/__tests__/column-explorer.test.tsx +27 -1
- package/src/components/data-table/__tests__/columns.test.tsx +105 -0
- package/src/components/data-table/__tests__/context-menu-interaction.test.tsx +130 -0
- package/src/components/data-table/__tests__/data-table.test.tsx +1 -0
- package/src/components/data-table/__tests__/date-popover.test.tsx +72 -0
- package/src/components/data-table/__tests__/export-actions.test.tsx +105 -0
- package/src/components/data-table/__tests__/keyboard-selection.test.tsx +188 -0
- package/src/components/data-table/__tests__/search-highlight.test.tsx +109 -0
- package/src/components/data-table/__tests__/url-detector.test.tsx +74 -0
- package/src/components/data-table/cell-selection/feature.ts +2 -2
- package/src/components/data-table/cell-selection/types.ts +2 -2
- package/src/components/data-table/charts/__tests__/chart-panel.test.tsx +74 -1
- package/src/components/data-table/charts/__tests__/spec-snapshot.test.ts +20 -20
- package/src/components/data-table/charts/__tests__/spec.test.ts +78 -52
- package/src/components/data-table/charts/__tests__/storage.test.ts +4 -1
- package/src/components/data-table/charts/chart-spec/spec.ts +68 -43
- package/src/components/data-table/charts/charts.tsx +40 -30
- package/src/components/data-table/charts/storage.ts +16 -5
- package/src/components/data-table/column-explorer-panel/column-explorer.tsx +1 -1
- package/src/components/data-table/column-summary/chart-spec-model.tsx +23 -16
- package/src/components/data-table/column-summary/column-summary.tsx +2 -4
- package/src/components/data-table/column-visibility-dropdown.tsx +8 -13
- package/src/components/data-table/columns.tsx +45 -46
- package/src/components/data-table/context-menu.tsx +36 -20
- package/src/components/data-table/data-table.tsx +13 -1
- package/src/components/data-table/date-popover.tsx +6 -4
- package/src/components/data-table/export-actions.tsx +76 -48
- package/src/components/data-table/range-focus/atoms.ts +4 -6
- package/src/components/data-table/range-focus/use-cell-range-selection.ts +65 -38
- package/src/components/data-table/range-focus/use-scroll-into-view.ts +21 -2
- package/src/components/data-table/renderers.tsx +16 -7
- package/src/components/data-table/row-viewer-panel/__tests__/row-viewer.test.tsx +24 -1
- package/src/components/data-table/row-viewer-panel/row-viewer.tsx +4 -4
- package/src/components/data-table/search-highlight.tsx +79 -0
- package/src/components/data-table/types.ts +1 -0
- package/src/components/data-table/url-detector.tsx +49 -9
- package/src/components/datasources/__tests__/column-actions.test.tsx +97 -0
- package/src/components/datasources/__tests__/column-preview.test.tsx +98 -5
- package/src/components/datasources/__tests__/datasources-interactions.test.tsx +181 -0
- package/src/components/datasources/__tests__/table-list.test.tsx +118 -0
- package/src/components/datasources/__tests__/utils.test.ts +57 -6
- package/src/components/datasources/column-preview.tsx +13 -4
- package/src/components/datasources/datasources.tsx +51 -39
- package/src/components/datasources/utils.ts +32 -23
- package/src/components/debugger/debugger-code.tsx +5 -0
- package/src/components/dependency-graph/dependency-graph-tree.tsx +8 -8
- package/src/components/dependency-graph/elements.ts +24 -21
- package/src/components/dependency-graph/panels.tsx +2 -1
- package/src/components/dependency-graph/utils/__tests__/layout.test.ts +18 -11
- package/src/components/editor/SortableCell.tsx +1 -3
- package/src/{core/attachments/__tests__/toast.test.tsx → components/editor/__tests__/agent-toast.test.tsx} +1 -1
- package/src/components/editor/__tests__/data-attributes.test.tsx +6 -2
- package/src/components/editor/__tests__/dynamic-favicon.test.tsx +111 -18
- package/src/components/editor/__tests__/package-alert.test.tsx +22 -1
- package/src/components/editor/actions/__tests__/pair-with-agent-modal.test.tsx +24 -0
- package/src/components/editor/actions/pair-with-agent-modal.tsx +18 -15
- package/src/components/editor/actions/useRestartKernel.tsx +1 -1
- package/src/components/editor/ai/add-cell-with-ai.tsx +3 -3
- package/src/components/editor/ai/ai-completion-editor.tsx +1 -0
- package/src/components/editor/alerts/__tests__/connection-notice.test.tsx +1 -1
- package/src/components/editor/alerts/connection-notice.tsx +1 -1
- package/src/components/editor/alerts/startup-logs-alert.tsx +1 -0
- package/src/components/editor/app-container.tsx +1 -1
- package/src/components/editor/boundary/__tests__/ErrorBoundary.test.tsx +1 -1
- package/src/components/editor/cell/CreateCellButton.tsx +10 -12
- package/src/components/editor/cell/DeleteButton.tsx +3 -2
- package/src/components/editor/cell/RunButton.tsx +2 -2
- package/src/components/editor/cell/StopButton.tsx +2 -2
- package/src/components/editor/cell/__tests__/useShouldShowInterrupt.test.ts +39 -0
- package/src/components/editor/cell/code/__tests__/language-toggle.test.tsx +54 -0
- package/src/components/editor/cell/code/cell-editor.tsx +2 -2
- package/src/components/editor/cell/code/language-toggle.tsx +8 -7
- package/src/components/editor/cell/collapse.tsx +5 -3
- package/src/components/editor/cell/useShouldShowInterrupt.ts +2 -12
- package/src/components/editor/chrome/components/__tests__/feedback-button.test.tsx +1 -1
- package/src/components/editor/chrome/components/feedback-button.tsx +1 -1
- package/src/components/editor/chrome/panels/__tests__/packages-panel.test.tsx +31 -2
- package/src/components/editor/chrome/panels/__tests__/runtime-details.test.tsx +1 -1
- package/src/components/editor/chrome/panels/__tests__/sandbox-recovery.test.tsx +1 -1
- package/src/components/editor/chrome/panels/cache-panel.tsx +1 -0
- package/src/components/editor/chrome/panels/outline/__tests__/outline-keyboard.test.tsx +84 -0
- package/src/components/editor/chrome/panels/outline/floating-outline.tsx +39 -14
- package/src/components/editor/chrome/panels/outline/useActiveOutline.tsx +3 -2
- package/src/components/editor/chrome/panels/packages-panel.tsx +4 -7
- package/src/components/editor/chrome/panels/secrets-panel.tsx +1 -0
- package/src/components/editor/chrome/panels/snippets-panel.tsx +5 -1
- package/src/components/editor/chrome/wrapper/__tests__/attachment-status.test.tsx +9 -18
- package/src/components/editor/chrome/wrapper/__tests__/pending-ai-cells.test.tsx +58 -1
- package/src/components/editor/chrome/wrapper/footer-items/attachment-status.tsx +4 -4
- package/src/components/editor/chrome/wrapper/footer-items/backend-status.tsx +1 -1
- package/src/components/editor/chrome/wrapper/footer-items/lsp-status.tsx +1 -1
- package/src/components/editor/chrome/wrapper/footer-items/machine-stats.tsx +1 -1
- package/src/components/editor/chrome/wrapper/footer-items/runtime-settings.tsx +1 -7
- package/src/components/editor/chrome/wrapper/pending-ai-cells.tsx +12 -2
- package/src/components/editor/chrome/wrapper/storage.ts +1 -1
- package/src/components/editor/connections/components.tsx +1 -1
- package/src/components/editor/controls/Controls.tsx +2 -2
- package/src/components/editor/controls/__tests__/command-palette.test.tsx +53 -0
- package/src/components/editor/controls/__tests__/keyboard-shortcuts.test.tsx +61 -0
- package/src/components/editor/controls/__tests__/notebook-menu-dropdown.test.tsx +1 -1
- package/src/components/editor/controls/command-palette.tsx +22 -10
- package/src/components/editor/controls/keyboard-shortcuts.tsx +14 -5
- package/src/components/editor/dynamic-favicon.tsx +21 -40
- package/src/components/editor/errors/__tests__/send-error-report-button.test.tsx +9 -23
- package/src/components/editor/errors/send-error-report-button.tsx +3 -6
- package/src/components/editor/file-tree/__tests__/file-explorer-interactions.test.tsx +6 -0
- package/src/components/editor/file-tree/__tests__/file-explorer-navigation.test.tsx +47 -0
- package/src/components/editor/file-tree/__tests__/use-file-search.test.tsx +91 -0
- package/src/components/editor/file-tree/file-explorer.tsx +45 -8
- package/src/components/editor/file-tree/file-name-input.tsx +1 -0
- package/src/components/editor/file-tree/file-viewer.tsx +4 -2
- package/src/components/editor/file-tree/use-file-search.ts +35 -21
- package/src/components/editor/header/__tests__/status.test.tsx +5 -3
- package/src/components/editor/header/app-header.tsx +1 -1
- package/src/components/editor/header/status.tsx +40 -20
- package/src/components/editor/links/__tests__/cell-link.test.tsx +146 -0
- package/src/components/editor/links/cell-link.tsx +14 -5
- package/src/components/editor/navigation/focus-utils.ts +4 -4
- package/src/components/editor/notebook-banner.tsx +1 -0
- package/src/components/editor/notebook-cell.tsx +12 -3
- package/src/components/editor/output/MarimoErrorOutput.tsx +2 -1
- package/src/components/editor/output/MarimoTracebackOutput.tsx +19 -17
- package/src/components/editor/output/Outputs.css +8 -0
- package/src/components/editor/output/__tests__/traceback.test.tsx +27 -1
- package/src/components/editor/output/ansi-reduce.ts +33 -20
- package/src/components/editor/output/console/ConsoleOutput.tsx +19 -25
- package/src/components/editor/package-alert.tsx +14 -7
- package/src/components/editor/renderers/grid-layout/grid-layout.tsx +12 -6
- package/src/components/editor/renderers/vertical-layout/sidebar/toggle.tsx +7 -1
- package/src/components/home/components.tsx +17 -31
- package/src/components/icons/__tests__/large-spinner.test.tsx +39 -0
- package/src/components/icons/large-spinner.tsx +3 -14
- package/src/components/icons/spinner.tsx +1 -1
- package/src/components/mcp/mcp-status-indicator.tsx +1 -1
- package/src/components/pages/__tests__/home-page.test.tsx +116 -0
- package/src/components/pages/home-page.tsx +164 -91
- package/src/components/scratchpad/scratchpad.test.tsx +95 -0
- package/src/components/scratchpad/scratchpad.tsx +16 -3
- package/src/components/slides/reveal-component.tsx +4 -2
- package/src/components/slides/slide-cell-view.tsx +1 -1
- package/src/components/slides/slide-form.tsx +1 -0
- package/src/components/tracing/tracing-keyboard.test.tsx +85 -0
- package/src/components/tracing/tracing.tsx +45 -41
- package/src/components/ui/__tests__/draggable-popover.test.tsx +24 -0
- package/src/components/ui/__tests__/range-slider.test.tsx +165 -0
- package/src/components/ui/alert-dialog.tsx +1 -1
- package/src/components/ui/draggable-popover.tsx +24 -2
- package/src/components/ui/range-slider.tsx +22 -9
- package/src/core/ai/context/providers/datasource.ts +6 -2
- package/src/core/ai/tools/base.ts +16 -7
- package/src/core/ai/tools/edit-notebook-tool.ts +47 -45
- package/src/core/ai/tools/registry.ts +13 -8
- package/src/core/ai/tools/sample-tool.ts +6 -7
- package/src/core/cells/__tests__/__snapshots__/cells.test.ts.snap +4 -0
- package/src/core/cells/__tests__/cell.test.ts +39 -0
- package/src/core/cells/__tests__/cells.test.ts +3 -1
- package/src/core/cells/__tests__/collapseConsoleOutputs.test.ts +54 -0
- package/src/core/cells/__tests__/notebook-outline.test.ts +113 -0
- package/src/core/cells/__tests__/session.test.ts +117 -36
- package/src/core/cells/cell.ts +14 -3
- package/src/core/cells/cells.ts +3 -1
- package/src/core/cells/pending-delete-service.ts +2 -6
- package/src/core/cells/session.ts +1 -1
- package/src/core/cells/types.ts +10 -1
- package/src/core/codemirror/__tests__/setup.test.ts +29 -29
- package/src/core/codemirror/ai/__tests__/resources.test.ts +117 -0
- package/src/core/codemirror/ai/resources.ts +1 -1
- package/src/core/codemirror/cells/__tests__/extensions.test.ts +15 -0
- package/src/core/codemirror/cells/extensions.ts +7 -3
- package/src/core/codemirror/keymaps/vim.ts +2 -6
- package/src/core/codemirror/language/__tests__/sql.test.ts +22 -20
- package/src/core/codemirror/language/extension.ts +8 -8
- package/src/core/codemirror/language/languages/markdown.ts +8 -6
- package/src/core/codemirror/language/languages/python.ts +16 -10
- package/src/core/codemirror/language/languages/sql/sql.ts +9 -7
- package/src/core/codemirror/language/panel/panel.tsx +1 -0
- package/src/core/codemirror/language/types.ts +7 -7
- package/src/core/codemirror/readonly/__tests__/extension.test.ts +1 -1
- package/src/core/codemirror/readonly/extension.ts +2 -2
- package/src/core/codemirror/rtc/extension.ts +24 -12
- package/src/core/codemirror/rtc/loro/awareness.ts +34 -19
- package/src/core/codemirror/rtc/loro/sync.ts +1 -0
- package/src/core/codemirror/utils.ts +1 -0
- package/src/core/config/__tests__/config-schema.test.ts +5 -3
- package/src/core/config/config-schema.ts +3 -0
- package/src/core/datasets/__tests__/data-source-discovery.test.ts +5 -5
- package/src/core/datasets/data-source-discovery.ts +4 -6
- package/src/core/edit-app.tsx +2 -2
- package/src/core/errors/error-entries.ts +3 -0
- package/src/core/export/hooks.ts +1 -1
- package/src/core/hotkeys/actions.ts +2 -4
- package/src/core/islands/__tests__/bootstrap.test.ts +16 -42
- package/src/core/islands/__tests__/bridge.test.ts +31 -26
- package/src/core/islands/bootstrap.ts +22 -52
- package/src/core/islands/bridge.ts +31 -20
- package/src/core/islands/components/__tests__/IslandControls.test.tsx +7 -5
- package/src/core/islands/worker/__tests__/controller.test.ts +62 -4
- package/src/core/islands/worker/controller.ts +4 -10
- package/src/core/islands/worker/worker.tsx +33 -33
- package/src/core/kernel/__tests__/RuntimeState.test.ts +1 -1
- package/src/core/network/__tests__/connection.test.ts +1 -1
- package/src/core/network/connection-notice.ts +1 -1
- package/src/core/network/connection.ts +5 -3
- package/src/core/network/requests-lazy.ts +1 -1
- package/src/core/network/useConnectionNotice.ts +8 -2
- package/src/core/notebook/attachments.ts +38 -0
- package/src/core/notebook/document/__tests__/codemirror.test.ts +485 -0
- package/src/core/notebook/document/__tests__/draft.test.ts +322 -0
- package/src/core/notebook/document/__tests__/fixtures.ts +92 -0
- package/src/core/notebook/document/__tests__/hooks.test.tsx +391 -0
- package/src/core/notebook/document/__tests__/lifecycle-scenarios.test.ts +61 -0
- package/src/core/notebook/document/__tests__/model.test.ts +191 -0
- package/src/core/notebook/document/__tests__/protocol-fixtures.ts +38 -0
- package/src/core/notebook/document/__tests__/recovery-scenarios.test.ts +230 -0
- package/src/core/notebook/document/__tests__/scenario-fixture.ts +43 -0
- package/src/core/notebook/document/__tests__/scenarios.test.ts +205 -0
- package/src/core/notebook/document/__tests__/state.test.ts +438 -0
- package/src/core/notebook/document/__tests__/submission.test.ts +203 -0
- package/src/core/notebook/document/__tests__/test-host.test.ts +92 -0
- package/src/core/notebook/document/__tests__/test-host.ts +247 -0
- package/src/core/notebook/document/__tests__/test-notebook.ts +149 -0
- package/src/core/notebook/document/__tests__/user.ts +61 -0
- package/src/core/notebook/document/codemirror.ts +311 -0
- package/src/core/notebook/document/draft.ts +472 -0
- package/src/core/notebook/document/hooks.tsx +118 -0
- package/src/core/notebook/document/index.ts +15 -0
- package/src/core/notebook/document/model.ts +55 -0
- package/src/core/notebook/document/select.ts +41 -0
- package/src/core/notebook/document/state.ts +374 -0
- package/src/core/notebook/document/sync.ts +369 -0
- package/src/core/notebook/index.ts +18 -0
- package/src/core/notebook/replica/AGENTS.md +11 -0
- package/src/core/notebook/replica/__tests__/attachments.test.ts +56 -0
- package/src/core/notebook/replica/__tests__/document.test.ts +126 -0
- package/src/core/notebook/replica/__tests__/fixtures.ts +79 -0
- package/src/core/notebook/replica/__tests__/replica.test.ts +550 -0
- package/src/core/notebook/replica/backend.ts +19 -0
- package/src/core/notebook/replica/connection.ts +42 -0
- package/src/core/notebook/replica/index.ts +13 -0
- package/src/core/notebook/replica/replica.ts +286 -0
- package/src/core/notebook/replica/resources/attachments.ts +22 -0
- package/src/core/notebook/replica/resources/document.ts +101 -0
- package/src/core/packages/__tests__/useSandboxController.test.tsx +1 -1
- package/src/core/packages/useSandboxController.ts +1 -1
- package/src/core/run-app.tsx +3 -3
- package/src/core/runtime/__tests__/adapter.test.ts +1 -1
- package/src/core/runtime/__tests__/createWsUrl.test.ts +77 -7
- package/src/core/runtime/__tests__/runtime.test.ts +32 -58
- package/src/core/runtime/adapter.ts +1 -1
- package/src/core/runtime/config.ts +2 -2
- package/src/core/runtime/runtime.ts +38 -42
- package/src/core/runtime/types.ts +0 -2
- package/src/core/saving/filename.ts +1 -1
- package/src/core/saving/save-component.tsx +13 -4
- package/src/core/saving/useAutoSave.ts +1 -1
- package/src/core/session/__tests__/backend.test.ts +235 -0
- package/src/core/session/__tests__/useNotebookReplica.hook.test.tsx +183 -0
- package/src/core/session/__tests__/useNotebookSession.hook.test.tsx +609 -0
- package/src/core/session/active-notebook.ts +7 -0
- package/src/core/session/backend.ts +125 -0
- package/src/core/{websocket → session}/types.ts +2 -2
- package/src/core/session/useNotebookReplica.ts +72 -0
- package/src/core/{websocket → session}/useNotebookSession.tsx +18 -25
- package/src/core/state/__tests__/jotai.test.tsx +108 -0
- package/src/core/state/jotai.ts +1 -1
- package/src/core/static/__tests__/files.test.ts +38 -10
- package/src/core/static/files.ts +2 -0
- package/src/core/{websocket → transports}/__tests__/connection-state.test.ts +1 -13
- package/src/core/transports/__tests__/server.test.ts +408 -0
- package/src/core/transports/__tests__/static.test.ts +175 -0
- package/src/core/transports/__tests__/wasm.test.ts +166 -0
- package/src/core/{websocket → transports}/connection-state.ts +9 -16
- package/src/core/transports/server.ts +152 -0
- package/src/core/transports/static.ts +84 -0
- package/src/core/transports/wasm.ts +97 -0
- package/src/core/wasm/__tests__/bridge.test.ts +213 -50
- package/src/core/wasm/__tests__/worker.test.ts +187 -0
- package/src/core/wasm/bridge.ts +81 -52
- package/src/core/wasm/rpc.ts +15 -3
- package/src/core/wasm/store.ts +3 -3
- package/src/core/wasm/worker/bootstrap.ts +55 -51
- package/src/core/wasm/worker/getMarimoWheel.ts +1 -1
- package/src/core/wasm/worker/save-worker.ts +9 -10
- package/src/core/wasm/worker/types.ts +29 -18
- package/src/core/wasm/worker/worker.ts +97 -44
- package/src/css/globals.css +10 -0
- package/src/hooks/__tests__/useAsyncData.test.tsx +148 -0
- package/src/hooks/__tests__/useDebounce.test.tsx +51 -0
- package/src/hooks/__tests__/useDeepCompareMemoize.test.tsx +39 -0
- package/src/hooks/__tests__/useDelayElapsed.test.tsx +28 -0
- package/src/hooks/__tests__/useInternalStateWithSync.test.tsx +20 -0
- package/src/hooks/__tests__/useScript.test.tsx +77 -0
- package/src/hooks/__tests__/useStateForKey.test.tsx +257 -0
- package/src/hooks/useAsyncData.ts +3 -3
- package/src/hooks/useDataSourceDiscovery.ts +6 -4
- package/src/hooks/useDebounce.ts +6 -10
- package/src/hooks/useDeepCompareMemoize.ts +1 -1
- package/src/hooks/useDelayElapsed.ts +14 -10
- package/src/hooks/useElapsedTime.ts +3 -3
- package/src/hooks/useEventListener.ts +1 -2
- package/src/hooks/useInputHistory.ts +4 -7
- package/src/hooks/useInternalStateWithSync.ts +6 -6
- package/src/hooks/useResizeObserver.ts +4 -7
- package/src/hooks/useScript.ts +67 -70
- package/src/hooks/useStateForKey.ts +93 -0
- package/src/mount.tsx +1 -5
- package/src/plugins/__tests__/plugin-object-schemas.test.ts +104 -0
- package/src/plugins/core/registerReactComponent.tsx +1 -1
- package/src/plugins/impl/CodeEditorPlugin.tsx +1 -1
- package/src/plugins/impl/DataEditorPlugin.tsx +1 -1
- package/src/plugins/impl/DataTablePlugin.tsx +29 -33
- package/src/plugins/impl/DropdownPlugin.tsx +2 -6
- package/src/plugins/impl/FileBrowserPlugin.tsx +4 -16
- package/src/plugins/impl/FormPlugin.tsx +1 -1
- package/src/plugins/impl/RangeSliderPlugin.tsx +16 -2
- package/src/plugins/impl/RefreshPlugin.tsx +1 -0
- package/src/plugins/impl/SliderPlugin.tsx +6 -8
- package/src/plugins/impl/__tests__/DataTablePlugin.test.tsx +117 -1
- package/src/plugins/impl/__tests__/FileBrowserPlugin.test.tsx +45 -0
- package/src/plugins/impl/__tests__/RangeSliderPlugin.test.tsx +109 -0
- package/src/plugins/impl/__tests__/SliderPlugin.test.tsx +24 -3
- package/src/plugins/impl/anywidget/__tests__/registry.test.ts +153 -0
- package/src/plugins/impl/anywidget/__tests__/widget-binding.test.ts +241 -2
- package/src/plugins/impl/anywidget/model.ts +3 -1
- package/src/plugins/impl/anywidget/registry.ts +18 -14
- package/src/plugins/impl/anywidget/runtime.ts +21 -9
- package/src/plugins/impl/anywidget/widget-binding.ts +160 -82
- package/src/plugins/impl/chat/__tests__/chat-prompts.test.tsx +93 -0
- package/src/plugins/impl/chat/chat-ui.tsx +14 -11
- package/src/plugins/impl/code/any-language-editor.tsx +2 -2
- package/src/plugins/impl/data-editor/glide-data-editor.tsx +8 -5
- package/src/plugins/impl/data-editor/glide-utils.ts +3 -1
- package/src/plugins/impl/data-explorer/ConnectedDataExplorerComponent.tsx +1 -1
- package/src/plugins/impl/data-explorer/components/column-summary.tsx +4 -2
- package/src/plugins/impl/data-explorer/state/reducer.ts +1 -1
- package/src/plugins/impl/data-frames/DataFramePlugin.tsx +1 -2
- package/src/plugins/impl/data-frames/__tests__/sidebar.test.tsx +160 -0
- package/src/plugins/impl/data-frames/forms/__tests__/__snapshots__/form.test.tsx.snap +66 -66
- package/src/plugins/impl/data-frames/panel.tsx +43 -16
- package/src/plugins/impl/mpl-interactive/MplInteractivePlugin.tsx +5 -3
- package/src/plugins/impl/panel/PanelPlugin.tsx +16 -17
- package/src/plugins/impl/panel/__tests__/utils.test.ts +39 -1
- package/src/plugins/impl/panel/utils.ts +17 -0
- package/src/plugins/impl/plotly/PlotlyPlugin.tsx +2 -5
- package/src/plugins/impl/plotly/selection.ts +25 -19
- package/src/plugins/impl/vega/VegaPlugin.tsx +2 -3
- package/src/plugins/impl/vega/make-selectable.ts +4 -7
- package/src/plugins/layout/RoutesPlugin.tsx +1 -1
- package/src/stories/__tests__/editor-story.test.tsx +33 -0
- package/src/stories/button.stories.tsx +1 -0
- package/src/stories/cell.stories.tsx +1 -1
- package/src/stories/editor.stories.tsx +24 -17
- package/src/stories/form-wrapper.stories.tsx +2 -2
- package/src/stories/layout/vertical/one-column.stories.tsx +1 -1
- package/src/stories/runtime-story.tsx +1 -1
- package/src/stories/select.stories.tsx +2 -2
- package/src/stories/switchable-multi-select.stories.tsx +1 -1
- package/src/utils/__tests__/arrays.test.ts +35 -0
- package/src/utils/__tests__/batch-requests.test.ts +3 -3
- package/src/utils/__tests__/createReducer.test.ts +1 -0
- package/src/utils/__tests__/numbers.test.ts +105 -1
- package/src/utils/__tests__/objects.test.ts +21 -0
- package/src/utils/arrays.ts +11 -2
- package/src/utils/blob.ts +1 -1
- package/src/utils/createReducer.ts +11 -5
- package/src/utils/maps.ts +0 -3
- package/src/utils/numbers.ts +79 -18
- package/src/utils/objects.ts +4 -9
- package/src/utils/once.ts +19 -19
- package/src/utils/tracer.ts +9 -5
- package/src/utils/zod-utils.ts +1 -3
- package/dist/any-language-editor-DZ_YTVus.js +0 -76
- package/dist/assets/__vite-browser-external-BXYkiFsk.js +0 -1
- package/dist/assets/worker-HPY9fbhz.js +0 -114
- package/dist/mermaid-HWGCJPDP-ByCsZnYF.js +0 -2
- package/dist/precisionRound-DMIVQrt2.js +0 -97
- package/src/core/attachments/state.ts +0 -21
- package/src/core/host/AGENTS.md +0 -6
- package/src/core/host/__tests__/events.test.ts +0 -46
- package/src/core/host/__tests__/notebook-client.test.ts +0 -191
- package/src/core/host/__tests__/protocol.test.ts +0 -214
- package/src/core/host/connection.ts +0 -81
- package/src/core/host/events.ts +0 -60
- package/src/core/host/notebook-client.ts +0 -226
- package/src/core/host/protocol.ts +0 -1943
- package/src/core/state/__tests__/jotai.test.ts +0 -25
- package/src/core/wasm/worker/message-buffer.ts +0 -33
- package/src/core/websocket/__tests__/createConnectionTransport.test.ts +0 -49
- package/src/core/websocket/__tests__/useNotebookClient.hook.test.tsx +0 -140
- package/src/core/websocket/__tests__/useNotebookSession.hook.test.tsx +0 -883
- package/src/core/websocket/transports/__tests__/basic.test.ts +0 -275
- package/src/core/websocket/transports/__tests__/sse.test.ts +0 -335
- package/src/core/websocket/transports/__tests__/transport.test.ts +0 -308
- package/src/core/websocket/transports/__tests__/ws.test.ts +0 -125
- package/src/core/websocket/transports/basic.ts +0 -102
- package/src/core/websocket/transports/create.ts +0 -31
- package/src/core/websocket/transports/sse.ts +0 -308
- package/src/core/websocket/transports/transport.ts +0 -50
- package/src/core/websocket/transports/ws.ts +0 -98
- package/src/core/websocket/useNotebookClient.ts +0 -80
- /package/src/{core/attachments/toast.ts → components/editor/agent-toast.ts} +0 -0
- /package/src/core/{websocket → session}/connection-utils.ts +0 -0
|
@@ -59,7 +59,7 @@ import {
|
|
|
59
59
|
shouldHidePublishedCell,
|
|
60
60
|
} from "../../core/cells/utils";
|
|
61
61
|
import type { UserConfig } from "../../core/config/config-schema";
|
|
62
|
-
import { isAppInteractionDisabled } from "../../core/
|
|
62
|
+
import { isAppInteractionDisabled } from "../../core/session/connection-utils";
|
|
63
63
|
import { useCellRenderCount } from "../../hooks/useCellRenderCount";
|
|
64
64
|
import type { Theme } from "../../theme/useTheme";
|
|
65
65
|
import { Functions } from "../../utils/functions";
|
|
@@ -525,13 +525,22 @@ const EditableCellComponent = ({
|
|
|
525
525
|
isMarkdownCodeHidden &&
|
|
526
526
|
isEmptyMarkdownContent &&
|
|
527
527
|
!needsRun && (
|
|
528
|
+
// Preserve pointer double-click editing; keyboard and assistive clicks activate directly.
|
|
529
|
+
// react-doctor-disable-next-line react-doctor/prefer-tag-over-role
|
|
528
530
|
<div
|
|
531
|
+
// eslint-disable-next-line jsx-a11y/prefer-tag-over-role
|
|
529
532
|
role="button"
|
|
530
|
-
aria-label="
|
|
533
|
+
aria-label="Edit markdown"
|
|
531
534
|
className="relative cursor-pointer px-3 py-2"
|
|
532
535
|
onDoubleClick={showHiddenCodeIfMarkdown}
|
|
536
|
+
onClick={(e) => {
|
|
537
|
+
if (e.detail === 0) {
|
|
538
|
+
showHiddenCodeIfMarkdown();
|
|
539
|
+
}
|
|
540
|
+
}}
|
|
533
541
|
onKeyDown={(e) => {
|
|
534
|
-
if (e.key === "Enter") {
|
|
542
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
543
|
+
e.preventDefault();
|
|
535
544
|
showHiddenCodeIfMarkdown();
|
|
536
545
|
}
|
|
537
546
|
}}
|
|
@@ -207,7 +207,8 @@ export const MarimoErrorOutput = ({
|
|
|
207
207
|
e.type === "ancestor-stopped",
|
|
208
208
|
);
|
|
209
209
|
const syntaxErrors = errors.filter(
|
|
210
|
-
(e): e is Extract<MarimoError, { type: "syntax" }> =>
|
|
210
|
+
(e): e is Extract<MarimoError, { type: "syntax" | "lazy-import" }> =>
|
|
211
|
+
e.type === "syntax" || e.type === "lazy-import",
|
|
211
212
|
);
|
|
212
213
|
const unknownErrors = errors.filter(
|
|
213
214
|
(e): e is Extract<MarimoError, { type: "unknown" }> => e.type === "unknown",
|
|
@@ -248,21 +248,22 @@ export const replaceTracebackFilenames = (domNode: DOMNode) => {
|
|
|
248
248
|
<Tooltip content={tooltipContent}>
|
|
249
249
|
<button
|
|
250
250
|
type="button"
|
|
251
|
-
|
|
251
|
+
aria-label={
|
|
252
|
+
debuggerEnabled ? "Toggle breakpoint" : "Insert breakpoint"
|
|
253
|
+
}
|
|
254
|
+
className="ml-1 p-1 rounded-sm hover:bg-muted transition-colors inline"
|
|
255
|
+
onClick={() => {
|
|
256
|
+
if (debuggerEnabled && !isStaticNotebook()) {
|
|
257
|
+
toggleBreakpoint(info.cellId, info.lineNumber);
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
const view = getCellEditorView(info.cellId);
|
|
261
|
+
if (view) {
|
|
262
|
+
insertDebuggerAtLine(view, info.lineNumber);
|
|
263
|
+
}
|
|
264
|
+
}}
|
|
252
265
|
>
|
|
253
|
-
<BugPlayIcon
|
|
254
|
-
onClick={() => {
|
|
255
|
-
if (debuggerEnabled && !isStaticNotebook()) {
|
|
256
|
-
toggleBreakpoint(info.cellId, info.lineNumber);
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
const view = getCellEditorView(info.cellId);
|
|
260
|
-
if (view) {
|
|
261
|
-
insertDebuggerAtLine(view, info.lineNumber);
|
|
262
|
-
}
|
|
263
|
-
}}
|
|
264
|
-
className="h-3 w-3"
|
|
265
|
-
/>
|
|
266
|
+
<BugPlayIcon className="h-3 w-3" />
|
|
266
267
|
</button>
|
|
267
268
|
</Tooltip>
|
|
268
269
|
)}
|
|
@@ -272,9 +273,10 @@ export const replaceTracebackFilenames = (domNode: DOMNode) => {
|
|
|
272
273
|
}
|
|
273
274
|
if (info?.kind === "file") {
|
|
274
275
|
return (
|
|
275
|
-
<
|
|
276
|
+
<button
|
|
277
|
+
type="button"
|
|
276
278
|
className="inline-block cursor-pointer text-destructive hover:underline"
|
|
277
|
-
onClick={(
|
|
279
|
+
onClick={() => {
|
|
278
280
|
getRequestClient().openFile({
|
|
279
281
|
path: info.filePath,
|
|
280
282
|
lineNumber: info.lineNumber,
|
|
@@ -282,7 +284,7 @@ export const replaceTracebackFilenames = (domNode: DOMNode) => {
|
|
|
282
284
|
}}
|
|
283
285
|
>
|
|
284
286
|
<span className="nb">"{info.filePath}"</span>
|
|
285
|
-
</
|
|
287
|
+
</button>
|
|
286
288
|
);
|
|
287
289
|
}
|
|
288
290
|
};
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
|
-
import { render } from "@testing-library/react";
|
|
3
|
+
import { fireEvent, render, screen } from "@testing-library/react";
|
|
4
4
|
import { Provider } from "jotai";
|
|
5
5
|
import { beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
|
6
6
|
import { MockRequestClient } from "@/__mocks__/requests";
|
|
7
7
|
import { Tracebacks } from "@/__mocks__/tracebacks";
|
|
8
8
|
import { cellId } from "@/__tests__/branded";
|
|
9
|
+
import { toggleBreakpoint } from "@/core/codemirror/cells/debugger-state";
|
|
9
10
|
import { TooltipProvider } from "@/components/ui/tooltip";
|
|
10
11
|
import { initialModeAtom } from "@/core/mode";
|
|
11
12
|
import { requestClientAtom } from "@/core/network/requests";
|
|
@@ -19,7 +20,32 @@ import {
|
|
|
19
20
|
|
|
20
21
|
const cid = cellId("1");
|
|
21
22
|
|
|
23
|
+
vi.mock("@/core/config/feature-flag", async (importOriginal) => ({
|
|
24
|
+
...(await importOriginal<typeof import("@/core/config/feature-flag")>()),
|
|
25
|
+
getFeatureFlag: (flag: string) => flag === "debugger",
|
|
26
|
+
}));
|
|
27
|
+
vi.mock("@/core/codemirror/cells/debugger-state", async (importOriginal) => ({
|
|
28
|
+
...(await importOriginal<
|
|
29
|
+
typeof import("@/core/codemirror/cells/debugger-state")
|
|
30
|
+
>()),
|
|
31
|
+
toggleBreakpoint: vi.fn(),
|
|
32
|
+
}));
|
|
33
|
+
|
|
22
34
|
describe("traceback component", () => {
|
|
35
|
+
test("activates the breakpoint from the named button itself", () => {
|
|
36
|
+
render(
|
|
37
|
+
<Provider store={store}>
|
|
38
|
+
<TooltipProvider>
|
|
39
|
+
<MarimoTracebackOutput traceback={Tracebacks.raw} cellId={cid} />
|
|
40
|
+
</TooltipProvider>
|
|
41
|
+
</Provider>,
|
|
42
|
+
);
|
|
43
|
+
const buttons = screen.getAllByRole("button", {
|
|
44
|
+
name: "Toggle breakpoint",
|
|
45
|
+
});
|
|
46
|
+
fireEvent.click(buttons[0]);
|
|
47
|
+
expect(toggleBreakpoint).toHaveBeenCalledOnce();
|
|
48
|
+
});
|
|
23
49
|
beforeEach(() => {
|
|
24
50
|
vi.resetAllMocks();
|
|
25
51
|
store.set(initialModeAtom, "edit");
|
|
@@ -358,6 +358,7 @@ export class AnsiReducer {
|
|
|
358
358
|
|
|
359
359
|
export type StringOutputMessage = Omit<OutputMessage, "data"> & {
|
|
360
360
|
data: string;
|
|
361
|
+
id?: number;
|
|
361
362
|
};
|
|
362
363
|
|
|
363
364
|
/**
|
|
@@ -369,6 +370,7 @@ export class StatefulOutputMessage implements OutputMessage {
|
|
|
369
370
|
public readonly channel: OutputMessage["channel"];
|
|
370
371
|
public readonly timestamp: OutputMessage["timestamp"];
|
|
371
372
|
public readonly code: OutputMessage["code"];
|
|
373
|
+
public readonly id: StringOutputMessage["id"];
|
|
372
374
|
private ansiReducer = new AnsiReducer();
|
|
373
375
|
private _data: string;
|
|
374
376
|
|
|
@@ -379,39 +381,50 @@ export class StatefulOutputMessage implements OutputMessage {
|
|
|
379
381
|
public static create(message: StringOutputMessage): StatefulOutputMessage {
|
|
380
382
|
const ansiReducer = new AnsiReducer();
|
|
381
383
|
ansiReducer.append(message.data);
|
|
382
|
-
return new StatefulOutputMessage(
|
|
383
|
-
message.mimetype,
|
|
384
|
-
message.channel,
|
|
385
|
-
message.timestamp,
|
|
384
|
+
return new StatefulOutputMessage({
|
|
385
|
+
mimetype: message.mimetype,
|
|
386
|
+
channel: message.channel,
|
|
387
|
+
timestamp: message.timestamp,
|
|
386
388
|
ansiReducer,
|
|
387
|
-
message.code,
|
|
388
|
-
|
|
389
|
+
code: message.code,
|
|
390
|
+
id: message.id,
|
|
391
|
+
});
|
|
389
392
|
}
|
|
390
393
|
|
|
391
|
-
private constructor(
|
|
392
|
-
mimetype
|
|
393
|
-
channel
|
|
394
|
-
timestamp
|
|
395
|
-
ansiReducer
|
|
396
|
-
code
|
|
397
|
-
|
|
394
|
+
private constructor({
|
|
395
|
+
mimetype,
|
|
396
|
+
channel,
|
|
397
|
+
timestamp,
|
|
398
|
+
ansiReducer,
|
|
399
|
+
code,
|
|
400
|
+
id,
|
|
401
|
+
}: {
|
|
402
|
+
mimetype: OutputMessage["mimetype"];
|
|
403
|
+
channel: OutputMessage["channel"];
|
|
404
|
+
timestamp: OutputMessage["timestamp"];
|
|
405
|
+
ansiReducer: AnsiReducer;
|
|
406
|
+
code: OutputMessage["code"];
|
|
407
|
+
id: StringOutputMessage["id"];
|
|
408
|
+
}) {
|
|
398
409
|
this.mimetype = mimetype;
|
|
399
410
|
this.channel = channel;
|
|
400
411
|
this.timestamp = timestamp;
|
|
401
412
|
this.code = code;
|
|
413
|
+
this.id = id;
|
|
402
414
|
this.ansiReducer = ansiReducer;
|
|
403
415
|
this._data = this.ansiReducer.render();
|
|
404
416
|
}
|
|
405
417
|
|
|
406
418
|
public appendData(chunk: string): StatefulOutputMessage {
|
|
407
419
|
this.ansiReducer.append(chunk);
|
|
408
|
-
return new StatefulOutputMessage(
|
|
409
|
-
this.mimetype,
|
|
410
|
-
this.channel,
|
|
411
|
-
this.timestamp,
|
|
412
|
-
this.ansiReducer,
|
|
413
|
-
this.code,
|
|
414
|
-
|
|
420
|
+
return new StatefulOutputMessage({
|
|
421
|
+
mimetype: this.mimetype,
|
|
422
|
+
channel: this.channel,
|
|
423
|
+
timestamp: this.timestamp,
|
|
424
|
+
ansiReducer: this.ansiReducer,
|
|
425
|
+
code: this.code,
|
|
426
|
+
id: this.id,
|
|
427
|
+
});
|
|
415
428
|
}
|
|
416
429
|
|
|
417
430
|
public toJSON(): StringOutputMessage {
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
ChevronsUpDownIcon,
|
|
7
7
|
WrapTextIcon,
|
|
8
8
|
} from "lucide-react";
|
|
9
|
-
import React, { useEffect, useLayoutEffect,
|
|
9
|
+
import React, { useEffect, useLayoutEffect, useState } from "react";
|
|
10
10
|
import { ToggleButton } from "react-aria-components";
|
|
11
11
|
import { DebuggerControls } from "@/components/debugger/debugger-code";
|
|
12
12
|
import { CopyClipboardIcon } from "@/components/icons/copy-icon";
|
|
@@ -16,8 +16,7 @@ import { Tooltip } from "@/components/ui/tooltip";
|
|
|
16
16
|
import type { CellId } from "@/core/cells/ids";
|
|
17
17
|
import { isInternalCellName } from "@/core/cells/names";
|
|
18
18
|
import { useExpandedConsoleOutput } from "@/core/cells/outputs";
|
|
19
|
-
import type {
|
|
20
|
-
import type { OutputMessage } from "@/core/kernel/messages";
|
|
19
|
+
import type { ConsoleOutputMessage } from "@/core/cells/types";
|
|
21
20
|
import {
|
|
22
21
|
type UseInputHistoryReturn,
|
|
23
22
|
useInputHistory,
|
|
@@ -49,31 +48,21 @@ export const CONSOLE_CLEAR_DEBOUNCE_MS = 200;
|
|
|
49
48
|
*/
|
|
50
49
|
function useDebouncedConsoleOutputs<T>(outputs: T[]): T[] {
|
|
51
50
|
const [debouncedOutputs, setDebouncedOutputs] = useState(outputs);
|
|
52
|
-
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
53
51
|
|
|
54
|
-
// Non-empty outputs: apply immediately
|
|
52
|
+
// Non-empty outputs: apply immediately. Effect cleanup cancels pending clears.
|
|
55
53
|
if (outputs.length > 0 && debouncedOutputs !== outputs) {
|
|
56
|
-
if (timerRef.current !== null) {
|
|
57
|
-
clearTimeout(timerRef.current);
|
|
58
|
-
timerRef.current = null;
|
|
59
|
-
}
|
|
60
54
|
setDebouncedOutputs(outputs);
|
|
61
55
|
}
|
|
62
56
|
|
|
63
57
|
// Empty outputs: delay the clear so new outputs can arrive first
|
|
64
58
|
useEffect(() => {
|
|
65
|
-
if (outputs.length
|
|
66
|
-
|
|
67
|
-
timerRef.current = null;
|
|
68
|
-
setDebouncedOutputs([]);
|
|
69
|
-
}, CONSOLE_CLEAR_DEBOUNCE_MS);
|
|
59
|
+
if (outputs.length > 0) {
|
|
60
|
+
return;
|
|
70
61
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
};
|
|
62
|
+
const timer = setTimeout(() => {
|
|
63
|
+
setDebouncedOutputs([]);
|
|
64
|
+
}, CONSOLE_CLEAR_DEBOUNCE_MS);
|
|
65
|
+
return () => clearTimeout(timer);
|
|
77
66
|
}, [outputs]);
|
|
78
67
|
|
|
79
68
|
return debouncedOutputs;
|
|
@@ -83,7 +72,7 @@ interface Props {
|
|
|
83
72
|
cellId: CellId;
|
|
84
73
|
cellName: string;
|
|
85
74
|
className?: string;
|
|
86
|
-
consoleOutputs:
|
|
75
|
+
consoleOutputs: ConsoleOutputMessage[];
|
|
87
76
|
stale: boolean;
|
|
88
77
|
interrupted: boolean;
|
|
89
78
|
debuggerActive: boolean;
|
|
@@ -251,19 +240,24 @@ const ConsoleOutputInternal = (props: Props): React.ReactNode => {
|
|
|
251
240
|
return null;
|
|
252
241
|
}
|
|
253
242
|
|
|
243
|
+
const originalIdx = consoleOutputs.length - idx - 1;
|
|
244
|
+
// Outputs render in reverse, so the reversed index shifts on every
|
|
245
|
+
// new line. The assigned id survives collapse and truncation. The
|
|
246
|
+
// original position is the fallback for outputs without one.
|
|
247
|
+
const key = output.id ?? `position-${originalIdx}`;
|
|
248
|
+
|
|
254
249
|
if (output.channel === "stdin") {
|
|
255
250
|
invariant(
|
|
256
251
|
typeof output.data === "string",
|
|
257
252
|
"Expected data to be a string",
|
|
258
253
|
);
|
|
259
254
|
|
|
260
|
-
const originalIdx = consoleOutputs.length - idx - 1;
|
|
261
255
|
const isPassword = output.mimetype === "text/password";
|
|
262
256
|
|
|
263
257
|
if (output.response == null && lastStdInputIdx === idx) {
|
|
264
258
|
return (
|
|
265
259
|
<StdInput
|
|
266
|
-
key={
|
|
260
|
+
key={key}
|
|
267
261
|
output={output.data}
|
|
268
262
|
isPdb={isPdb}
|
|
269
263
|
isPassword={isPassword}
|
|
@@ -278,7 +272,7 @@ const ConsoleOutputInternal = (props: Props): React.ReactNode => {
|
|
|
278
272
|
|
|
279
273
|
return (
|
|
280
274
|
<StdInputWithResponse
|
|
281
|
-
key={
|
|
275
|
+
key={key}
|
|
282
276
|
output={output.data}
|
|
283
277
|
response={output.response}
|
|
284
278
|
isPassword={isPassword}
|
|
@@ -288,7 +282,7 @@ const ConsoleOutputInternal = (props: Props): React.ReactNode => {
|
|
|
288
282
|
}
|
|
289
283
|
|
|
290
284
|
return (
|
|
291
|
-
<React.Fragment key={
|
|
285
|
+
<React.Fragment key={key}>
|
|
292
286
|
<OutputRenderer
|
|
293
287
|
cellId={cellId}
|
|
294
288
|
onRefactorWithAI={onRefactorWithAI}
|
|
@@ -55,6 +55,7 @@ import {
|
|
|
55
55
|
DropdownMenu,
|
|
56
56
|
DropdownMenuCheckboxItem,
|
|
57
57
|
DropdownMenuContent,
|
|
58
|
+
DropdownMenuItem,
|
|
58
59
|
DropdownMenuTrigger,
|
|
59
60
|
} from "../ui/dropdown-menu";
|
|
60
61
|
import { ExternalLink } from "../ui/links";
|
|
@@ -158,6 +159,7 @@ export const PackageAlert: React.FC = () => {
|
|
|
158
159
|
<SourceBadge source={packageAlert.source} />
|
|
159
160
|
</span>
|
|
160
161
|
<Button
|
|
162
|
+
aria-label="Dismiss missing packages alert"
|
|
161
163
|
variant="text"
|
|
162
164
|
data-testid="remove-banner-button"
|
|
163
165
|
size="icon"
|
|
@@ -171,12 +173,12 @@ export const PackageAlert: React.FC = () => {
|
|
|
171
173
|
<p>The following packages were not found:</p>
|
|
172
174
|
<table className="list-disc ml-2 mt-1">
|
|
173
175
|
<tbody>
|
|
174
|
-
{packageAlert.packages.map((pkg
|
|
176
|
+
{packageAlert.packages.map((pkg) => {
|
|
175
177
|
const parsed = parsePackageSpecifier(pkg);
|
|
176
178
|
const currentExtras = selectedExtras[pkg] || parsed.extras;
|
|
177
179
|
|
|
178
180
|
return (
|
|
179
|
-
<tr className="font-mono text-sm" key={
|
|
181
|
+
<tr className="font-mono text-sm" key={pkg}>
|
|
180
182
|
<td className="pr-2 py-1 align-middle">
|
|
181
183
|
<BoxIcon size="1rem" />
|
|
182
184
|
</td>
|
|
@@ -270,6 +272,7 @@ export const PackageAlert: React.FC = () => {
|
|
|
270
272
|
<SourceBadge source={packageAlert.source} />
|
|
271
273
|
</span>
|
|
272
274
|
<Button
|
|
275
|
+
aria-label={`Dismiss ${title}`}
|
|
273
276
|
variant="text"
|
|
274
277
|
data-testid="remove-banner-button"
|
|
275
278
|
size="icon"
|
|
@@ -294,7 +297,7 @@ export const PackageAlert: React.FC = () => {
|
|
|
294
297
|
</>
|
|
295
298
|
)}
|
|
296
299
|
<ul className="list-disc ml-2 mt-1">
|
|
297
|
-
{Object.entries(packageAlert.packages).map(([pkg, st]
|
|
300
|
+
{Object.entries(packageAlert.packages).map(([pkg, st]) => (
|
|
298
301
|
<li
|
|
299
302
|
className={cn(
|
|
300
303
|
"flex items-center gap-1 font-mono text-sm",
|
|
@@ -305,7 +308,7 @@ export const PackageAlert: React.FC = () => {
|
|
|
305
308
|
status === "failed" &&
|
|
306
309
|
"text-muted-foreground",
|
|
307
310
|
)}
|
|
308
|
-
key={
|
|
311
|
+
key={pkg}
|
|
309
312
|
>
|
|
310
313
|
<ProgressIcon status={st} />
|
|
311
314
|
{pkg}
|
|
@@ -590,14 +593,18 @@ const ExtrasSelector: React.FC<ExtrasSelectorProps> = ({
|
|
|
590
593
|
<div className="p-2 bg-popover border-b border-border">
|
|
591
594
|
<div className="flex flex-wrap gap-1 p-1 min-h-[24px]">
|
|
592
595
|
{selectedExtras.map((extra) => (
|
|
593
|
-
<
|
|
596
|
+
<DropdownMenuItem
|
|
594
597
|
key={extra}
|
|
598
|
+
aria-label={`Remove ${extra}`}
|
|
595
599
|
className="inline-flex items-center gap-1 px-1 py-0.5 text-sm font-mono border border-muted-foreground/30 hover:border-muted-foreground/60 rounded-sm cursor-pointer group transition-colors"
|
|
596
|
-
|
|
600
|
+
onSelect={(e) => {
|
|
601
|
+
e.preventDefault();
|
|
602
|
+
handleExtraToggle(extra, false);
|
|
603
|
+
}}
|
|
597
604
|
>
|
|
598
605
|
{extra}
|
|
599
606
|
<XIcon className="w-3 h-3 opacity-60 group-hover:opacity-100" />
|
|
600
|
-
</
|
|
607
|
+
</DropdownMenuItem>
|
|
601
608
|
))}
|
|
602
609
|
</div>
|
|
603
610
|
</div>
|
|
@@ -190,12 +190,18 @@ export const GridLayoutRenderer: React.FC<Props> = ({
|
|
|
190
190
|
cells: [...cellLayouts, dropped],
|
|
191
191
|
});
|
|
192
192
|
}}
|
|
193
|
-
onDragStart={
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
}
|
|
193
|
+
onDragStart={
|
|
194
|
+
// oxlint-disable-next-line marimo/prefer-object-params -- React Grid Layout supplies the event as the fifth argument.
|
|
195
|
+
(_layout, _oldItem, _newItem, _placeholder, event) => {
|
|
196
|
+
dragProps.onDragStart(event);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
onDrag={
|
|
200
|
+
// oxlint-disable-next-line marimo/prefer-object-params -- React Grid Layout supplies the event as the fifth argument.
|
|
201
|
+
(_layout, _oldItem, _newItem, _placeholder, event) => {
|
|
202
|
+
dragProps.onDragMove(event);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
199
205
|
onDragStop={() => {
|
|
200
206
|
dragProps.onDragStop();
|
|
201
207
|
}}
|
|
@@ -12,7 +12,13 @@ interface SidebarToggleProps {
|
|
|
12
12
|
export const SidebarToggle = ({ isOpen, toggle }: SidebarToggleProps) => {
|
|
13
13
|
return (
|
|
14
14
|
<div className="invisible lg:visible absolute top-[12px] right-[16px] z-20">
|
|
15
|
-
<Button
|
|
15
|
+
<Button
|
|
16
|
+
aria-label={isOpen ? "Collapse sidebar" : "Expand sidebar"}
|
|
17
|
+
onClick={toggle}
|
|
18
|
+
className="w-10 h-8"
|
|
19
|
+
variant="ghost"
|
|
20
|
+
size="icon"
|
|
21
|
+
>
|
|
16
22
|
<ChevronLeft
|
|
17
23
|
className={cn(
|
|
18
24
|
"h-5 w-5 transition-transform ease-in-out duration-700",
|
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
GraduationCapIcon,
|
|
13
13
|
GridIcon,
|
|
14
14
|
LayoutIcon,
|
|
15
|
-
LinkIcon,
|
|
16
15
|
MessagesSquareIcon,
|
|
17
16
|
OrbitIcon,
|
|
18
17
|
PackageIcon,
|
|
@@ -82,7 +81,12 @@ export const OpenTutorialDropDown: React.FC = () => {
|
|
|
82
81
|
return (
|
|
83
82
|
<DropdownMenu>
|
|
84
83
|
<DropdownMenuTrigger asChild={true}>
|
|
85
|
-
<Button
|
|
84
|
+
<Button
|
|
85
|
+
data-testid="open-tutorial-button"
|
|
86
|
+
size="sm"
|
|
87
|
+
variant="outline"
|
|
88
|
+
className="border-border text-(--gray-11) shadow-none hover:border-(--gray-7) hover:bg-(--gray-3)"
|
|
89
|
+
>
|
|
86
90
|
<GraduationCapIcon className="w-4 h-4 mr-2" />
|
|
87
91
|
Tutorials
|
|
88
92
|
<CaretDownIcon className="w-3 h-3 ml-1" />
|
|
@@ -135,7 +139,7 @@ const RESOURCES = [
|
|
|
135
139
|
url: Constants.githubPage,
|
|
136
140
|
},
|
|
137
141
|
{
|
|
138
|
-
title: "
|
|
142
|
+
title: "Discussion",
|
|
139
143
|
description: "Join the marimo Discord community",
|
|
140
144
|
icon: MessagesSquareIcon,
|
|
141
145
|
url: Constants.discordLink,
|
|
@@ -162,9 +166,11 @@ const RESOURCES = [
|
|
|
162
166
|
|
|
163
167
|
export const ResourceLinks: React.FC = () => {
|
|
164
168
|
return (
|
|
165
|
-
<
|
|
166
|
-
|
|
167
|
-
|
|
169
|
+
<nav
|
|
170
|
+
aria-label="Resources"
|
|
171
|
+
className="mt-12 border-t border-border/60 pt-6"
|
|
172
|
+
>
|
|
173
|
+
<div className="flex flex-wrap items-center gap-x-6 gap-y-4">
|
|
168
174
|
{RESOURCES.map((resource) => (
|
|
169
175
|
<a
|
|
170
176
|
key={resource.title}
|
|
@@ -172,19 +178,15 @@ export const ResourceLinks: React.FC = () => {
|
|
|
172
178
|
target="_blank"
|
|
173
179
|
rel="noreferrer"
|
|
174
180
|
aria-label={`${resource.title}: ${resource.description}`}
|
|
175
|
-
|
|
181
|
+
title={resource.description}
|
|
182
|
+
className="flex items-center gap-2 rounded-sm text-sm text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-ring"
|
|
176
183
|
>
|
|
177
|
-
<resource.icon className="
|
|
178
|
-
<
|
|
179
|
-
<h3 className="font-medium">{resource.title}</h3>
|
|
180
|
-
<p className="text-sm text-muted-foreground">
|
|
181
|
-
{resource.description}
|
|
182
|
-
</p>
|
|
183
|
-
</div>
|
|
184
|
+
<resource.icon className="h-4 w-4" />
|
|
185
|
+
<span>{resource.title}</span>
|
|
184
186
|
</a>
|
|
185
187
|
))}
|
|
186
188
|
</div>
|
|
187
|
-
</
|
|
189
|
+
</nav>
|
|
188
190
|
);
|
|
189
191
|
};
|
|
190
192
|
|
|
@@ -203,19 +205,3 @@ export const TruncatedWorkspaceBanner: React.FC<{
|
|
|
203
205
|
</Banner>
|
|
204
206
|
);
|
|
205
207
|
};
|
|
206
|
-
|
|
207
|
-
export const Header: React.FC<{
|
|
208
|
-
Icon: React.FC<React.SVGProps<SVGSVGElement>>;
|
|
209
|
-
control?: React.ReactNode;
|
|
210
|
-
children: React.ReactNode;
|
|
211
|
-
}> = ({ Icon, control, children }) => {
|
|
212
|
-
return (
|
|
213
|
-
<div className="flex items-center justify-between gap-2">
|
|
214
|
-
<h2 className="flex items-center gap-2 text-xl font-semibold text-muted-foreground select-none">
|
|
215
|
-
<Icon className="h-5 w-5" />
|
|
216
|
-
{children}
|
|
217
|
-
</h2>
|
|
218
|
-
{control}
|
|
219
|
-
</div>
|
|
220
|
-
);
|
|
221
|
-
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { act, render, screen } from "@testing-library/react";
|
|
4
|
+
import { Profiler } from "react";
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
6
|
+
import { LargeSpinner } from "../large-spinner";
|
|
7
|
+
|
|
8
|
+
describe("LargeSpinner", () => {
|
|
9
|
+
beforeEach(() => vi.useFakeTimers());
|
|
10
|
+
afterEach(() => vi.useRealTimers());
|
|
11
|
+
|
|
12
|
+
it("fades the old title without a second commit before the timer fires", () => {
|
|
13
|
+
const onRender = vi.fn();
|
|
14
|
+
const spinner = (title: string) => (
|
|
15
|
+
<Profiler id="spinner" onRender={onRender}>
|
|
16
|
+
<LargeSpinner title={title} />
|
|
17
|
+
</Profiler>
|
|
18
|
+
);
|
|
19
|
+
const { rerender } = render(spinner("Starting"));
|
|
20
|
+
onRender.mockClear();
|
|
21
|
+
|
|
22
|
+
rerender(spinner("Loading"));
|
|
23
|
+
expect(onRender).toHaveBeenCalledOnce();
|
|
24
|
+
expect(screen.getByText("Starting")).toHaveClass("opacity-0");
|
|
25
|
+
|
|
26
|
+
act(() => vi.advanceTimersByTime(300));
|
|
27
|
+
expect(screen.getByText("Loading")).toHaveClass("opacity-100");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("restores visibility if the title changes back during the fade", () => {
|
|
31
|
+
const { rerender } = render(<LargeSpinner title="Starting" />);
|
|
32
|
+
rerender(<LargeSpinner title="Loading" />);
|
|
33
|
+
rerender(<LargeSpinner title="Starting" />);
|
|
34
|
+
|
|
35
|
+
expect(screen.getByText("Starting")).toHaveClass("opacity-100");
|
|
36
|
+
act(() => vi.advanceTimersByTime(300));
|
|
37
|
+
expect(screen.queryByText("Loading")).not.toBeInTheDocument();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -1,23 +1,12 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
3
|
import { Loader2Icon } from "lucide-react";
|
|
4
|
-
import {
|
|
4
|
+
import { useDebounce } from "@/hooks/useDebounce";
|
|
5
5
|
import { cn } from "@/utils/cn";
|
|
6
6
|
|
|
7
7
|
export const LargeSpinner = ({ title }: { title?: string }) => {
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
useEffect(() => {
|
|
12
|
-
if (title !== currentTitle) {
|
|
13
|
-
setIsVisible(false);
|
|
14
|
-
const timer = setTimeout(() => {
|
|
15
|
-
setCurrentTitle(title);
|
|
16
|
-
setIsVisible(true);
|
|
17
|
-
}, 300); // Wait for fade out animation to complete
|
|
18
|
-
return () => clearTimeout(timer);
|
|
19
|
-
}
|
|
20
|
-
}, [title, currentTitle]);
|
|
8
|
+
const currentTitle = useDebounce(title, 300);
|
|
9
|
+
const isVisible = title === currentTitle;
|
|
21
10
|
|
|
22
11
|
return (
|
|
23
12
|
<div className="flex flex-col h-full flex-1 items-center justify-center p-4">
|
|
@@ -25,7 +25,7 @@ const spinnerVariants = cva("animate-spin", {
|
|
|
25
25
|
const Spinner = React.forwardRef<
|
|
26
26
|
SVGSVGElement,
|
|
27
27
|
React.SVGProps<SVGSVGElement> & VariantProps<typeof spinnerVariants>
|
|
28
|
-
>(({ className, children, centered, size, ...props }, ref) => (
|
|
28
|
+
>(({ className, children: _children, centered, size, ...props }, ref) => (
|
|
29
29
|
<Loader2Icon
|
|
30
30
|
ref={ref}
|
|
31
31
|
className={cn(spinnerVariants({ centered, size }), className)}
|
|
@@ -41,7 +41,7 @@ export const MCPStatusIndicator: React.FC = () => {
|
|
|
41
41
|
<Popover>
|
|
42
42
|
<Tooltip content="MCP Status">
|
|
43
43
|
<PopoverTrigger asChild={true}>
|
|
44
|
-
<Button variant="text" size="icon">
|
|
44
|
+
<Button aria-label="MCP status" variant="text" size="icon">
|
|
45
45
|
<PlugIcon
|
|
46
46
|
className={cn(
|
|
47
47
|
"h-4 w-4",
|