@marimo-team/islands 0.25.3-dev141 → 0.25.3-dev143
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-CNSxdKyJ.js → ConnectedDataExplorerComponent-BAiSVaHj.js} +17 -15
- package/dist/{ErrorBoundary-Cg59O3xL.js → ErrorBoundary-BRBKqg2U.js} +16 -16
- package/dist/{abnfDiagram-VCTEODGH-DQDjNXt3.js → abnfDiagram-VCTEODGH-BBHN92-F.js} +2 -2
- package/dist/any-language-editor-3E24SnCV.js +75 -0
- package/dist/{architectureDiagram-5GKGNRK7-Nmls7Wxn.js → architectureDiagram-5GKGNRK7-C0Rd64qh.js} +1 -1
- package/dist/{arrays-CN1djC4k.js → arrays-R6JsImiT.js} +8 -0
- package/dist/assets/__vite-browser-external-BgQNn4dS.js +1 -0
- package/dist/assets/worker-FKe3RHT4.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-BDpymeoe.js → chat-ui-CvB8Map3.js} +1195 -1195
- package/dist/{check-EDwSwP89.js → check-SpOMoCLP.js} +1 -1
- package/dist/{chunk-IMKFNOWR-CoIFEo-1.js → chunk-IMKFNOWR-hJXey5p2.js} +1 -1
- package/dist/{chunk-SHT3W25Y-lHiGx3ZC.js → chunk-SHT3W25Y-JMzTmmVW.js} +1 -1
- package/dist/{chunk-SVP7TREG-BvsHIrY_.js → chunk-SVP7TREG-BIyoHTXi.js} +1 -1
- package/dist/{chunk-TICWLB2K-BC8YIm_n.js → chunk-TICWLB2K-CCzH2Uwa.js} +1 -1
- package/dist/{chunk-YOKDWASO-DPZk8vhS.js → chunk-YOKDWASO-DKplTrBY.js} +20 -20
- package/dist/{classDiagram-ZZMXUADV-Bt98lkkv.js → classDiagram-ZZMXUADV-DB1kOPS6.js} +2 -2
- package/dist/{classDiagram-v2-VYDZK3BY-D9bfbcC3.js → classDiagram-v2-VYDZK3BY-CPaFL0OB.js} +2 -2
- package/dist/{code-visibility-Da3iitn_.js → code-visibility-CAgcNzoX.js} +17 -17
- package/dist/{common-C6FHcu5p.js → common-BovIV1xq.js} +6341 -5870
- package/dist/{copy-icon-Ft7t9bqz.js → copy-icon-C1trdvVt.js} +3 -3
- package/dist/{cynefinDiagram-5FMLGOSQ-CgWra7wt.js → cynefinDiagram-5FMLGOSQ-CF93uliH.js} +1 -1
- package/dist/{dagre-GXQ25YYZ-CFZ8-35c.js → dagre-GXQ25YYZ-BBB-_p9D.js} +1 -1
- package/dist/{data-grid-overlay-editor-mJt3Pg4S.js → data-grid-overlay-editor-CBsr8Yo0.js} +5 -5
- package/dist/{data-grid-types-BH_r7g7l.js → data-grid-types-0PJ-9N5n.js} +1 -1
- package/dist/{diagram-S7CK7UJ4-lCNQrW7d.js → diagram-S7CK7UJ4-BynCnbyt.js} +1 -1
- package/dist/{diagram-UQ7AKVKN-CQPQ6pP_.js → diagram-UQ7AKVKN-svOxikMa.js} +1 -1
- package/dist/{diagram-VX7I27RA-Cf3b0llz.js → diagram-VX7I27RA-BVQSnPx0.js} +1 -1
- package/dist/{diagram-Z3DM3KII-Bt4QLrpn.js → diagram-Z3DM3KII-nR1J0BH5.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-GWcGCcxE.js} +1277 -1229
- package/dist/{ebnfDiagram-PWID7BFC-D3NAyPFY.js → ebnfDiagram-PWID7BFC-C9tq9-Qo.js} +2 -2
- package/dist/{erDiagram-RLTQ6QDP-Tlu09_Nm.js → erDiagram-RLTQ6QDP-BiaeB7Fi.js} +1 -1
- package/dist/{error-banner-Da600cwz.js → error-banner-D40pmfQQ.js} +86 -81
- package/dist/{cells-C8iCYvLU.js → error-entries-CmFDQ9CA.js} +1718 -1621
- package/dist/{feedback-button-DaPwHIdM.js → feedback-button-B_9o6DdV.js} +122 -123
- package/dist/{flowDiagram-HODETNUW-CAYbpJmV.js → flowDiagram-HODETNUW-f-sLm87k.js} +2 -2
- package/dist/{formats-BGh2thRc.js → formats-CCxaLPNs.js} +3 -3
- package/dist/{ganttDiagram-EL5Y4UJY-BQT16JSc.js → ganttDiagram-EL5Y4UJY-Dh_4cBJZ.js} +2 -2
- package/dist/{glide-data-editor-Ctz2mH6k.js → glide-data-editor-i7BEAfhs.js} +370 -368
- package/dist/{glide-utils-DJyqh0EM.js → glide-utils-Dz_F4pAY.js} +16 -16
- package/dist/{globals-EpFoRj_E.js → globals-BDzA_Re9.js} +3 -3
- package/dist/{highlighted-body-KPVGNVTW-zwjq21tf.js → highlighted-body-KPVGNVTW-3Ziwfz-V.js} +2 -2
- package/dist/{html-to-image-CZY1pIZH.js → html-to-image-BrC8OJcj.js} +634 -597
- package/dist/{infoDiagram-27XIBGKW-XrDxhr0x.js → infoDiagram-27XIBGKW-BHrWywBe.js} +1 -1
- package/dist/{ishikawaDiagram-5VMMS53U-CD1muzov.js → ishikawaDiagram-5VMMS53U-Da4s0Reg.js} +1 -1
- package/dist/{kanban-definition-UXKFOSKX-Dg9W142_.js → kanban-definition-UXKFOSKX-DDf1GVLj.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 +7548 -7226
- package/dist/{mermaid-CiAXjLpA.js → mermaid-ClwTt7OD.js} +38 -38
- package/dist/mermaid-HWGCJPDP-Du3-HPQA.js +2 -0
- package/dist/{mindmap-definition-YA3MSWOX-DgCidgYJ.js → mindmap-definition-YA3MSWOX-D60oMZtT.js} +1 -1
- package/dist/{number-overlay-editor-CtxrummL.js → number-overlay-editor-D9WjQlOL.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-coOYYKB6.js → pegDiagram-XKGWAZYB-B9wFpMga.js} +2 -2
- package/dist/{pieDiagram-E7YTZNPT-BnXTc3bj.js → pieDiagram-E7YTZNPT-BZwvMuBT.js} +1 -1
- package/dist/precisionRound-DhAzeRcm.js +49 -0
- package/dist/{process-output-e4jj9Ijt.js → process-output-Bw-vzyoy.js} +4 -4
- package/dist/{quadrantDiagram-AXDQQJYC-Ccw0xMjN.js → quadrantDiagram-AXDQQJYC-Blrm7V7_.js} +1 -1
- package/dist/{railroadDiagram-O6MQD6OU-B28-u83n.js → railroadDiagram-O6MQD6OU-DqhZGsN2.js} +2 -2
- package/dist/{react-vega-BED0DjiB.js → react-vega-C4T9Rb_w.js} +12284 -12270
- package/dist/{requirementDiagram-BXWQKSXE-CdYCTMu0.js → requirementDiagram-BXWQKSXE-CL5dYARV.js} +1 -1
- package/dist/{reveal-component-DrIXvR_7.js → reveal-component-BxP2jlPx.js} +14 -14
- package/dist/{select-BButFi-d.js → select-CkF_GBxO.js} +537 -458
- package/dist/{sequenceDiagram-WJ2MYXX4-CM3aRAe_.js → sequenceDiagram-WJ2MYXX4-BSUCRd2x.js} +1 -1
- package/dist/{spec-BwarBpUJ.js → spec-DiSh_qJC.js} +41 -11
- package/dist/{stateDiagram-D77RDMKH-DOZUMVj8.js → stateDiagram-D77RDMKH-B-1Hvyb0.js} +2 -2
- package/dist/{stateDiagram-v2-MP3YSRHH-CISYxma6.js → stateDiagram-v2-MP3YSRHH--HtiR4yB.js} +2 -2
- package/dist/style.css +1 -1
- package/dist/{swimlanes-42K2YHIH-BkSppxp8.js → swimlanes-42K2YHIH-Bdfhrd-2.js} +1 -1
- package/dist/{swimlanesDiagram-VR7AAH4N-c8G5pGxC.js → swimlanesDiagram-VR7AAH4N-BJIfxSz0.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-CaMQayqK.js → timeline-definition-24CTP7MA-Cs4EfFD3.js} +1 -1
- package/dist/{toDate-BNJf01u1.js → toDate-DGvRHwTk.js} +57 -54
- 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-BmVgnMP5.js} +15 -14
- package/dist/{useDateFormatter-D8XruNGG.js → useDateFormatter-eCL_SdeG.js} +2 -2
- package/dist/{useDeepCompareMemoize-DXwzRINI.js → useDeepCompareMemoize-Ch_AeGu6.js} +1 -1
- package/dist/{useIframeCapabilities-DBETvvPl.js → useIframeCapabilities-CSdWn6NP.js} +1 -1
- package/dist/{useLifecycle-j7D9uD1o.js → useLifecycle-B5BX921H.js} +3 -3
- package/dist/{useTheme-CRnjkku0.js → useTheme-Bq9pi_vz.js} +6 -6
- package/dist/{vega-component-DG29TAB7.js → vega-component-BgyZ-COt.js} +147 -147
- 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-CF8pfaK3.js → vennDiagram-4TSXK5OY-DRu0vRjO.js} +1 -1
- package/dist/{wardleyDiagram-VM6X3IG4-dGPu39d-.js → wardleyDiagram-VM6X3IG4-DzbDxwDY.js} +1 -1
- package/dist/{xychartDiagram-S5SC5T6Z-CP6-9q56.js → xychartDiagram-S5SC5T6Z-CLWj6ZFQ.js} +2 -2
- package/package.json +15 -12
- package/src/__tests__/fixtures/{pair-preview.ts → pair-config.ts} +3 -2
- package/src/__tests__/host-imports.test.ts +101 -0
- package/src/__tests__/module-entry.test.ts +32 -0
- package/src/__tests__/mount.test.ts +8 -8
- 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/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__/context-menu.test.ts +176 -0
- package/src/components/data-table/__tests__/data-table.test.tsx +1 -0
- package/src/components/data-table/__tests__/date-filter-inputs.test.tsx +24 -1
- package/src/components/data-table/__tests__/date-popover.test.tsx +72 -0
- package/src/components/data-table/__tests__/export-actions.test.tsx +434 -6
- 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 +161 -46
- package/src/components/data-table/data-table.tsx +13 -1
- package/src/components/data-table/date-filter-inputs.tsx +15 -42
- package/src/components/data-table/date-popover.tsx +6 -4
- package/src/components/data-table/export-actions.tsx +267 -163
- 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/schemas.ts +14 -36
- 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/data-table/utils.ts +18 -0
- 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/Output.tsx +9 -2
- package/src/components/editor/SortableCell.tsx +1 -3
- 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-commands.test.ts +80 -252
- package/src/components/editor/actions/__tests__/pair-with-agent-modal.test.tsx +210 -34
- package/src/components/editor/actions/pair-with-agent-commands.ts +42 -51
- package/src/components/editor/actions/pair-with-agent-modal.tsx +100 -37
- 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/startup-logs-alert.tsx +1 -0
- package/src/components/editor/cell/CreateCellButton.tsx +8 -10
- package/src/components/editor/cell/DeleteButton.tsx +1 -0
- 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 +1 -1
- 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/panels/__tests__/packages-panel.test.tsx +30 -1
- package/src/components/editor/chrome/panels/cache-panel.tsx +1 -0
- package/src/components/editor/chrome/panels/error-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 +366 -0
- package/src/components/editor/chrome/wrapper/__tests__/pending-ai-cells.test.tsx +58 -1
- package/src/components/editor/chrome/wrapper/footer-item.tsx +32 -24
- package/src/components/editor/chrome/wrapper/footer-items/attachment-status.tsx +237 -0
- package/src/components/editor/chrome/wrapper/footer-items/runtime-settings.tsx +1 -7
- package/src/components/editor/chrome/wrapper/footer.tsx +2 -0
- 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/__tests__/command-palette.test.tsx +53 -0
- package/src/components/editor/controls/__tests__/keyboard-shortcuts.test.tsx +61 -0
- 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 +537 -0
- package/src/components/editor/errors/send-error-report-button.tsx +69 -0
- 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/status.tsx +28 -5
- 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 +11 -2
- package/src/components/editor/output/MarimoErrorOutput.tsx +21 -5
- package/src/components/editor/output/MarimoTracebackOutput.tsx +54 -37
- package/src/components/editor/output/__tests__/ansi-reduce.test.ts +18 -0
- package/src/components/editor/output/__tests__/traceback.test.tsx +27 -1
- package/src/components/editor/output/ansi-reduce.ts +36 -17
- 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/attachments/__tests__/toast.test.tsx +58 -0
- package/src/core/attachments/state.ts +18 -0
- package/src/core/attachments/toast.ts +15 -0
- 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 +55 -1
- package/src/core/cells/__tests__/collapseConsoleOutputs.test.ts +54 -0
- package/src/core/cells/__tests__/error-report.test.ts +139 -0
- package/src/core/cells/__tests__/notebook-outline.test.ts +113 -0
- package/src/core/cells/__tests__/session.test.ts +167 -37
- package/src/core/cells/cell.ts +14 -3
- package/src/core/cells/cells.ts +3 -1
- package/src/core/cells/error-report.ts +63 -0
- package/src/core/cells/pending-delete-service.ts +2 -6
- package/src/core/cells/session.ts +29 -2
- package/src/core/cells/types.ts +10 -1
- package/src/core/codemirror/__tests__/setup.test.ts +29 -29
- 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/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/pair.ts +5 -3
- package/src/core/datasets/__tests__/data-source-discovery.test.ts +4 -4
- package/src/core/datasets/data-source-discovery.ts +4 -6
- package/src/core/document/__tests__/codemirror.test.ts +485 -0
- package/src/core/document/__tests__/draft.test.ts +322 -0
- package/src/core/document/__tests__/fixtures.ts +92 -0
- package/src/core/document/__tests__/hooks.test.tsx +386 -0
- package/src/core/document/__tests__/lifecycle-scenarios.test.ts +61 -0
- package/src/core/document/__tests__/model.test.ts +191 -0
- package/src/core/document/__tests__/protocol-fixtures.ts +38 -0
- package/src/core/document/__tests__/recovery-scenarios.test.ts +230 -0
- package/src/core/document/__tests__/scenario-fixture.ts +43 -0
- package/src/core/document/__tests__/scenarios.test.ts +205 -0
- package/src/core/document/__tests__/state.test.ts +438 -0
- package/src/core/document/__tests__/submission.test.ts +203 -0
- package/src/core/document/__tests__/test-host.test.ts +92 -0
- package/src/core/document/__tests__/test-host.ts +247 -0
- package/src/core/document/__tests__/test-notebook.ts +149 -0
- package/src/core/document/__tests__/user.ts +61 -0
- package/src/core/document/codemirror.ts +311 -0
- package/src/core/document/draft.ts +472 -0
- package/src/core/document/hooks.tsx +118 -0
- package/src/core/document/index.ts +15 -0
- package/src/core/document/model.ts +55 -0
- package/src/core/document/select.ts +41 -0
- package/src/core/document/state.ts +374 -0
- package/src/core/document/sync.ts +369 -0
- package/src/core/edit-app.tsx +2 -2
- package/src/core/host/AGENTS.md +12 -0
- package/src/core/host/__tests__/attachments.test.ts +56 -0
- package/src/core/host/__tests__/document.test.ts +126 -0
- package/src/core/host/__tests__/fixtures.ts +79 -0
- package/src/core/host/__tests__/replica.test.ts +550 -0
- package/src/core/host/__tests__/static.test.ts +175 -0
- package/src/core/host/__tests__/wasm.test.ts +166 -0
- package/src/core/host/backend.ts +19 -0
- package/src/core/host/connection.ts +42 -0
- package/src/core/host/index.ts +14 -0
- package/src/core/host/replica.ts +286 -0
- package/src/core/host/resources/attachments.ts +22 -0
- package/src/core/host/resources/document.ts +101 -0
- package/src/core/host/static.ts +77 -0
- package/src/core/host/wasm.ts +97 -0
- package/src/core/hotkeys/actions.ts +2 -4
- package/src/core/islands/__tests__/bootstrap.test.ts +17 -17
- package/src/core/islands/__tests__/bridge.test.ts +31 -26
- package/src/core/islands/bootstrap.ts +22 -51
- 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/connection.ts +4 -2
- package/src/core/network/useConnectionNotice.ts +8 -2
- package/src/core/run-app.tsx +2 -2
- package/src/core/runtime/__tests__/createWsUrl.test.ts +77 -7
- package/src/core/runtime/__tests__/runtime.test.ts +33 -15
- package/src/core/runtime/runtime.ts +39 -30
- package/src/core/saving/save-component.tsx +12 -3
- 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/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/core/websocket/__tests__/backend.test.ts +235 -0
- package/src/core/websocket/__tests__/{useMarimoKernelConnection.test.ts → connection-state.test.ts} +15 -29
- package/src/core/websocket/__tests__/useNotebookReplica.hook.test.tsx +141 -0
- package/src/core/websocket/__tests__/{useMarimoKernelConnection.hook.test.tsx → useNotebookSession.hook.test.tsx} +197 -184
- package/src/core/websocket/backend.ts +129 -0
- package/src/core/websocket/connection-state.ts +60 -0
- package/src/core/websocket/state.ts +7 -0
- package/src/core/websocket/transports/__tests__/notebook.test.ts +405 -0
- package/src/core/websocket/transports/notebook.ts +159 -0
- package/src/core/websocket/types.ts +9 -39
- package/src/core/websocket/useNotebookReplica.ts +69 -0
- package/src/core/websocket/{useMarimoKernelConnection.tsx → useNotebookSession.tsx} +63 -228
- package/src/css/globals.css +5 -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 +3 -3
- 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 +201 -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 +2 -0
- package/src/plugins/impl/anywidget/__tests__/widget-binding.test.ts +241 -2
- 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/editor.stories.tsx +24 -17
- package/src/stories/form-wrapper.stories.tsx +2 -2
- 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__/dates.test.ts +116 -0
- package/src/utils/__tests__/numbers.test.ts +105 -1
- package/src/utils/__tests__/objects.test.ts +21 -0
- package/src/utils/arrays.ts +10 -0
- package/src/utils/blob.ts +1 -1
- package/src/utils/dates.ts +94 -0
- package/src/utils/numbers.ts +79 -18
- package/src/utils/objects.ts +3 -7
- 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-B9REGlD9.js +0 -76
- package/dist/assets/__vite-browser-external-BXYkiFsk.js +0 -1
- package/dist/assets/worker-HPY9fbhz.js +0 -114
- package/dist/error-entries-CzoYkIQZ.js +0 -56
- package/dist/mermaid-HWGCJPDP-ByCsZnYF.js +0 -2
- package/dist/precisionRound-DMIVQrt2.js +0 -97
- 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__/useWebSocket.test.ts +0 -49
- package/src/core/websocket/transports/__tests__/basic.test.ts +0 -275
- package/src/core/websocket/transports/__tests__/sse.test.ts +0 -338
- 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/sse.ts +0 -308
- package/src/core/websocket/transports/transport.ts +0 -61
- package/src/core/websocket/transports/ws.ts +0 -98
- package/src/core/websocket/useWebSocket.tsx +0 -88
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
type NotebookTransport,
|
|
5
|
+
sse,
|
|
6
|
+
StreamStopped,
|
|
7
|
+
type StreamUrl,
|
|
8
|
+
} from "@marimo-team/client";
|
|
9
|
+
import { jsonParseWithSpecialChar } from "@/utils/json/json-parser";
|
|
10
|
+
import { classifyCloseEvent } from "../connection-state";
|
|
11
|
+
|
|
12
|
+
/** The server can be slow to accept when many notebooks are open. */
|
|
13
|
+
const CONNECT_MS = 10_000;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The error that ends a stream on this close, or none to retry.
|
|
17
|
+
*
|
|
18
|
+
* `cause` is the connection status the editor shows.
|
|
19
|
+
*/
|
|
20
|
+
function stopOn(close: { code?: number; reason?: string }) {
|
|
21
|
+
const decision = classifyCloseEvent(close);
|
|
22
|
+
if (decision.kind === "retry") {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
const reason = "reason" in decision.status ? decision.status.reason : "";
|
|
26
|
+
return new StreamStopped(reason, { cause: decision.status });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Read a URL provider, stopping the stream when it gives up. */
|
|
30
|
+
async function resolve(url: StreamUrl): Promise<URL | undefined> {
|
|
31
|
+
try {
|
|
32
|
+
return new URL(typeof url === "function" ? await url() : url);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
if (error instanceof StreamStopped) {
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Send each request with the runtime's headers, read before each request. */
|
|
42
|
+
export function withHeaders(
|
|
43
|
+
headers: () => Record<string, string>,
|
|
44
|
+
): typeof globalThis.fetch {
|
|
45
|
+
return (input, init) => {
|
|
46
|
+
const sent = new Headers(init?.headers);
|
|
47
|
+
for (const [name, value] of Object.entries(headers())) {
|
|
48
|
+
sent.set(name, value);
|
|
49
|
+
}
|
|
50
|
+
return globalThis.fetch(input, { ...init, headers: sent });
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** A resume cursor and replica belong to the session that produced them. */
|
|
55
|
+
function withSessionIdentity(
|
|
56
|
+
url: StreamUrl,
|
|
57
|
+
connect: (target: URL) => NotebookTransport,
|
|
58
|
+
): NotebookTransport {
|
|
59
|
+
let previous: string | undefined;
|
|
60
|
+
return async (attempt, handlers) => {
|
|
61
|
+
const target = await resolve(url);
|
|
62
|
+
if (target === undefined || attempt.signal.aborted) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
target.searchParams.delete("cursor");
|
|
66
|
+
const identity = new URL(target);
|
|
67
|
+
identity.searchParams.delete("access_token");
|
|
68
|
+
identity.searchParams.sort();
|
|
69
|
+
identity.hash = "";
|
|
70
|
+
const key = identity.toString();
|
|
71
|
+
let { cursor } = attempt;
|
|
72
|
+
if (previous !== undefined && previous !== key) {
|
|
73
|
+
// Reset both the stream's cursor and its subscribers' state.
|
|
74
|
+
handlers.message({ event: "reset", data: {} });
|
|
75
|
+
cursor = null;
|
|
76
|
+
}
|
|
77
|
+
previous = key;
|
|
78
|
+
if (!attempt.signal.aborted) {
|
|
79
|
+
return connect(target)({ ...attempt, cursor }, handlers);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Follow a marimo session over its WebSocket route.
|
|
86
|
+
*
|
|
87
|
+
* Each attempt opens one socket with the cursor as a query parameter. The
|
|
88
|
+
* editor's close policy decides which closes end the stream.
|
|
89
|
+
*
|
|
90
|
+
* TODO: Notice a connection that died without closing, such as after a laptop
|
|
91
|
+
* sleeps. `/sse` sends a heartbeat that its silence limit relies on, and
|
|
92
|
+
* `/ws` drops it. Sending it on `/ws` would let this transport close a
|
|
93
|
+
* silent socket.
|
|
94
|
+
*/
|
|
95
|
+
export function websocket(url: StreamUrl): NotebookTransport {
|
|
96
|
+
return withSessionIdentity(
|
|
97
|
+
url,
|
|
98
|
+
(target) =>
|
|
99
|
+
async ({ cursor, signal }, { open, message }) => {
|
|
100
|
+
if (cursor !== null) {
|
|
101
|
+
target.searchParams.set("cursor", cursor);
|
|
102
|
+
}
|
|
103
|
+
await new Promise<void>((settle, reject) => {
|
|
104
|
+
const socket = new WebSocket(target);
|
|
105
|
+
const timeout = setTimeout(() => socket.close(), CONNECT_MS);
|
|
106
|
+
const abort = () => socket.close();
|
|
107
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
108
|
+
socket.addEventListener("open", () => {
|
|
109
|
+
clearTimeout(timeout);
|
|
110
|
+
open();
|
|
111
|
+
});
|
|
112
|
+
socket.addEventListener("message", ({ data }) =>
|
|
113
|
+
// marimo's parser reads `NaN`. A message it cannot read arrives as an
|
|
114
|
+
// empty object, which `NotebookEvents` rejects as not an event.
|
|
115
|
+
message(jsonParseWithSpecialChar(String(data))),
|
|
116
|
+
);
|
|
117
|
+
socket.addEventListener("close", (event) => {
|
|
118
|
+
clearTimeout(timeout);
|
|
119
|
+
signal.removeEventListener("abort", abort);
|
|
120
|
+
const stopped = signal.aborted ? undefined : stopOn(event);
|
|
121
|
+
if (stopped === undefined) {
|
|
122
|
+
settle();
|
|
123
|
+
} else {
|
|
124
|
+
reject(stopped);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
},
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Follow a marimo session over its server-sent events route.
|
|
134
|
+
*
|
|
135
|
+
* The session's `close` frames carry the same reasons as WebSocket closes.
|
|
136
|
+
* marimo's parser decodes tagged bigints and non-finite numbers in every frame.
|
|
137
|
+
*/
|
|
138
|
+
export function sessionSse(
|
|
139
|
+
url: StreamUrl,
|
|
140
|
+
headers: () => Record<string, string>,
|
|
141
|
+
): NotebookTransport {
|
|
142
|
+
return withSessionIdentity(url, (target) =>
|
|
143
|
+
sse(target, {
|
|
144
|
+
parseData: jsonParseWithSpecialChar,
|
|
145
|
+
fetch: withHeaders(headers),
|
|
146
|
+
stop: (frame) =>
|
|
147
|
+
frame.event === "close"
|
|
148
|
+
? stopOn(frame.data as { code?: number; reason?: string })
|
|
149
|
+
: undefined,
|
|
150
|
+
}),
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/** A connection that opens and delivers nothing, for static notebooks. */
|
|
155
|
+
export const idle: NotebookTransport = ({ signal }, { open }) =>
|
|
156
|
+
new Promise((settle) => {
|
|
157
|
+
open();
|
|
158
|
+
signal.addEventListener("abort", () => settle(), { once: true });
|
|
159
|
+
});
|
|
@@ -1,47 +1,17 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
|
+
import type { ConnectionStatus as HostConnectionStatus } from "../host";
|
|
3
4
|
import type { NotificationMessageData } from "../kernel/messages";
|
|
4
5
|
|
|
6
|
+
export {
|
|
7
|
+
ConnectionState,
|
|
8
|
+
ConnectionClosedReason as WebSocketClosedReason,
|
|
9
|
+
} from "../host";
|
|
10
|
+
|
|
5
11
|
export type ConnectionPhase =
|
|
6
12
|
| NotificationMessageData<"startup-progress">["phase"]
|
|
7
13
|
| "reconnecting";
|
|
8
14
|
|
|
9
|
-
export
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
OPEN: "OPEN",
|
|
13
|
-
CLOSING: "CLOSING",
|
|
14
|
-
CLOSED: "CLOSED",
|
|
15
|
-
} as const;
|
|
16
|
-
|
|
17
|
-
export type ConnectionState =
|
|
18
|
-
(typeof ConnectionState)[keyof typeof ConnectionState];
|
|
19
|
-
|
|
20
|
-
export const WebSocketClosedReason = {
|
|
21
|
-
KERNEL_DISCONNECTED: "KERNEL_DISCONNECTED",
|
|
22
|
-
KERNEL_STARTUP_ERROR: "KERNEL_STARTUP_ERROR",
|
|
23
|
-
} as const;
|
|
24
|
-
|
|
25
|
-
export type WebSocketClosedReason =
|
|
26
|
-
(typeof WebSocketClosedReason)[keyof typeof WebSocketClosedReason];
|
|
27
|
-
|
|
28
|
-
export type ConnectionStatus =
|
|
29
|
-
| {
|
|
30
|
-
state: typeof ConnectionState.CLOSED;
|
|
31
|
-
code: WebSocketClosedReason;
|
|
32
|
-
/**
|
|
33
|
-
* Human-readable reason for closing the connection.
|
|
34
|
-
*/
|
|
35
|
-
reason: string;
|
|
36
|
-
phase?: ConnectionPhase;
|
|
37
|
-
}
|
|
38
|
-
| {
|
|
39
|
-
state: typeof ConnectionState.CONNECTING;
|
|
40
|
-
phase?: ConnectionPhase;
|
|
41
|
-
}
|
|
42
|
-
| {
|
|
43
|
-
state:
|
|
44
|
-
| typeof ConnectionState.OPEN
|
|
45
|
-
| typeof ConnectionState.CLOSING
|
|
46
|
-
| typeof ConnectionState.NOT_STARTED;
|
|
47
|
-
};
|
|
15
|
+
export type ConnectionStatus = HostConnectionStatus & {
|
|
16
|
+
phase?: ConnectionPhase;
|
|
17
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
/** The editor session's replica, following its backend while mounted. */
|
|
4
|
+
|
|
5
|
+
import { useStore } from "jotai";
|
|
6
|
+
import { useEffect, useMemo } from "react";
|
|
7
|
+
import useEvent from "react-use-event-hook";
|
|
8
|
+
import type {
|
|
9
|
+
NotificationMessage,
|
|
10
|
+
NotificationPayload,
|
|
11
|
+
} from "../kernel/messages";
|
|
12
|
+
import { createNotebookReplica, type NotebookReplica } from "../host";
|
|
13
|
+
import { notebookReplicaAtom } from "./state";
|
|
14
|
+
import { createEditorBackend, type EditorBackendOptions } from "./backend";
|
|
15
|
+
|
|
16
|
+
type Options = EditorBackendOptions & {
|
|
17
|
+
onNotification: (notification: NotificationPayload) => void;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export function useNotebookReplica(options: Options): NotebookReplica {
|
|
21
|
+
const store = useStore();
|
|
22
|
+
const { static: isStatic, transportType } = options;
|
|
23
|
+
const replica = useMemo(() => createNotebookReplica(store), [store]);
|
|
24
|
+
const url = useEvent(options.url);
|
|
25
|
+
const headers = useEvent(options.headers);
|
|
26
|
+
const notebookUrl = useEvent(options.notebookUrl);
|
|
27
|
+
const waitUntilReady = useEvent(options.waitUntilReady);
|
|
28
|
+
const checkHealth = useEvent(options.checkHealth);
|
|
29
|
+
const onNotification = useEvent(options.onNotification);
|
|
30
|
+
// Opens nothing until the replica follows it.
|
|
31
|
+
const backend = useMemo(
|
|
32
|
+
() =>
|
|
33
|
+
createEditorBackend({
|
|
34
|
+
static: isStatic,
|
|
35
|
+
transportType,
|
|
36
|
+
url,
|
|
37
|
+
headers,
|
|
38
|
+
notebookUrl,
|
|
39
|
+
waitUntilReady,
|
|
40
|
+
checkHealth,
|
|
41
|
+
}),
|
|
42
|
+
[
|
|
43
|
+
isStatic,
|
|
44
|
+
transportType,
|
|
45
|
+
url,
|
|
46
|
+
headers,
|
|
47
|
+
notebookUrl,
|
|
48
|
+
waitUntilReady,
|
|
49
|
+
checkHealth,
|
|
50
|
+
],
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
store.set(notebookReplicaAtom, replica);
|
|
55
|
+
const disconnect = replica.connect(backend, {
|
|
56
|
+
// The host validates the envelope, not the native notification contents.
|
|
57
|
+
onNotification: (notification) =>
|
|
58
|
+
onNotification({ data: notification as NotificationMessage }),
|
|
59
|
+
});
|
|
60
|
+
return () => {
|
|
61
|
+
disconnect();
|
|
62
|
+
if (store.get(notebookReplicaAtom) === replica) {
|
|
63
|
+
store.set(notebookReplicaAtom, null);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}, [replica, backend, store, onNotification]);
|
|
67
|
+
|
|
68
|
+
return replica;
|
|
69
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
|
|
3
3
|
import { invalidatePackageData } from "@/core/packages/package-data";
|
|
4
|
-
import { useAtom, useAtomValue, useSetAtom } from "jotai";
|
|
5
|
-
import {
|
|
4
|
+
import { useAtom, useAtomValue, useSetAtom, useStore } from "jotai";
|
|
5
|
+
import { useLayoutEffect } from "react";
|
|
6
6
|
import { useErrorBoundary } from "react-error-boundary";
|
|
7
7
|
import { toast } from "@/components/ui/use-toast";
|
|
8
8
|
import { getNotebook, useCellActions } from "@/core/cells/cells";
|
|
@@ -12,8 +12,7 @@ import type {
|
|
|
12
12
|
NotificationMessageData,
|
|
13
13
|
NotificationPayload,
|
|
14
14
|
} from "@/core/kernel/messages";
|
|
15
|
-
import {
|
|
16
|
-
import { useConnectionTransport } from "@/core/websocket/useWebSocket";
|
|
15
|
+
import { useNotebookReplica } from "@/core/websocket/useNotebookReplica";
|
|
17
16
|
import { renderHTML } from "@/plugins/core/RenderHTML";
|
|
18
17
|
import {
|
|
19
18
|
handleWidgetMessage,
|
|
@@ -21,11 +20,7 @@ import {
|
|
|
21
20
|
} from "@/plugins/impl/anywidget/registry";
|
|
22
21
|
import { logNever } from "@/utils/assertNever";
|
|
23
22
|
import { prettyError } from "@/utils/errors";
|
|
24
|
-
import {
|
|
25
|
-
type JsonString,
|
|
26
|
-
safeExtractSetUIElementMessageBuffers,
|
|
27
|
-
} from "@/utils/json/base64";
|
|
28
|
-
import { jsonParseWithSpecialChar } from "@/utils/json/json-parser";
|
|
23
|
+
import { safeExtractSetUIElementMessageBuffers } from "@/utils/json/base64";
|
|
29
24
|
import { Logger } from "@/utils/Logger";
|
|
30
25
|
import { reloadSafe } from "@/utils/reload-safe";
|
|
31
26
|
import { useAlertActions } from "../alerts/state";
|
|
@@ -80,105 +75,10 @@ import {
|
|
|
80
75
|
import { useStorageActions } from "../storage/state";
|
|
81
76
|
import { useVariablesActions } from "../variables/state";
|
|
82
77
|
import type { VariableName } from "../variables/types";
|
|
83
|
-
import {
|
|
84
|
-
import {
|
|
85
|
-
type ConnectionStatus,
|
|
86
|
-
WebSocketClosedReason,
|
|
87
|
-
ConnectionState,
|
|
88
|
-
} from "./types";
|
|
78
|
+
import { WebSocketClosedReason, ConnectionState } from "./types";
|
|
89
79
|
|
|
90
80
|
const SUPPORTS_LAZY_KERNELS = true;
|
|
91
81
|
|
|
92
|
-
// All MARIMO_* reasons except TRANSPORT_EXHAUSTED are emitted by the backend
|
|
93
|
-
// (marimo/_server/api/endpoints/ws_endpoint.py and ws/*.py). Keep in sync with
|
|
94
|
-
// the backend literals. Over the SSE transport these arrive as in-band
|
|
95
|
-
// `close` events rather than WebSocket close frames, so every terminal
|
|
96
|
-
// reason must be classified here — an unclassified reason falls into the
|
|
97
|
-
// retry path.
|
|
98
|
-
export type CloseReason =
|
|
99
|
-
| "MARIMO_NO_FILE_KEY"
|
|
100
|
-
| "MARIMO_NO_SESSION_ID"
|
|
101
|
-
| "MARIMO_NO_SESSION"
|
|
102
|
-
| "MARIMO_SHUTDOWN"
|
|
103
|
-
| "MARIMO_KERNEL_STARTUP_ERROR"
|
|
104
|
-
| "MARIMO_UNAUTHORIZED"
|
|
105
|
-
| "MARIMO_KIOSK_NOT_ALLOWED"
|
|
106
|
-
| typeof TRANSPORT_EXHAUSTED_REASON;
|
|
107
|
-
|
|
108
|
-
export type CloseDecision =
|
|
109
|
-
| { kind: "terminal"; status: ConnectionStatus; closeTransport: boolean }
|
|
110
|
-
| { kind: "gave-up"; status: ConnectionStatus }
|
|
111
|
-
| { kind: "retry"; status: ConnectionStatus };
|
|
112
|
-
|
|
113
|
-
export function classifyCloseEvent(event: { reason?: string }): CloseDecision {
|
|
114
|
-
switch (event.reason as CloseReason | undefined) {
|
|
115
|
-
case TRANSPORT_EXHAUSTED_REASON:
|
|
116
|
-
return {
|
|
117
|
-
kind: "gave-up",
|
|
118
|
-
status: {
|
|
119
|
-
state: ConnectionState.CLOSED,
|
|
120
|
-
code: WebSocketClosedReason.KERNEL_DISCONNECTED,
|
|
121
|
-
reason: "kernel not found",
|
|
122
|
-
},
|
|
123
|
-
};
|
|
124
|
-
case "MARIMO_NO_FILE_KEY":
|
|
125
|
-
case "MARIMO_NO_SESSION_ID":
|
|
126
|
-
case "MARIMO_NO_SESSION":
|
|
127
|
-
case "MARIMO_SHUTDOWN":
|
|
128
|
-
return {
|
|
129
|
-
kind: "terminal",
|
|
130
|
-
status: {
|
|
131
|
-
state: ConnectionState.CLOSED,
|
|
132
|
-
code: WebSocketClosedReason.KERNEL_DISCONNECTED,
|
|
133
|
-
reason: "kernel not found",
|
|
134
|
-
},
|
|
135
|
-
closeTransport: true,
|
|
136
|
-
};
|
|
137
|
-
case "MARIMO_UNAUTHORIZED":
|
|
138
|
-
return {
|
|
139
|
-
kind: "terminal",
|
|
140
|
-
status: {
|
|
141
|
-
state: ConnectionState.CLOSED,
|
|
142
|
-
code: WebSocketClosedReason.KERNEL_DISCONNECTED,
|
|
143
|
-
reason: "not authorized",
|
|
144
|
-
},
|
|
145
|
-
closeTransport: true,
|
|
146
|
-
};
|
|
147
|
-
case "MARIMO_KIOSK_NOT_ALLOWED":
|
|
148
|
-
return {
|
|
149
|
-
kind: "terminal",
|
|
150
|
-
status: {
|
|
151
|
-
state: ConnectionState.CLOSED,
|
|
152
|
-
code: WebSocketClosedReason.KERNEL_DISCONNECTED,
|
|
153
|
-
reason: "kiosk mode is not available for this session",
|
|
154
|
-
},
|
|
155
|
-
closeTransport: true,
|
|
156
|
-
};
|
|
157
|
-
case "MARIMO_KERNEL_STARTUP_ERROR":
|
|
158
|
-
return {
|
|
159
|
-
kind: "terminal",
|
|
160
|
-
status: {
|
|
161
|
-
state: ConnectionState.CLOSED,
|
|
162
|
-
code: WebSocketClosedReason.KERNEL_STARTUP_ERROR,
|
|
163
|
-
reason: "Failed to start kernel sandbox",
|
|
164
|
-
},
|
|
165
|
-
closeTransport: true,
|
|
166
|
-
};
|
|
167
|
-
default:
|
|
168
|
-
// Empty/undefined reasons are normal transient closes. Anything else is
|
|
169
|
-
// an unknown server reason; warn so a new MARIMO_* reason doesn't fall
|
|
170
|
-
// silently into the retry path.
|
|
171
|
-
if (event.reason) {
|
|
172
|
-
logNever(event.reason as never);
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
return {
|
|
177
|
-
kind: "retry",
|
|
178
|
-
status: { state: ConnectionState.CONNECTING },
|
|
179
|
-
};
|
|
180
|
-
}
|
|
181
|
-
|
|
182
82
|
function getExistingCells(): CellData[] | undefined {
|
|
183
83
|
if (!SUPPORTS_LAZY_KERNELS) {
|
|
184
84
|
return undefined;
|
|
@@ -190,16 +90,12 @@ function getExistingCells(): CellData[] | undefined {
|
|
|
190
90
|
);
|
|
191
91
|
}
|
|
192
92
|
|
|
193
|
-
/**
|
|
194
|
-
|
|
195
|
-
*/
|
|
196
|
-
export function useMarimoKernelConnection(opts: {
|
|
93
|
+
/** Coordinate session startup and apply notifications to the editor. */
|
|
94
|
+
export function useNotebookSession(opts: {
|
|
197
95
|
sessionId: SessionId;
|
|
198
96
|
autoInstantiate: boolean;
|
|
199
97
|
setCells: (cells: CellData[], layout: LayoutState) => void;
|
|
200
98
|
}) {
|
|
201
|
-
// Track whether we want to try reconnecting.
|
|
202
|
-
const shouldTryReconnecting = useRef<boolean>(true);
|
|
203
99
|
const { autoInstantiate, sessionId, setCells } = opts;
|
|
204
100
|
const { showBoundary } = useErrorBoundary();
|
|
205
101
|
|
|
@@ -246,8 +142,7 @@ export function useMarimoKernelConnection(opts: {
|
|
|
246
142
|
filterFromVariables: filterStorageFromVariables,
|
|
247
143
|
} = useStorageActions();
|
|
248
144
|
|
|
249
|
-
const
|
|
250
|
-
const msg = jsonParseWithSpecialChar(e.data);
|
|
145
|
+
const handleNotification = (msg: NotificationPayload) => {
|
|
251
146
|
switch (msg.data.op) {
|
|
252
147
|
case "reload":
|
|
253
148
|
reloadSafe();
|
|
@@ -368,13 +263,18 @@ export function useMarimoKernelConnection(opts: {
|
|
|
368
263
|
filterStorageFromVariables(variableNames);
|
|
369
264
|
return;
|
|
370
265
|
case "variable-values":
|
|
371
|
-
setMetadata(
|
|
372
|
-
msg.data.
|
|
266
|
+
setMetadata([
|
|
267
|
+
...(msg.data.removed ?? []).map((v) => ({
|
|
268
|
+
name: v.name as VariableName,
|
|
269
|
+
dataType: undefined,
|
|
270
|
+
value: undefined,
|
|
271
|
+
})),
|
|
272
|
+
...msg.data.variables.map((v) => ({
|
|
373
273
|
name: v.name as VariableName,
|
|
374
274
|
dataType: v.datatype,
|
|
375
275
|
value: v.value,
|
|
376
276
|
})),
|
|
377
|
-
);
|
|
277
|
+
]);
|
|
378
278
|
return;
|
|
379
279
|
case "alert":
|
|
380
280
|
toast({
|
|
@@ -505,107 +405,56 @@ export function useMarimoKernelConnection(opts: {
|
|
|
505
405
|
}
|
|
506
406
|
};
|
|
507
407
|
|
|
508
|
-
const
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
}
|
|
516
|
-
};
|
|
517
|
-
|
|
518
|
-
// Manual reconnect. Probes /health first to fail fast when the runtime
|
|
519
|
-
// is unreachable, instead of waiting on partysocket's retry budget.
|
|
520
|
-
const reconnect = async () => {
|
|
521
|
-
if (
|
|
522
|
-
ws.readyState === WebSocket.OPEN ||
|
|
523
|
-
ws.readyState === WebSocket.CONNECTING
|
|
524
|
-
) {
|
|
525
|
-
return;
|
|
526
|
-
}
|
|
527
|
-
shouldTryReconnecting.current = true;
|
|
528
|
-
setKernelStartupError(null);
|
|
529
|
-
setConnection({ state: ConnectionState.CONNECTING });
|
|
530
|
-
const healthy = await runtimeManager.reconcileFromHealth();
|
|
531
|
-
if (!healthy) {
|
|
532
|
-
shouldTryReconnecting.current = false;
|
|
533
|
-
setConnection({
|
|
534
|
-
state: ConnectionState.CLOSED,
|
|
535
|
-
code: WebSocketClosedReason.KERNEL_DISCONNECTED,
|
|
536
|
-
reason: "kernel not found",
|
|
537
|
-
});
|
|
538
|
-
return;
|
|
539
|
-
}
|
|
540
|
-
ws.reconnect();
|
|
408
|
+
const store = useStore();
|
|
409
|
+
const onMessageError = (error: unknown) => {
|
|
410
|
+
toast({
|
|
411
|
+
title: "Failed to handle message",
|
|
412
|
+
description: prettyError(error),
|
|
413
|
+
variant: "danger",
|
|
414
|
+
});
|
|
541
415
|
};
|
|
542
|
-
|
|
543
|
-
const ws = useConnectionTransport({
|
|
416
|
+
const replica = useNotebookReplica({
|
|
544
417
|
static: isStaticNotebook(),
|
|
545
418
|
transportType,
|
|
546
|
-
/**
|
|
547
|
-
* Unique URL for this session.
|
|
548
|
-
*/
|
|
549
419
|
url: () =>
|
|
550
420
|
transportType === "sse"
|
|
551
421
|
? runtimeManager.getSseURL(sessionId).toString()
|
|
552
422
|
: runtimeManager.getWsURL(sessionId).toString(),
|
|
553
|
-
|
|
554
|
-
* Auth headers for the SSE transport. WebSockets cannot send headers
|
|
555
|
-
* and instead put the access token in the URL.
|
|
556
|
-
*/
|
|
423
|
+
// SSE uses headers for auth. WebSockets carry the token in the URL.
|
|
557
424
|
headers: () => runtimeManager.headers(),
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
updateStartupProgress(null);
|
|
564
|
-
// If we are open, we can reset our reconnecting flag.
|
|
565
|
-
shouldTryReconnecting.current = true;
|
|
566
|
-
},
|
|
567
|
-
|
|
568
|
-
/**
|
|
569
|
-
* Wait to connect, in case the remote kernel still starting up.
|
|
570
|
-
*/
|
|
571
|
-
waitToConnect: async () => {
|
|
572
|
-
if (isStaticNotebook()) {
|
|
573
|
-
return;
|
|
574
|
-
}
|
|
575
|
-
if (isWasm()) {
|
|
576
|
-
return;
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
if (runtimeManager.isSameOrigin) {
|
|
580
|
-
return;
|
|
425
|
+
notebookUrl: (notebookId) => runtimeManager.getNotebookURL(notebookId),
|
|
426
|
+
// Only the host's transports read the URL, so static and WASM never wait.
|
|
427
|
+
waitUntilReady: async () => {
|
|
428
|
+
if (!runtimeManager.isSameOrigin) {
|
|
429
|
+
await runtimeManager.waitForHealthy();
|
|
581
430
|
}
|
|
582
|
-
await runtimeManager.waitForHealthy();
|
|
583
431
|
},
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
* Handle messages sent by the kernel.
|
|
587
|
-
*/
|
|
588
|
-
onMessage: (e) => {
|
|
432
|
+
checkHealth: () => runtimeManager.reconcileFromHealth(),
|
|
433
|
+
onNotification: (notification) => {
|
|
589
434
|
try {
|
|
590
|
-
|
|
435
|
+
handleNotification(notification);
|
|
591
436
|
} catch (error) {
|
|
592
|
-
Logger.error("Failed to handle
|
|
593
|
-
|
|
594
|
-
title: "Failed to handle message",
|
|
595
|
-
description: prettyError(error),
|
|
596
|
-
variant: "danger",
|
|
597
|
-
});
|
|
437
|
+
Logger.error("Failed to handle notification", notification, error);
|
|
438
|
+
onMessageError(error);
|
|
598
439
|
}
|
|
599
440
|
},
|
|
441
|
+
});
|
|
600
442
|
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
443
|
+
// Subscribe before passive connection setup: static/WASM transports can emit synchronously.
|
|
444
|
+
useLayoutEffect(() => {
|
|
445
|
+
const updateConnection = () => {
|
|
446
|
+
const status = store.get(replica.connectionAtom);
|
|
447
|
+
if (status.state === ConnectionState.NOT_STARTED) {
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
if (status.state === ConnectionState.OPEN) {
|
|
451
|
+
updateStartupProgress(null);
|
|
452
|
+
return; // kernel-ready, not the socket, establishes session readiness.
|
|
453
|
+
}
|
|
454
|
+
if (status.state === ConnectionState.CONNECTING) {
|
|
455
|
+
setKernelStartupError(null);
|
|
456
|
+
}
|
|
607
457
|
setConnection((previous) => {
|
|
608
|
-
const status = decision.status;
|
|
609
458
|
if (
|
|
610
459
|
status.state === ConnectionState.CLOSED &&
|
|
611
460
|
status.code === WebSocketClosedReason.KERNEL_STARTUP_ERROR &&
|
|
@@ -624,31 +473,17 @@ export function useMarimoKernelConnection(opts: {
|
|
|
624
473
|
}
|
|
625
474
|
return status;
|
|
626
475
|
});
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
* When we encounter an error, we should close the connection.
|
|
641
|
-
*/
|
|
642
|
-
onError: (e) => {
|
|
643
|
-
Logger.warn("WebSocket error", e);
|
|
644
|
-
setConnection({
|
|
645
|
-
state: ConnectionState.CLOSED,
|
|
646
|
-
code: WebSocketClosedReason.KERNEL_DISCONNECTED,
|
|
647
|
-
reason: "kernel not found",
|
|
648
|
-
});
|
|
649
|
-
tryReconnecting();
|
|
650
|
-
},
|
|
651
|
-
});
|
|
652
|
-
|
|
653
|
-
return { connection, reconnect };
|
|
476
|
+
};
|
|
477
|
+
const unsubscribe = store.sub(replica.connectionAtom, updateConnection);
|
|
478
|
+
updateConnection();
|
|
479
|
+
return unsubscribe;
|
|
480
|
+
}, [
|
|
481
|
+
replica,
|
|
482
|
+
store,
|
|
483
|
+
setConnection,
|
|
484
|
+
setKernelStartupError,
|
|
485
|
+
updateStartupProgress,
|
|
486
|
+
]);
|
|
487
|
+
|
|
488
|
+
return { replica, connection, reconnect: replica.reconnect };
|
|
654
489
|
}
|
package/src/css/globals.css
CHANGED
|
@@ -75,6 +75,9 @@
|
|
|
75
75
|
--ring: hsl(215deg 20.2% 65.1%);
|
|
76
76
|
|
|
77
77
|
/* Semantic colors. */
|
|
78
|
+
--brand: light-dark(#365f43, #a8c9ae);
|
|
79
|
+
--brand-hover: light-dark(#2b5037, #bdd8c2);
|
|
80
|
+
--brand-foreground: light-dark(#fff, #172b1c);
|
|
78
81
|
--destructive: var(--red-9, #e5484d);
|
|
79
82
|
--destructive-hover: var(--red-10, #dc3e42);
|
|
80
83
|
--destructive-border: var(--red-11, #ce2c31);
|
|
@@ -89,6 +92,7 @@
|
|
|
89
92
|
--action-hover: var(--yellow-10, #ffdc00);
|
|
90
93
|
--action-border: var(--yellow-11, #9e6c00);
|
|
91
94
|
--action-foreground: var(--yellow-12, #473b1f);
|
|
95
|
+
--search-highlight: var(--yellow-4, #fff394);
|
|
92
96
|
--link: light-dark(hsl(211deg 90% 42%), hsl(211deg 90% 62%));
|
|
93
97
|
--link-visited: light-dark(hsl(272deg 51% 54%), hsl(272deg 51% 74%));
|
|
94
98
|
--stale: hsl(42deg 56% 44% / 25%);
|
|
@@ -137,6 +141,7 @@
|
|
|
137
141
|
--action-hover: var(--yellow-7, #665417);
|
|
138
142
|
--action-border: var(--yellow-11, #f5e147);
|
|
139
143
|
--action-foreground: var(--yellow-12, #f6eeb4);
|
|
144
|
+
--search-highlight: var(--yellow-6, #524202);
|
|
140
145
|
--stale: hsl(54deg 100% 86.7% / 25%);
|
|
141
146
|
}
|
|
142
147
|
}
|