@marimo-team/islands 0.25.3-dev20 → 0.25.3-dev201
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-BsWiIPFk.js} +22 -20
- package/dist/{ErrorBoundary-DAPIRYqd.js → ErrorBoundary-JYAf40sB.js} +19 -19
- package/dist/{abnfDiagram-VCTEODGH-D-Ez91gV.js → abnfDiagram-VCTEODGH-I2x4Yu25.js} +2 -2
- package/dist/any-language-editor-BVFHDDQ3.js +75 -0
- package/dist/{architectureDiagram-5GKGNRK7-CTpcNtO8.js → architectureDiagram-5GKGNRK7-1bSQMKzK.js} +1 -1
- package/dist/{arrays-CN1djC4k.js → arrays-DoQ-AILx.js} +15 -27
- package/dist/assets/__vite-browser-external-BCJsx8QS.js +1 -0
- package/dist/assets/worker-DodjWT_Z.js +113 -0
- package/dist/{button-CvjkwdSk.js → button-BQRdqQi1.js} +199 -192
- package/dist/{capabilities-CQ5IjhzL.js → capabilities-C2QUNRXi.js} +2 -2
- package/dist/{chat-ui-DaHynk8g.js → chat-ui-DXDoSuS4.js} +370 -369
- package/dist/{check-EDwSwP89.js → check-C9Mp9eCK.js} +1 -1
- package/dist/{chunk-IMKFNOWR-DGxi-zeo.js → chunk-IMKFNOWR-fsCGAJ9G.js} +1 -1
- package/dist/{chunk-SHT3W25Y-CV9J3rAB.js → chunk-SHT3W25Y-D2STW4hj.js} +1 -1
- package/dist/{chunk-SVP7TREG-BL-9Fqgg.js → chunk-SVP7TREG-CiY7cQG-.js} +1 -1
- package/dist/{chunk-TICWLB2K-Cu_XMjDM.js → chunk-TICWLB2K-C_t5RBp9.js} +1 -1
- package/dist/{chunk-YOKDWASO-DPZk8vhS.js → chunk-YOKDWASO-DKplTrBY.js} +20 -20
- package/dist/{classDiagram-ZZMXUADV-BXXV13Hq.js → classDiagram-ZZMXUADV-B2JvZAP4.js} +2 -2
- package/dist/{classDiagram-v2-VYDZK3BY-B7FXJ1Cp.js → classDiagram-v2-VYDZK3BY-L8VsZG5A.js} +2 -2
- package/dist/code-visibility-BKyYMfr_.js +134 -0
- package/dist/{common-DsUPhkD6.js → common-BCY25vum.js} +6040 -5865
- package/dist/{copy-icon-Ft7t9bqz.js → copy-icon-De584pZ4.js} +3 -3
- package/dist/{cynefinDiagram-5FMLGOSQ-CH96rwba.js → cynefinDiagram-5FMLGOSQ-DdllC264.js} +1 -1
- package/dist/{dagre-GXQ25YYZ-BD3PmpFY.js → dagre-GXQ25YYZ-BaWHw4_f.js} +1 -1
- package/dist/{data-grid-overlay-editor-D7UuVsgB.js → data-grid-overlay-editor-gQmJxgU-.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-pFt-tUDe.js} +1 -1
- package/dist/{diagram-UQ7AKVKN-muQtNZc4.js → diagram-UQ7AKVKN-DqGJiBp4.js} +1 -1
- package/dist/{diagram-VX7I27RA-CdhuZAqR.js → diagram-VX7I27RA-Dr-yzMjf.js} +1 -1
- package/dist/{diagram-Z3DM3KII-BD8mXjOj.js → diagram-Z3DM3KII-8xzJzv-w.js} +1 -1
- package/dist/{dialog-CEBFZNyc.js → dialog-DVRfQuhD.js} +25 -25
- package/dist/{dist-F8Ep36rk.js → dist-B1M0bGO3.js} +1 -1
- package/dist/{dist-D6d86eNJ.js → dist-BA13RJj5.js} +1 -1
- package/dist/{dist-Bvs24R_E.js → dist-BJtmSgcE.js} +48 -48
- package/dist/{dist-CN_BeG2I.js → dist-Ba2VIn1K.js} +53 -53
- package/dist/{dist-PXYI_yuP.js → dist-Bj4bmwUm.js} +12 -12
- package/dist/{dist-DoE4XJBC.js → dist-BmS-ZGjl.js} +8626 -8626
- package/dist/{dist-BorMD-uX.js → dist-Bzogh7CW.js} +87 -87
- package/dist/{dist-CN8zI-XC.js → dist-CThPVKaP.js} +1385 -1382
- package/dist/{dist-DiDibOYr.js → dist-CTi5FTiV.js} +87 -87
- package/dist/{dist-diIx5qJW.js → dist-Ck_C32ye.js} +2 -2
- package/dist/{dist-BLfKmR-l.js → dist-D1fnFp1J.js} +1 -1
- package/dist/{dist-OR1OnN-y.js → dist-D3x9__Fu.js} +46 -46
- package/dist/{dist-BMQf5zIS.js → dist-D7mrh5sO.js} +36 -36
- package/dist/{dist-CSJ0MDRw.js → dist-D9Q3xjiP.js} +1 -1
- package/dist/{dist-BuaRHxOc.js → dist-DP60Ubh8.js} +2 -2
- package/dist/{dist-CSbh1PNP.js → dist-DTv9KkpW.js} +12 -12
- package/dist/{dist-D-wwqlzJ.js → dist-DVVwOfrD.js} +109 -109
- package/dist/{dist-C8fAKSH1.js → dist-DYXM73-k.js} +36 -36
- package/dist/{dist-DBtSl3sf.js → dist-DjeybPOb.js} +1 -1
- package/dist/{dist-CrSP_H1M.js → dist-DtGn9N4h.js} +197 -197
- package/dist/{dist-CLdpGQVr.js → dist-KN80qWCP.js} +2 -2
- package/dist/{dist-DpBpA_n1.js → dist-Lm-D-Vr6.js} +3 -3
- package/dist/{dist-Cg7gzw-a.js → dist-O0qFpEJh.js} +56 -56
- package/dist/{dist-CkTTIdBe.js → dist-OUle2RT7.js} +207 -207
- package/dist/{dist-BK4Oj99o.js → dist-T5rh6JvL.js} +1 -1
- package/dist/{dropdown-menu-CP_qCYHC.js → dropdown-menu-NlnsmNA6.js} +1481 -1433
- package/dist/{ebnfDiagram-PWID7BFC-BIN1sweE.js → ebnfDiagram-PWID7BFC-Br04Wy-E.js} +2 -2
- package/dist/{erDiagram-RLTQ6QDP-Ctp5cfoN.js → erDiagram-RLTQ6QDP-D5-XVgvv.js} +1 -1
- package/dist/{error-banner-D-WCIiMt.js → error-banner-DxJ3s8YO.js} +86 -86
- package/dist/{error-entries-Bv6bZPF3.js → error-entries-C2Ux0Fjt.js} +8404 -9095
- package/dist/{esm-D2gTsXEV.js → esm-Bbw_Njjx.js} +575 -575
- package/dist/{esm-AMFssoNp.js → esm-mDQNEFe_.js} +354 -354
- package/dist/feedback-button-BKgw9MHY.js +374 -0
- package/dist/{flowDiagram-HODETNUW-3EfLrlFb.js → flowDiagram-HODETNUW-CVl2kREF.js} +2 -2
- package/dist/{formats-27CW_UP4.js → formats-BCYthwyc.js} +3 -3
- package/dist/{ganttDiagram-EL5Y4UJY-BQT16JSc.js → ganttDiagram-EL5Y4UJY-Dh_4cBJZ.js} +2 -2
- package/dist/{glide-data-editor-KvS90MGh.js → glide-data-editor-CzS51bb2.js} +370 -368
- package/dist/{glide-utils-DJyqh0EM.js → glide-utils-D98laidb.js} +16 -16
- package/dist/{globals-yruoELTW.js → globals-DQ4tv_a-.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-CkH7vdBZ.js} +477 -380
- package/dist/{infoDiagram-27XIBGKW-DipQoHxl.js → infoDiagram-27XIBGKW-BJ4vNcZE.js} +1 -1
- package/dist/{ishikawaDiagram-5VMMS53U-DgFMjSGz.js → ishikawaDiagram-5VMMS53U-B_Jy1Dsm.js} +1 -1
- package/dist/{kanban-definition-UXKFOSKX-w1ACVjgl.js → kanban-definition-UXKFOSKX-C6MkS9vw.js} +1 -1
- package/dist/{label-BDKF3Afc.js → label-Qvw1E97W.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 +9706 -7709
- package/dist/{mermaid-CHo49Yv-.js → mermaid-Bh918qrq.js} +52 -52
- package/dist/mermaid-HWGCJPDP-Du3-HPQA.js +2 -0
- package/dist/{mindmap-definition-YA3MSWOX-CrT0KSfX.js → mindmap-definition-YA3MSWOX-BP3ZTuir.js} +1 -1
- package/dist/{number-overlay-editor-R2i0FdxV.js → number-overlay-editor-B3ZE3-6d.js} +3 -3
- package/dist/{objects-CzUgoMIF.js → objects-DCmMvZtn.js} +1 -3
- package/dist/{once-BtE-wKRL.js → once-NnpX_HnX.js} +1 -1
- package/dist/{pegDiagram-XKGWAZYB-BqvywNJA.js → pegDiagram-XKGWAZYB-nNGOQtnt.js} +2 -2
- package/dist/{pieDiagram-E7YTZNPT-BfxJ_XCc.js → pieDiagram-E7YTZNPT-CpRz5BZz.js} +1 -1
- package/dist/precisionRound-DhAzeRcm.js +49 -0
- package/dist/{process-output-BZg56CCb.js → process-output-OujAtFW4.js} +5 -5
- package/dist/{quadrantDiagram-AXDQQJYC-Ccw0xMjN.js → quadrantDiagram-AXDQQJYC-Blrm7V7_.js} +1 -1
- package/dist/{railroadDiagram-O6MQD6OU-8vFLVTPu.js → railroadDiagram-O6MQD6OU-BqOEN4I0.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-CEfg6vu9.js} +1 -1
- package/dist/{reveal-component-C42-YBfQ.js → reveal-component-DXa9FXf6.js} +733 -710
- package/dist/{select-BButFi-d.js → select-2KOiReNY.js} +536 -457
- package/dist/{sequenceDiagram-WJ2MYXX4-CXFMnxGh.js → sequenceDiagram-WJ2MYXX4-IOmpQcOi.js} +1 -1
- package/dist/{spec-BwarBpUJ.js → spec-Dkp64vVQ.js} +41 -11
- package/dist/{stateDiagram-D77RDMKH-DQeA_CwI.js → stateDiagram-D77RDMKH-tgU-EY9_.js} +2 -2
- package/dist/{stateDiagram-v2-MP3YSRHH-BxxQucm1.js → stateDiagram-v2-MP3YSRHH-BofhG6q1.js} +2 -2
- package/dist/style.css +1 -1
- package/dist/{swimlanes-42K2YHIH-Do6L-cYg.js → swimlanes-42K2YHIH-DW4vWDBd.js} +1 -1
- package/dist/{swimlanesDiagram-VR7AAH4N-DUzPvSVU.js → swimlanesDiagram-VR7AAH4N-BJcrqUJr.js} +2 -2
- package/dist/{swiper-component-DKntyn8p.js → swiper-component-BVfnhbnt.js} +2 -2
- package/dist/{time-BieKwdYS.js → time-BaMbJs4z.js} +18 -18
- package/dist/{timeline-definition-24CTP7MA-D3c46WM5.js → timeline-definition-24CTP7MA-D_QU3NGs.js} +1 -1
- package/dist/{toDate-UtiwmnH2.js → toDate-BNDEXbfV.js} +44 -43
- package/dist/{toast-B9UMEi8u.js → toast-B5t9o6s_.js} +219 -201
- package/dist/{tooltip-BO1REbqs.js → tooltip-s4zZxwKe.js} +325 -301
- package/dist/{use-restore-focus-BEM7sFWl.js → use-restore-focus-BgDTd2tc.js} +1482 -1433
- package/dist/{useAsyncData-Deh5kszT.js → useAsyncData-ASDni9vH.js} +15 -14
- package/dist/{useDateFormatter-D8XruNGG.js → useDateFormatter-D3Tkfzej.js} +2 -2
- package/dist/{useDeepCompareMemoize-DXwzRINI.js → useDeepCompareMemoize-B1Ogyf53.js} +1 -1
- package/dist/{useIframeCapabilities-DBETvvPl.js → useIframeCapabilities-6a_yDNXp.js} +1 -1
- package/dist/{useLifecycle-j7D9uD1o.js → useLifecycle-Bfpa2m7k.js} +28 -25
- package/dist/{useTheme-CRnjkku0.js → useTheme-5TwyOh3B.js} +522 -314
- package/dist/{vega-component-BeF9dfyO.js → vega-component-BHS9UOtC.js} +158 -158
- 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-YFYsNIAh.js} +1 -1
- package/dist/{wardleyDiagram-VM6X3IG4-48cUWkfA.js → wardleyDiagram-VM6X3IG4-i_n8mAWC.js} +1 -1
- package/dist/{xychartDiagram-S5SC5T6Z-CswYgYeu.js → xychartDiagram-S5SC5T6Z-BYGN95wW.js} +2 -2
- package/package.json +16 -16
- package/src/__mocks__/document.tsx +63 -0
- package/src/__mocks__/notebook.ts +3 -4
- package/src/__mocks__/partial.ts +26 -0
- package/src/__mocks__/requests.ts +0 -3
- package/src/__tests__/main.test.tsx +24 -1
- 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/app-config-form.tsx +5 -9
- 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/__tests__/notebook-access-selector.test.tsx +64 -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 +20 -101
- package/src/components/chat/chat-utils.ts +4 -8
- package/src/components/chat/notebook-access-selector.stories.tsx +22 -0
- package/src/components/chat/notebook-access-selector.tsx +100 -0
- package/src/components/data-table/TableBottomBar.tsx +4 -1
- 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__/pagination.test.tsx +28 -1
- 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 +17 -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/pagination.tsx +44 -33
- 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 +96 -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 +17 -12
- package/src/components/datasources/datasources.tsx +56 -43
- package/src/components/datasources/utils.ts +32 -23
- package/src/components/debugger/debugger-code.tsx +5 -0
- package/src/components/dependency-graph/custom-node.tsx +1 -1
- 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/minimap-content.tsx +13 -19
- package/src/components/dependency-graph/panels.tsx +4 -2
- package/src/components/dependency-graph/utils/__tests__/layout.test.ts +18 -11
- package/src/components/editor/SortableCell.tsx +1 -3
- package/src/components/editor/__tests__/Output.test.tsx +50 -32
- 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 +28 -14
- package/src/components/editor/__tests__/dynamic-favicon.test.tsx +111 -18
- package/src/components/editor/__tests__/output-persistence.test.tsx +6 -2
- package/src/components/editor/__tests__/package-alert.test.tsx +22 -1
- package/src/components/editor/actions/__tests__/name-cell-input.test.tsx +69 -0
- package/src/components/editor/actions/__tests__/pair-with-agent-modal.test.tsx +34 -8
- package/src/components/editor/actions/__tests__/pair-with-agent.test.tsx +2 -6
- package/src/components/editor/actions/name-cell-input.tsx +4 -3
- package/src/components/editor/actions/pair-with-agent-commands.ts +2 -2
- package/src/components/editor/actions/pair-with-agent-modal.tsx +19 -16
- package/src/components/editor/actions/useCellActionButton.tsx +26 -31
- package/src/components/editor/actions/useConfigActions.tsx +3 -4
- package/src/components/editor/actions/useNotebookActions.tsx +19 -23
- package/src/components/editor/actions/useRestartKernel.tsx +1 -1
- package/src/components/editor/actions/useSetCodeVisibility.ts +11 -12
- package/src/components/editor/actions/useSetOutputsExpanded.ts +14 -19
- 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/alerts/stdin-blocking-alert.tsx +1 -1
- 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 +15 -21
- package/src/components/editor/cell/DeleteButton.tsx +3 -2
- package/src/components/editor/cell/RunButton.tsx +2 -2
- package/src/components/editor/cell/StagedAICell.tsx +10 -2
- package/src/components/editor/cell/StopButton.tsx +2 -2
- package/src/components/editor/cell/__tests__/StagedAICell.test.tsx +3 -1
- package/src/components/editor/cell/__tests__/useShouldShowInterrupt.test.ts +39 -0
- package/src/components/editor/cell/cell-actions.tsx +12 -1
- package/src/components/editor/cell/code/__tests__/language-toggle.test.tsx +54 -0
- package/src/components/editor/cell/code/cell-editor.tsx +36 -43
- package/src/components/editor/cell/code/language-toggle.tsx +8 -7
- package/src/components/editor/cell/collapse.tsx +11 -4
- package/src/components/editor/cell/useAddCell.ts +4 -8
- package/src/components/editor/cell/useDeleteCell.tsx +10 -36
- package/src/components/editor/cell/useRunCells.ts +2 -5
- package/src/components/editor/cell/useShouldShowInterrupt.ts +2 -12
- package/src/components/editor/cell/useSplitCell.tsx +10 -6
- package/src/components/editor/chrome/components/__tests__/feedback-button.test.tsx +1 -1
- package/src/components/editor/chrome/components/feedback-button.tsx +2 -8
- 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/dependency-graph-panel.tsx +1 -1
- package/src/components/editor/chrome/panels/logs-panel.tsx +2 -1
- 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/session-panel.tsx +1 -1
- package/src/components/editor/chrome/panels/snippets-panel.tsx +10 -12
- package/src/components/editor/chrome/panels/variable-panel.tsx +1 -5
- package/src/components/editor/chrome/wrapper/__tests__/attachment-status.test.tsx +9 -18
- package/src/components/editor/chrome/wrapper/__tests__/document-sync-status.test.tsx +92 -0
- package/src/components/editor/chrome/wrapper/__tests__/pending-ai-cells.test.tsx +61 -2
- 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/document-sync-status.tsx +54 -0
- 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/footer.tsx +2 -0
- package/src/components/editor/chrome/wrapper/minimap-state.ts +1 -1
- 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/columns/__tests__/cell-column.test.tsx +1 -1
- package/src/components/editor/columns/cell-column.tsx +1 -1
- package/src/components/editor/columns/sortable-column.tsx +2 -2
- package/src/components/editor/connections/components.tsx +5 -10
- package/src/components/editor/controls/Controls.tsx +4 -4
- 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 +10 -4
- package/src/components/editor/controls/command-palette.tsx +22 -10
- package/src/components/editor/controls/keyboard-shortcuts.tsx +14 -5
- package/src/components/editor/documentation.css +34 -11
- package/src/components/editor/dynamic-favicon.tsx +21 -40
- package/src/components/editor/errors/__tests__/send-error-report-button.test.tsx +17 -29
- package/src/components/editor/errors/auto-fix.tsx +4 -8
- 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 +48 -15
- 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 +148 -0
- package/src/components/editor/links/cell-link-list.tsx +1 -1
- package/src/components/editor/links/cell-link.tsx +17 -7
- package/src/components/editor/navigation/__tests__/clipboard.test.ts +60 -38
- package/src/components/editor/navigation/__tests__/navigation.test.ts +108 -85
- package/src/components/editor/navigation/__tests__/selection.test.ts +43 -21
- package/src/components/editor/navigation/clipboard.ts +17 -14
- package/src/components/editor/navigation/focus-utils.ts +23 -4
- package/src/components/editor/navigation/multi-cell-action-toolbar.tsx +17 -33
- package/src/components/editor/navigation/navigation.ts +71 -70
- package/src/components/editor/navigation/selection.ts +30 -29
- package/src/components/editor/notebook-banner.tsx +1 -0
- package/src/components/editor/notebook-cell.tsx +29 -31
- 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/output/console/__tests__/ConsoleOutput.test.tsx +125 -69
- package/src/components/editor/package-alert.tsx +14 -7
- package/src/components/editor/renderers/cell-array.tsx +22 -33
- package/src/components/editor/renderers/grid-layout/grid-layout.tsx +12 -6
- package/src/components/editor/renderers/slides-layout/__tests__/plugin.test.ts +0 -1
- package/src/components/editor/renderers/slides-layout/slides-layout.tsx +1 -1
- package/src/components/editor/renderers/vertical-layout/__tests__/useFocusFirstEditor.test.ts +4 -4
- package/src/components/editor/renderers/vertical-layout/sidebar/toggle.tsx +7 -1
- package/src/components/editor/renderers/vertical-layout/useFocusFirstEditor.ts +1 -1
- package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +1 -1
- package/src/components/editor/stdin-blocking-alert.tsx +1 -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/markdown/markdown-renderer.tsx +4 -8
- 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/edit-page.tsx +19 -17
- package/src/components/pages/home-page.tsx +164 -91
- package/src/components/scratchpad/scratchpad.test.tsx +97 -0
- package/src/components/scratchpad/scratchpad.tsx +20 -11
- package/src/components/slides/__tests__/minimap-actions.test.tsx +22 -29
- package/src/components/slides/__tests__/minimap.test.ts +38 -19
- package/src/components/slides/__tests__/slide-scroll-hint.test.tsx +37 -0
- package/src/components/slides/minimap.tsx +17 -12
- package/src/components/slides/reveal-component.tsx +58 -26
- package/src/components/slides/reveal-slides.css +5 -4
- package/src/components/slides/slide-cell-view.tsx +4 -5
- package/src/components/slides/slide-form.tsx +1 -0
- package/src/components/slides/slide-scroll-hint.tsx +3 -1
- package/src/components/sort/SortableCellsProvider.tsx +8 -25
- package/src/components/tracing/tracing-keyboard.test.tsx +85 -0
- package/src/components/tracing/tracing.tsx +46 -42
- 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/MarimoApp.tsx +1 -1
- package/src/core/ai/__tests__/staged-cells.test.ts +27 -26
- package/src/core/ai/context/providers/__tests__/cell-output.test.ts +8 -12
- package/src/core/ai/context/providers/cell-output.ts +2 -2
- package/src/core/ai/context/providers/datasource.ts +6 -2
- package/src/core/ai/staged-cells.ts +15 -18
- package/src/core/ai/tools/__tests__/edit-notebook-tool.test.ts +40 -88
- package/src/core/ai/tools/__tests__/registry.test.ts +17 -0
- package/src/core/ai/tools/base.ts +18 -15
- package/src/core/ai/tools/edit-notebook-tool.ts +86 -80
- package/src/core/ai/tools/registry.ts +13 -10
- package/src/core/ai/tools/sample-tool.ts +6 -7
- package/src/core/cells/__tests__/__snapshots__/cells.test.ts.snap +4 -37
- package/src/core/cells/__tests__/actions.test.ts +624 -35
- package/src/core/cells/__tests__/add-missing-import.test.ts +7 -8
- package/src/core/cells/__tests__/arrange.test.ts +432 -0
- package/src/core/cells/__tests__/cell.test.ts +39 -0
- package/src/core/cells/__tests__/cells.test.ts +218 -2491
- package/src/core/cells/__tests__/collapseConsoleOutputs.test.ts +54 -0
- package/src/core/cells/__tests__/document.test.ts +341 -0
- package/src/core/cells/__tests__/editor.test.ts +57 -0
- package/src/core/cells/__tests__/flush-document.test.ts +40 -0
- package/src/core/cells/__tests__/harness.ts +106 -0
- package/src/core/cells/__tests__/layout.test.ts +177 -0
- package/src/core/cells/__tests__/notebook-outline.test.ts +120 -0
- package/src/core/cells/__tests__/outputs.test.tsx +71 -53
- package/src/core/cells/__tests__/session.test.ts +445 -211
- package/src/core/cells/__tests__/utils.test.ts +9 -108
- package/src/core/cells/__tests__/with-document-save.test.ts +67 -0
- package/src/core/cells/actions.ts +636 -6
- package/src/core/cells/add-missing-import.ts +47 -43
- package/src/core/cells/arrange.ts +529 -0
- package/src/core/cells/cell.ts +14 -3
- package/src/core/cells/cells.ts +120 -1337
- package/src/core/cells/columns.ts +38 -0
- package/src/core/cells/document.ts +289 -0
- package/src/core/cells/edit.ts +30 -0
- package/src/core/cells/editor.ts +82 -0
- package/src/core/cells/layout.ts +221 -0
- package/src/core/cells/outputs.ts +12 -28
- package/src/core/cells/pending-delete-service.ts +3 -7
- package/src/core/cells/session.ts +76 -53
- package/src/core/cells/types.ts +22 -6
- package/src/core/cells/utils.ts +10 -8
- 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 +42 -1
- package/src/core/codemirror/cells/extensions.ts +27 -9
- package/src/core/codemirror/cells/state.ts +1 -1
- package/src/core/codemirror/copilot/__tests__/getCodes.test.ts +6 -7
- package/src/core/codemirror/copilot/getCodes.ts +2 -2
- package/src/core/codemirror/format.ts +6 -5
- package/src/core/codemirror/keymaps/vim.ts +4 -8
- package/src/core/codemirror/language/__tests__/sql.test.ts +22 -20
- package/src/core/codemirror/language/__tests__/utils.test.ts +187 -15
- package/src/core/codemirror/language/cell-code.ts +114 -0
- package/src/core/codemirror/language/extension.ts +52 -35
- 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 +16 -24
- package/src/core/codemirror/language/panel/panel.tsx +1 -0
- package/src/core/codemirror/language/types.ts +7 -7
- package/src/core/codemirror/language/utils.ts +9 -39
- package/src/core/codemirror/lsp/__tests__/notebook-lsp.test.ts +1 -2
- package/src/core/codemirror/lsp/notebook-lsp.ts +6 -5
- package/src/core/codemirror/lsp/utils.ts +1 -1
- 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 -13
- 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__/app-config.test.ts +64 -0
- package/src/core/config/__tests__/config-schema.test.ts +13 -6
- package/src/core/config/config-schema.ts +13 -3
- package/src/core/config/config.ts +26 -12
- 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/documentation/doc-lookup.ts +1 -1
- package/src/core/edit-app.tsx +21 -28
- package/src/core/errors/error-entries.ts +4 -1
- package/src/core/export/hooks.ts +1 -1
- package/src/core/export/layout.ts +2 -2
- package/src/core/hotkeys/actions.ts +2 -4
- package/src/core/islands/__tests__/bootstrap.test.ts +69 -43
- package/src/core/islands/__tests__/bridge.test.ts +72 -25
- package/src/core/islands/bootstrap.ts +46 -54
- package/src/core/islands/bridge.ts +74 -23
- package/src/core/islands/components/__tests__/IslandControls.test.tsx +7 -5
- package/src/core/islands/components/web-components.tsx +1 -1
- 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/kernel/__tests__/handlers.test.ts +7 -153
- package/src/core/kernel/handlers.ts +19 -72
- package/src/core/meta/__tests__/code-visibility.test.tsx +78 -70
- package/src/core/meta/code-visibility.ts +18 -9
- package/src/core/network/__tests__/connection.test.ts +1 -1
- package/src/core/network/__tests__/requests-lazy.test.ts +1 -3
- package/src/core/network/connection-notice.ts +1 -1
- package/src/core/network/connection.ts +1 -1
- package/src/core/network/requests-lazy.ts +1 -4
- package/src/core/network/requests-network.ts +0 -25
- package/src/core/network/requests-static.ts +0 -3
- package/src/core/network/requests-toasting.tsx +0 -3
- package/src/core/network/types.ts +0 -12
- package/src/core/network/useConnectionNotice.ts +8 -2
- package/src/core/notebook/__tests__/operations.test.ts +51 -0
- package/src/core/notebook/attachments.ts +38 -0
- package/src/core/notebook/document/__tests__/codemirror.test.ts +586 -0
- package/src/core/notebook/document/__tests__/draft.test.ts +363 -0
- package/src/core/notebook/document/__tests__/fixtures.ts +92 -0
- package/src/core/notebook/document/__tests__/hold.test.ts +88 -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 +247 -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 +459 -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 +216 -0
- package/src/core/notebook/document/draft.ts +502 -0
- package/src/core/notebook/document/hooks.tsx +118 -0
- package/src/core/notebook/document/index.ts +24 -0
- package/src/core/notebook/document/model.ts +105 -0
- package/src/core/notebook/document/select.ts +41 -0
- package/src/core/notebook/document/state.ts +378 -0
- package/src/core/notebook/document/sync.ts +418 -0
- package/src/core/notebook/index.ts +19 -0
- package/src/core/notebook/operations.ts +30 -0
- package/src/core/notebook/replica/AGENTS.md +11 -0
- package/src/core/notebook/replica/__tests__/attachments.test.ts +56 -0
- package/src/core/{host → notebook/replica}/__tests__/document.test.ts +18 -16
- 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/{host → notebook/replica}/resources/document.ts +4 -4
- package/src/core/packages/__tests__/useSandboxController.test.tsx +1 -1
- package/src/core/packages/useSandboxController.ts +1 -1
- package/src/core/run-app.tsx +48 -51
- 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/__tests__/state.test.ts +111 -0
- package/src/core/saving/__tests__/useAutoSave.test.tsx +67 -0
- package/src/core/saving/filename.ts +1 -1
- package/src/core/saving/save-component.tsx +28 -36
- package/src/core/saving/state.ts +38 -39
- package/src/core/saving/useAutoSave.ts +17 -53
- package/src/core/session/__tests__/backend.test.ts +236 -0
- package/src/core/session/__tests__/useNotebookReplica.hook.test.tsx +184 -0
- package/src/core/session/__tests__/useNotebookSession.hook.test.tsx +663 -0
- package/src/core/session/active-notebook.ts +22 -0
- package/src/core/session/backend.ts +123 -0
- package/src/core/session/embedded.ts +7 -0
- package/src/core/{websocket → session}/types.ts +2 -2
- package/src/core/session/useNotebookReplica.ts +74 -0
- package/src/core/{websocket → session}/useNotebookSession.tsx +77 -72
- 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 +306 -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 +166 -0
- package/src/core/transports/wasm.ts +97 -0
- package/src/core/wasm/__tests__/bridge.test.ts +214 -50
- package/src/core/wasm/__tests__/worker.test.ts +187 -0
- package/src/core/wasm/bridge.ts +75 -69
- 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 +88 -44
- package/src/css/globals.css +66 -22
- 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 +20 -15
- 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 +69 -37
- 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 +387 -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 +2 -5
- package/src/stories/data-table.stories.tsx +31 -0
- 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 +2 -5
- package/src/stories/runtime-story.tsx +23 -17
- 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 → createReducer.test.tsx} +29 -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 +53 -26
- 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/code-visibility-DkCqn-PO.js +0 -138
- package/dist/feedback-button-wnAMXOGA.js +0 -379
- package/dist/mermaid-HWGCJPDP-ByCsZnYF.js +0 -2
- package/dist/precisionRound-DMIVQrt2.js +0 -97
- package/src/components/editor/navigation/__tests__/state.test.ts +0 -81
- package/src/components/editor/navigation/state.ts +0 -65
- package/src/core/ai/tools/__tests__/run-cells-tool.test.ts +0 -656
- package/src/core/ai/tools/run-cells-tool.ts +0 -303
- package/src/core/attachments/state.ts +0 -21
- package/src/core/cells/__tests__/apply-transaction.test.ts +0 -991
- package/src/core/cells/__tests__/document-changes.test.ts +0 -1140
- package/src/core/cells/__tests__/document-roundtrip.test.ts +0 -392
- package/src/core/cells/document-changes.ts +0 -944
- package/src/core/host/AGENTS.md +0 -11
- package/src/core/host/__tests__/events.test.ts +0 -46
- package/src/core/host/__tests__/fixtures.ts +0 -39
- package/src/core/host/__tests__/notebook-client.test.ts +0 -303
- package/src/core/host/__tests__/protocol.test.ts +0 -214
- package/src/core/host/__tests__/stream.test.ts +0 -211
- package/src/core/host/connection.ts +0 -81
- package/src/core/host/events.ts +0 -60
- package/src/core/host/notebook-client.ts +0 -272
- package/src/core/host/protocol.ts +0 -1943
- package/src/core/host/resources/resource.ts +0 -59
- package/src/core/host/stream.ts +0 -213
- 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/utils/__tests__/id-tree.test.ts +0 -2145
- package/src/utils/id-tree.tsx +0 -1134
- /package/src/{core/attachments/toast.ts → components/editor/agent-toast.ts} +0 -0
- /package/src/core/{websocket → session}/connection-utils.ts +0 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
/** How a document's cells fall into columns. */
|
|
4
|
+
|
|
5
|
+
import type { EditableDocument } from "@/core/notebook/document";
|
|
6
|
+
import type { CellId } from "./ids";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Each cell's column: its `column` config, or the column of the cell before
|
|
10
|
+
* it. The first cell starts in column 0.
|
|
11
|
+
*/
|
|
12
|
+
export function resolveColumns(
|
|
13
|
+
document: EditableDocument,
|
|
14
|
+
): Map<CellId, number> {
|
|
15
|
+
const columns = new Map<CellId, number>();
|
|
16
|
+
let current = 0;
|
|
17
|
+
for (const id of document.order) {
|
|
18
|
+
const column = document.cells.get(id)?.config.column;
|
|
19
|
+
if (column != null && column >= 0) {
|
|
20
|
+
current = column;
|
|
21
|
+
}
|
|
22
|
+
// The protocol's ids are plain strings; the notebook brands them.
|
|
23
|
+
columns.set(id as CellId, current);
|
|
24
|
+
}
|
|
25
|
+
return columns;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** The cells of each column in order, with empty columns for gaps. */
|
|
29
|
+
export function groupByColumn(document: EditableDocument): CellId[][] {
|
|
30
|
+
const columns: CellId[][] = [[]];
|
|
31
|
+
for (const [id, column] of resolveColumns(document)) {
|
|
32
|
+
while (columns.length <= column) {
|
|
33
|
+
columns.push([]);
|
|
34
|
+
}
|
|
35
|
+
columns[column].push(id);
|
|
36
|
+
}
|
|
37
|
+
return columns;
|
|
38
|
+
}
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Keep the notebook state and the host document in step while cells live
|
|
5
|
+
* in both.
|
|
6
|
+
*
|
|
7
|
+
* TODO(MO-8028): Delete this module once components read cells from the
|
|
8
|
+
* document model and `notebookAtom` holds only runtime and editor state.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { dequal as isEqual } from "dequal";
|
|
12
|
+
import type { createStore } from "jotai";
|
|
13
|
+
import { createRef, type RefObject } from "react";
|
|
14
|
+
import type { CellHandle } from "@/components/editor/notebook-cell";
|
|
15
|
+
import type {
|
|
16
|
+
DocumentEdit,
|
|
17
|
+
DocumentEditor,
|
|
18
|
+
DocumentModel,
|
|
19
|
+
EditableCell,
|
|
20
|
+
EditableDocument,
|
|
21
|
+
} from "@/core/notebook/document";
|
|
22
|
+
import type { DispatchedActionOf } from "@/utils/createReducer";
|
|
23
|
+
import { prepareCellCodeUpdate } from "../codemirror/language/cell-code";
|
|
24
|
+
import { canUseRtc, isRtcEnabled } from "../rtc/state";
|
|
25
|
+
import { store } from "../state/jotai";
|
|
26
|
+
import { activeDocumentModelAtom } from "../session/active-notebook";
|
|
27
|
+
import type { NotebookState, ReducerCellActions } from "./cells";
|
|
28
|
+
import type { CellId } from "./ids";
|
|
29
|
+
import { followColumnsAtom } from "./layout";
|
|
30
|
+
import {
|
|
31
|
+
type CellData,
|
|
32
|
+
createCell,
|
|
33
|
+
createCellConfig,
|
|
34
|
+
createCellRuntimeState,
|
|
35
|
+
isEdited,
|
|
36
|
+
} from "./types";
|
|
37
|
+
|
|
38
|
+
type CellAction = DispatchedActionOf<ReducerCellActions>;
|
|
39
|
+
|
|
40
|
+
// Following the document ----------------------------------------------------
|
|
41
|
+
|
|
42
|
+
/** The cell's data with the document's fields, and its editor brought along. */
|
|
43
|
+
function followCell(
|
|
44
|
+
current: CellData,
|
|
45
|
+
cell: EditableCell,
|
|
46
|
+
handle: RefObject<CellHandle | null> | undefined,
|
|
47
|
+
): CellData {
|
|
48
|
+
// Withheld source keeps the code this client has.
|
|
49
|
+
const code = cell.code ?? current.code;
|
|
50
|
+
const config = isEqual(current.config, cell.config)
|
|
51
|
+
? current.config
|
|
52
|
+
: createCellConfig(cell.config);
|
|
53
|
+
if (
|
|
54
|
+
code === current.code &&
|
|
55
|
+
cell.name === current.name &&
|
|
56
|
+
config === current.config
|
|
57
|
+
) {
|
|
58
|
+
return current;
|
|
59
|
+
}
|
|
60
|
+
if (code === current.code) {
|
|
61
|
+
return { ...current, name: cell.name, config };
|
|
62
|
+
}
|
|
63
|
+
// RTC cells follow Loro. Other editors take the host's code; one that
|
|
64
|
+
// shows it already, as the editor this client types in does, is left alone.
|
|
65
|
+
if (!isRtcEnabled() || !canUseRtc(current.id)) {
|
|
66
|
+
const view = handle?.current?.editorViewOrNull;
|
|
67
|
+
const update = view && prepareCellCodeUpdate(view.state, code);
|
|
68
|
+
if (update) {
|
|
69
|
+
view.dispatch(update);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
...current,
|
|
74
|
+
code,
|
|
75
|
+
name: cell.name,
|
|
76
|
+
config,
|
|
77
|
+
edited: isEdited(current.lastCodeRun, code),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Make the notebook's cells and order follow the document.
|
|
83
|
+
*
|
|
84
|
+
* Returns the same state when nothing differs, so a local edit that the
|
|
85
|
+
* document already reflects changes nothing.
|
|
86
|
+
*
|
|
87
|
+
* TODO(MO-8028): Delete with `reconcileDocument` once cells are read from
|
|
88
|
+
* the document model.
|
|
89
|
+
*/
|
|
90
|
+
export function applyDocument(
|
|
91
|
+
state: NotebookState,
|
|
92
|
+
document: EditableDocument,
|
|
93
|
+
): NotebookState {
|
|
94
|
+
// The protocol's ids are plain strings; the notebook brands them.
|
|
95
|
+
const cellIds = isEqual(document.order, state.cellIds)
|
|
96
|
+
? state.cellIds
|
|
97
|
+
: ([...document.order] as CellId[]);
|
|
98
|
+
let { cellData, cellRuntime, cellHandles } = state;
|
|
99
|
+
for (const id of cellIds) {
|
|
100
|
+
const cell = document.cells.get(id);
|
|
101
|
+
const current = state.cellData[id];
|
|
102
|
+
if (cell === undefined) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (current === undefined) {
|
|
106
|
+
// A new cell with code is stale until it runs. The kernel's last run
|
|
107
|
+
// settles it on kernel-ready.
|
|
108
|
+
const code = cell.code ?? "";
|
|
109
|
+
cellData = {
|
|
110
|
+
...cellData,
|
|
111
|
+
[id]: createCell({
|
|
112
|
+
id,
|
|
113
|
+
code,
|
|
114
|
+
name: cell.name,
|
|
115
|
+
config: createCellConfig(cell.config),
|
|
116
|
+
edited: code.trim().length > 0,
|
|
117
|
+
}),
|
|
118
|
+
};
|
|
119
|
+
cellRuntime = {
|
|
120
|
+
...cellRuntime,
|
|
121
|
+
[id]: cellRuntime[id] ?? createCellRuntimeState(),
|
|
122
|
+
};
|
|
123
|
+
cellHandles = { ...cellHandles, [id]: createRef() };
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const next = followCell(current, cell, state.cellHandles[id]);
|
|
127
|
+
if (next !== current) {
|
|
128
|
+
cellData = { ...cellData, [id]: next };
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const present = new Set(cellIds);
|
|
132
|
+
const removed = state.cellIds.filter((id) => !present.has(id));
|
|
133
|
+
if (removed.length > 0) {
|
|
134
|
+
const gone = new Set(removed);
|
|
135
|
+
const keep = <V>(record: Record<CellId, V>): Record<CellId, V> =>
|
|
136
|
+
Object.fromEntries(
|
|
137
|
+
Object.entries(record).filter(([id]) => !gone.has(id as CellId)),
|
|
138
|
+
) as Record<CellId, V>;
|
|
139
|
+
cellData = keep(cellData);
|
|
140
|
+
cellRuntime = keep(cellRuntime);
|
|
141
|
+
cellHandles = keep(cellHandles);
|
|
142
|
+
}
|
|
143
|
+
if (
|
|
144
|
+
cellIds === state.cellIds &&
|
|
145
|
+
cellData === state.cellData &&
|
|
146
|
+
removed.length === 0
|
|
147
|
+
) {
|
|
148
|
+
return state;
|
|
149
|
+
}
|
|
150
|
+
return { ...state, cellIds, cellData, cellRuntime, cellHandles };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Reconcile the model's document and name its columns, now and on each
|
|
155
|
+
* change, until the signal aborts.
|
|
156
|
+
*
|
|
157
|
+
* TODO(MO-8028): Delete with `applyDocument`.
|
|
158
|
+
*/
|
|
159
|
+
export function followDocument({
|
|
160
|
+
store,
|
|
161
|
+
model,
|
|
162
|
+
reconcile,
|
|
163
|
+
signal,
|
|
164
|
+
}: {
|
|
165
|
+
store: ReturnType<typeof createStore>;
|
|
166
|
+
model: Pick<DocumentModel, "documentAtom">;
|
|
167
|
+
reconcile: (document: EditableDocument) => void;
|
|
168
|
+
signal: AbortSignal;
|
|
169
|
+
}): void {
|
|
170
|
+
const follow = () => {
|
|
171
|
+
const document = store.get(model.documentAtom);
|
|
172
|
+
if (document !== null) {
|
|
173
|
+
reconcile(document);
|
|
174
|
+
store.set(followColumnsAtom, document);
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
const unsubscribe = store.sub(model.documentAtom, follow);
|
|
178
|
+
signal.addEventListener("abort", unsubscribe, { once: true });
|
|
179
|
+
follow();
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Editing the document ------------------------------------------------------
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* The edit that writes the code a reducer action changed, or null when none
|
|
186
|
+
* did. Order, creation, deletion, names and configs are edited on the model
|
|
187
|
+
* directly by their atoms.
|
|
188
|
+
*/
|
|
189
|
+
function diffNotebook(
|
|
190
|
+
prev: NotebookState,
|
|
191
|
+
next: NotebookState,
|
|
192
|
+
): DocumentEdit | null {
|
|
193
|
+
const steps: Array<(tx: DocumentEditor) => void> = [];
|
|
194
|
+
for (const id of next.cellIds) {
|
|
195
|
+
const cell = next.cellData[id];
|
|
196
|
+
const before = prev.cellData[id];
|
|
197
|
+
if (before !== undefined && cell !== before && before.code !== cell.code) {
|
|
198
|
+
steps.push((tx) => tx.setCode(id, cell.code));
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (steps.length === 0) {
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
return (tx) => {
|
|
205
|
+
for (const step of steps) {
|
|
206
|
+
step(tx);
|
|
207
|
+
}
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Middleware for the notebook reducer. Writes what an action changed about
|
|
213
|
+
* the cells and their order into the document model as one edit.
|
|
214
|
+
*
|
|
215
|
+
* TODO(MO-8028): Only code is left in `diffNotebook`. The middleware goes
|
|
216
|
+
* with it, once the editors bind to the model.
|
|
217
|
+
*/
|
|
218
|
+
export function documentEditMiddleware(
|
|
219
|
+
prev: NotebookState,
|
|
220
|
+
next: NotebookState,
|
|
221
|
+
action: CellAction,
|
|
222
|
+
): void {
|
|
223
|
+
// The document replaces the notebook's cells, so following it is no edit.
|
|
224
|
+
if (action.type === "reconcileDocument") {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
if (prev.cellIds === next.cellIds && prev.cellData === next.cellData) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
const model = store.get(activeDocumentModelAtom);
|
|
231
|
+
if (model === null) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
const edit = diffNotebook(prev, next);
|
|
235
|
+
if (edit !== null) {
|
|
236
|
+
store.set(model.editAtom, edit);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Commands that read the document on the host -------------------------------
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Send this client's edits to the host before a command that reads them
|
|
244
|
+
* there. Without a document or a backend, as on a static page, there is
|
|
245
|
+
* nothing to send and the command proceeds.
|
|
246
|
+
*/
|
|
247
|
+
export async function flushDocument(): Promise<void> {
|
|
248
|
+
const model = store.get(activeDocumentModelAtom);
|
|
249
|
+
if (
|
|
250
|
+
model === null ||
|
|
251
|
+
store.get(model.syncStatusAtom).status === "unavailable"
|
|
252
|
+
) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
await model.flush();
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Run a legacy save after this client's edits reach the host, and keep
|
|
260
|
+
* later edits local until it finishes. The save carries the whole
|
|
261
|
+
* notebook and the host takes it as the document, so an edit sent
|
|
262
|
+
* meanwhile would be overwritten. When the edits cannot be sent the save
|
|
263
|
+
* still runs, and the model resumes against the saved document.
|
|
264
|
+
*
|
|
265
|
+
* TODO(MO-8028): Goes with the legacy save, along with the hold.
|
|
266
|
+
*/
|
|
267
|
+
export async function withDocumentSave<T>(save: () => Promise<T>): Promise<T> {
|
|
268
|
+
const model = store.get(activeDocumentModelAtom);
|
|
269
|
+
if (model === null) {
|
|
270
|
+
return save();
|
|
271
|
+
}
|
|
272
|
+
let flushed = true;
|
|
273
|
+
try {
|
|
274
|
+
await model.flush();
|
|
275
|
+
} catch {
|
|
276
|
+
flushed = false;
|
|
277
|
+
}
|
|
278
|
+
const release = model.hold();
|
|
279
|
+
let result: T;
|
|
280
|
+
try {
|
|
281
|
+
result = await save();
|
|
282
|
+
} finally {
|
|
283
|
+
release();
|
|
284
|
+
}
|
|
285
|
+
if (!flushed) {
|
|
286
|
+
void model.retry().catch(() => undefined);
|
|
287
|
+
}
|
|
288
|
+
return result;
|
|
289
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
/** The active document model, as the notebook operations reach it. */
|
|
4
|
+
|
|
5
|
+
import type { Getter, Setter } from "jotai";
|
|
6
|
+
import type { DocumentModel, EditableDocument } from "@/core/notebook/document";
|
|
7
|
+
import { activeDocumentModelAtom } from "../session/active-notebook";
|
|
8
|
+
import { notebookAtom } from "./cells";
|
|
9
|
+
import type { CellId } from "./ids";
|
|
10
|
+
|
|
11
|
+
export function modelOf(get: Getter): DocumentModel {
|
|
12
|
+
const model = get(activeDocumentModelAtom);
|
|
13
|
+
if (!model) {
|
|
14
|
+
throw new Error("The notebook has no document to edit");
|
|
15
|
+
}
|
|
16
|
+
return model;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function documentOf(get: Getter): EditableDocument {
|
|
20
|
+
const document = get(modelOf(get).documentAtom);
|
|
21
|
+
if (!document) {
|
|
22
|
+
throw new Error("The notebook has no document to edit");
|
|
23
|
+
}
|
|
24
|
+
return document;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Scroll to and focus the cell once it mounts. */
|
|
28
|
+
export function focusWhenMounted(set: Setter, cellId: CellId): void {
|
|
29
|
+
set(notebookAtom, (state) => ({ ...state, scrollKey: cellId }));
|
|
30
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
/** What only this browser knows about cells: hidden code showing for now, and editor state to restore. */
|
|
4
|
+
|
|
5
|
+
import { atom, useAtomValue } from "jotai";
|
|
6
|
+
import { useMemo } from "react";
|
|
7
|
+
import type { SerializedEditorState } from "../codemirror/types";
|
|
8
|
+
import type { CellId } from "./ids";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Hidden cells whose code is showing for now: a cell being edited, one just
|
|
12
|
+
* created, or one just made hidden. Blurring the cell hides it again.
|
|
13
|
+
*/
|
|
14
|
+
export const shownHiddenCodeAtom = atom<ReadonlySet<CellId>>(new Set<CellId>());
|
|
15
|
+
|
|
16
|
+
export const useShowsHiddenCode = (cellId: CellId) =>
|
|
17
|
+
useAtomValue(
|
|
18
|
+
useMemo(
|
|
19
|
+
() => atom((get) => get(shownHiddenCodeAtom).has(cellId)),
|
|
20
|
+
[cellId],
|
|
21
|
+
),
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
/** Whether a cell's code is hidden on the page. */
|
|
25
|
+
export function isCodeHidden(
|
|
26
|
+
hideCode: boolean | undefined,
|
|
27
|
+
shown: ReadonlySet<CellId>,
|
|
28
|
+
cellId: CellId,
|
|
29
|
+
): boolean {
|
|
30
|
+
return Boolean(hideCode) && !shown.has(cellId);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const showHiddenCodeAtom = atom(
|
|
34
|
+
null,
|
|
35
|
+
(_get, set, { cellId }: { cellId: CellId }): void => {
|
|
36
|
+
set(shownHiddenCodeAtom, (cells) => new Set([...cells, cellId]));
|
|
37
|
+
},
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
/** Hide a cell's code again. Returns whether it was showing. */
|
|
41
|
+
export const hideShownCodeAtom = atom(
|
|
42
|
+
null,
|
|
43
|
+
(get, set, { cellId }: { cellId: CellId }): boolean => {
|
|
44
|
+
if (!get(shownHiddenCodeAtom).has(cellId)) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
set(shownHiddenCodeAtom, (cells) => {
|
|
48
|
+
const next = new Set(cells);
|
|
49
|
+
next.delete(cellId);
|
|
50
|
+
return next;
|
|
51
|
+
});
|
|
52
|
+
return true;
|
|
53
|
+
},
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Editor state for cells about to mount again, such as a cell undo brings
|
|
58
|
+
* back. The editor takes its entry when it mounts, and deleting the cell
|
|
59
|
+
* drops it.
|
|
60
|
+
*/
|
|
61
|
+
export const restoredEditorStatesAtom = atom<
|
|
62
|
+
ReadonlyMap<CellId, SerializedEditorState>
|
|
63
|
+
>(new Map<CellId, SerializedEditorState>());
|
|
64
|
+
|
|
65
|
+
export const useRestoredEditorState = (cellId: CellId) =>
|
|
66
|
+
useAtomValue(
|
|
67
|
+
useMemo(
|
|
68
|
+
() => atom((get) => get(restoredEditorStatesAtom).get(cellId) ?? null),
|
|
69
|
+
[cellId],
|
|
70
|
+
),
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
export const takeRestoredEditorStateAtom = atom(
|
|
74
|
+
null,
|
|
75
|
+
(_get, set, { cellId }: { cellId: CellId }): void => {
|
|
76
|
+
set(restoredEditorStatesAtom, (states) => {
|
|
77
|
+
const next = new Map(states);
|
|
78
|
+
next.delete(cellId);
|
|
79
|
+
return next;
|
|
80
|
+
});
|
|
81
|
+
},
|
|
82
|
+
);
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
/** The cells as they appear on the page: by column, with folded sections hidden. */
|
|
4
|
+
|
|
5
|
+
import { atom, useAtomValue } from "jotai";
|
|
6
|
+
import type { EditableDocument } from "@/core/notebook/document";
|
|
7
|
+
import { findCollapseRange } from "../dom/outline";
|
|
8
|
+
import { activeDocumentModelAtom } from "../session/active-notebook";
|
|
9
|
+
import { cellOutlinesAtom } from "./cells";
|
|
10
|
+
import { groupByColumn } from "./columns";
|
|
11
|
+
import { CellId } from "./ids";
|
|
12
|
+
import type { Outline } from "./outline";
|
|
13
|
+
|
|
14
|
+
/** A column's identity on this page, as drag and drop and saved widths refer to it. */
|
|
15
|
+
export type CellColumnId = string & { __brand: "CellColumnId" };
|
|
16
|
+
|
|
17
|
+
/** The headers whose sections the user folded. Only this browser knows. */
|
|
18
|
+
export const collapsedAtom = atom<ReadonlySet<CellId>>(new Set<CellId>());
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* This browser's names for the document's columns, by position. The
|
|
22
|
+
* document knows columns only by position, so `followColumnsAtom` names
|
|
23
|
+
* a column as it appears and forgets one as it goes, and the column
|
|
24
|
+
* operations carry the names along as they rearrange.
|
|
25
|
+
*/
|
|
26
|
+
export const columnIdsAtom = atom<readonly CellColumnId[]>([]);
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Trailing columns a rearrangement here emptied. The document cannot hold
|
|
30
|
+
* an empty column at its end, so the page keeps them, as drop targets for
|
|
31
|
+
* the cell being dragged, until a drop compacts them.
|
|
32
|
+
*/
|
|
33
|
+
export const emptyColumnIdsAtom = atom<readonly CellColumnId[]>([]);
|
|
34
|
+
|
|
35
|
+
export function newColumnId(): CellColumnId {
|
|
36
|
+
return `column-${CellId.create()}` as CellColumnId;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function isColumnId(id: unknown): id is CellColumnId {
|
|
40
|
+
return typeof id === "string" && id.startsWith("column-");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Name the document's columns as the document changes. A column that
|
|
45
|
+
* appears takes over an empty column the page keeps, or gets a fresh id;
|
|
46
|
+
* one that goes is forgotten.
|
|
47
|
+
*/
|
|
48
|
+
export const followColumnsAtom = atom(
|
|
49
|
+
null,
|
|
50
|
+
(get, set, document: EditableDocument): void => {
|
|
51
|
+
const count = groupByColumn(document).length;
|
|
52
|
+
const ids = get(columnIdsAtom);
|
|
53
|
+
if (ids.length === count) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const empty = get(emptyColumnIdsAtom);
|
|
57
|
+
const named = [...ids, ...empty].slice(0, count);
|
|
58
|
+
while (named.length < count) {
|
|
59
|
+
named.push(newColumnId());
|
|
60
|
+
}
|
|
61
|
+
set(columnIdsAtom, named);
|
|
62
|
+
set(emptyColumnIdsAtom, empty.slice(Math.max(0, count - ids.length)));
|
|
63
|
+
},
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
/** The document's columns, each with its id, then the empty ones the page keeps. */
|
|
67
|
+
function columnsOf(
|
|
68
|
+
document: EditableDocument | null,
|
|
69
|
+
ids: readonly CellColumnId[],
|
|
70
|
+
empty: readonly CellColumnId[],
|
|
71
|
+
): Array<{ id: CellColumnId; ids: CellId[] }> {
|
|
72
|
+
const groups = document === null ? [[]] : groupByColumn(document);
|
|
73
|
+
return [
|
|
74
|
+
...groups.map((cells, index) => ({
|
|
75
|
+
// Before the first document names them, columns go by position.
|
|
76
|
+
id: ids[index] ?? (`column-${index}` as CellColumnId),
|
|
77
|
+
ids: cells,
|
|
78
|
+
})),
|
|
79
|
+
...empty.map((id) => ({ id, ids: [] as CellId[] })),
|
|
80
|
+
];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface LayoutColumn {
|
|
84
|
+
readonly id: CellColumnId;
|
|
85
|
+
/** Every cell of the column, in order. */
|
|
86
|
+
readonly ids: readonly CellId[];
|
|
87
|
+
/** The cells on the page: those no fold hides. */
|
|
88
|
+
readonly visible: readonly CellId[];
|
|
89
|
+
/**
|
|
90
|
+
* Each folded header and the cells it hides, nested sections included. A
|
|
91
|
+
* folded header with nothing under it yet has an empty fold.
|
|
92
|
+
*/
|
|
93
|
+
readonly folds: ReadonlyMap<CellId, readonly CellId[]>;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface Layout {
|
|
97
|
+
readonly columns: readonly LayoutColumn[];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* The cells each folded header hides. A section runs from its header to the
|
|
102
|
+
* cell before the next header of the same or a higher level, so a folded
|
|
103
|
+
* header inside a folded section is hidden along with its own section.
|
|
104
|
+
*/
|
|
105
|
+
export function foldSections(
|
|
106
|
+
ids: readonly CellId[],
|
|
107
|
+
outlines: (Outline | null)[],
|
|
108
|
+
collapsed: ReadonlySet<CellId>,
|
|
109
|
+
): Map<CellId, readonly CellId[]> {
|
|
110
|
+
const folds = new Map<CellId, readonly CellId[]>();
|
|
111
|
+
ids.forEach((id, index) => {
|
|
112
|
+
const outline = outlines[index];
|
|
113
|
+
if (!collapsed.has(id) || !outline || outline.items.length === 0) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const range = findCollapseRange(index, outlines);
|
|
117
|
+
if (range === null) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
folds.set(id, ids.slice(index + 1, range[1] + 1));
|
|
121
|
+
});
|
|
122
|
+
return folds;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function deriveLayout(
|
|
126
|
+
columns: ReadonlyArray<{ id: CellColumnId; ids: readonly CellId[] }>,
|
|
127
|
+
outlineOf: (id: CellId) => Outline | null,
|
|
128
|
+
collapsed: ReadonlySet<CellId>,
|
|
129
|
+
): Layout {
|
|
130
|
+
return {
|
|
131
|
+
columns: columns.map(({ id, ids }) => {
|
|
132
|
+
const folds = foldSections(ids, ids.map(outlineOf), collapsed);
|
|
133
|
+
const hidden = new Set([...folds.values()].flat());
|
|
134
|
+
return { id, ids, visible: ids.filter((c) => !hidden.has(c)), folds };
|
|
135
|
+
}),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* The layout of the notebook's cells: the document's order and columns,
|
|
141
|
+
* this browser's column ids and folds, and the kernel's outlines.
|
|
142
|
+
*
|
|
143
|
+
* TODO(MO-8028): Outlines come from executions later.
|
|
144
|
+
*/
|
|
145
|
+
export const layoutAtom = atom((get): Layout => {
|
|
146
|
+
const model = get(activeDocumentModelAtom);
|
|
147
|
+
const document = model === null ? null : get(model.documentAtom);
|
|
148
|
+
const outlines = get(cellOutlinesAtom);
|
|
149
|
+
return deriveLayout(
|
|
150
|
+
columnsOf(document, get(columnIdsAtom), get(emptyColumnIdsAtom)),
|
|
151
|
+
(id) => outlines[id] ?? null,
|
|
152
|
+
get(collapsedAtom),
|
|
153
|
+
);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
export const useLayout = () => useAtomValue(layoutAtom);
|
|
157
|
+
|
|
158
|
+
export const numColumnsAtom = atom((get) => get(layoutAtom).columns.length);
|
|
159
|
+
|
|
160
|
+
export function findColumn(
|
|
161
|
+
layout: Layout,
|
|
162
|
+
columnId: CellColumnId,
|
|
163
|
+
): LayoutColumn | undefined {
|
|
164
|
+
return layout.columns.find((column) => column.id === columnId);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** The column holding `id`. Throws for a cell the layout does not have. */
|
|
168
|
+
export function columnOf(layout: Layout, id: CellId): LayoutColumn {
|
|
169
|
+
const column = layout.columns.find((column) => column.ids.includes(id));
|
|
170
|
+
if (column === undefined) {
|
|
171
|
+
throw new Error(`Cell ${id} is not in the layout`);
|
|
172
|
+
}
|
|
173
|
+
return column;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/** The cells a folded header hides, or undefined when `id` is not a folded header. */
|
|
177
|
+
export function foldOf(
|
|
178
|
+
layout: Layout,
|
|
179
|
+
id: CellId,
|
|
180
|
+
): readonly CellId[] | undefined {
|
|
181
|
+
for (const column of layout.columns) {
|
|
182
|
+
const fold = column.folds.get(id);
|
|
183
|
+
if (fold !== undefined) {
|
|
184
|
+
return fold;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return undefined;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** The headers whose folds hide `id`. */
|
|
191
|
+
export function foldsHiding(layout: Layout, id: CellId): CellId[] {
|
|
192
|
+
const column = layout.columns.find((column) => column.ids.includes(id));
|
|
193
|
+
if (column === undefined) {
|
|
194
|
+
return [];
|
|
195
|
+
}
|
|
196
|
+
return [...column.folds]
|
|
197
|
+
.filter(([, hidden]) => hidden.includes(id))
|
|
198
|
+
.map(([header]) => header);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* The folded headers whose sections a cell without a heading would fall
|
|
203
|
+
* into, placed right after `id`: those hiding `id`, and `id` itself when it
|
|
204
|
+
* is a folded header. A section runs until the next heading, so a cell
|
|
205
|
+
* placed after the last cell of a fold is still inside it.
|
|
206
|
+
*/
|
|
207
|
+
export function foldsAfter(layout: Layout, id: CellId): CellId[] {
|
|
208
|
+
const hiding = foldsHiding(layout, id);
|
|
209
|
+
return foldOf(layout, id) === undefined ? hiding : [...hiding, id];
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/** The visible cell `offset` places from `id` in its column, if there is one. */
|
|
213
|
+
export function visibleNeighbor(
|
|
214
|
+
layout: Layout,
|
|
215
|
+
id: CellId,
|
|
216
|
+
offset: -1 | 1,
|
|
217
|
+
): CellId | undefined {
|
|
218
|
+
const { visible } = columnOf(layout, id);
|
|
219
|
+
const index = visible.indexOf(id);
|
|
220
|
+
return index === -1 ? undefined : visible[index + offset];
|
|
221
|
+
}
|