@marimo-team/islands 0.25.3-dev19 → 0.25.3-dev192
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-BBbOElk3.js} +21 -19
- package/dist/{ErrorBoundary-CBHB755J.js → ErrorBoundary-Dw6uRKVk.js} +19 -19
- package/dist/{abnfDiagram-VCTEODGH-D-Ez91gV.js → abnfDiagram-VCTEODGH-DhMT6Uhd.js} +2 -2
- package/dist/any-language-editor-BVFHDDQ3.js +75 -0
- package/dist/{architectureDiagram-5GKGNRK7-CTpcNtO8.js → architectureDiagram-5GKGNRK7-BVbEiJLq.js} +1 -1
- package/dist/{arrays-CN1djC4k.js → arrays-R6JsImiT.js} +8 -0
- package/dist/assets/__vite-browser-external-C8gQho07.js +1 -0
- package/dist/assets/worker-C6e9ERyd.js +113 -0
- package/dist/{button-CvjkwdSk.js → button-BQRdqQi1.js} +199 -192
- package/dist/{capabilities-CQ5IjhzL.js → capabilities-CI4xUPsp.js} +2 -2
- package/dist/{chat-ui-DaHynk8g.js → chat-ui-BguxTQEL.js} +541 -540
- package/dist/{check-EDwSwP89.js → check-C9Mp9eCK.js} +1 -1
- package/dist/{chunk-IMKFNOWR-DGxi-zeo.js → chunk-IMKFNOWR-By5hSbJJ.js} +1 -1
- package/dist/{chunk-SHT3W25Y-CV9J3rAB.js → chunk-SHT3W25Y-DFrEYG54.js} +1 -1
- package/dist/{chunk-SVP7TREG-BL-9Fqgg.js → chunk-SVP7TREG-DFXGc9ew.js} +1 -1
- package/dist/{chunk-TICWLB2K-Cu_XMjDM.js → chunk-TICWLB2K-DZdNIpoZ.js} +1 -1
- package/dist/{chunk-YOKDWASO-DPZk8vhS.js → chunk-YOKDWASO-DKplTrBY.js} +20 -20
- package/dist/{classDiagram-ZZMXUADV-BXXV13Hq.js → classDiagram-ZZMXUADV-Cgj_eEQA.js} +2 -2
- package/dist/{classDiagram-v2-VYDZK3BY-B7FXJ1Cp.js → classDiagram-v2-VYDZK3BY-DLAUrSqj.js} +2 -2
- package/dist/{code-visibility-CEXXuuOE.js → code-visibility-v_7ijLtx.js} +25 -25
- package/dist/{common-OLE92qsR.js → common-BUwWHpnK.js} +6994 -6819
- package/dist/{copy-icon-Ft7t9bqz.js → copy-icon-De584pZ4.js} +3 -3
- package/dist/{cynefinDiagram-5FMLGOSQ-CH96rwba.js → cynefinDiagram-5FMLGOSQ-Cikf9AKa.js} +1 -1
- package/dist/{dagre-GXQ25YYZ-BD3PmpFY.js → dagre-GXQ25YYZ-C5KEi5_l.js} +1 -1
- package/dist/{data-grid-overlay-editor-CpHX98zN.js → data-grid-overlay-editor-4IZymnXZ.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-BaoBTQjR.js} +1 -1
- package/dist/{diagram-UQ7AKVKN-muQtNZc4.js → diagram-UQ7AKVKN-DDufBsUA.js} +1 -1
- package/dist/{diagram-VX7I27RA-CdhuZAqR.js → diagram-VX7I27RA-CY6RALJ8.js} +1 -1
- package/dist/{diagram-Z3DM3KII-BD8mXjOj.js → diagram-Z3DM3KII-Bc-LHsD6.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-drDjxJyV.js} +1481 -1433
- package/dist/{ebnfDiagram-PWID7BFC-BIN1sweE.js → ebnfDiagram-PWID7BFC-Cz0J-tcC.js} +2 -2
- package/dist/{erDiagram-RLTQ6QDP-Ctp5cfoN.js → erDiagram-RLTQ6QDP-DTXTDgFu.js} +1 -1
- package/dist/{error-banner-D-WCIiMt.js → error-banner-DxJ3s8YO.js} +86 -86
- package/dist/{error-entries-Bv6bZPF3.js → error-entries-CZ1NQ6Kv.js} +4771 -4702
- 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-_f7fx7zj.js → feedback-button-MpeoIn1D.js} +37 -37
- package/dist/{flowDiagram-HODETNUW-3EfLrlFb.js → flowDiagram-HODETNUW-RbwWf2zc.js} +2 -2
- package/dist/{formats-27CW_UP4.js → formats-DbXnijtH.js} +3 -3
- package/dist/{ganttDiagram-EL5Y4UJY-BQT16JSc.js → ganttDiagram-EL5Y4UJY-Dh_4cBJZ.js} +2 -2
- package/dist/{glide-data-editor-Cmu4vWKD.js → glide-data-editor-DU8_EDG5.js} +370 -368
- package/dist/{glide-utils-DJyqh0EM.js → glide-utils-D98laidb.js} +16 -16
- package/dist/{globals-1Hfhz6Dx.js → globals-BeBDOk22.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-D_4_hQ8U.js} +668 -622
- package/dist/{infoDiagram-27XIBGKW-DipQoHxl.js → infoDiagram-27XIBGKW-DlmzZjmI.js} +1 -1
- package/dist/{ishikawaDiagram-5VMMS53U-DgFMjSGz.js → ishikawaDiagram-5VMMS53U-EN3TYP_q.js} +1 -1
- package/dist/{kanban-definition-UXKFOSKX-w1ACVjgl.js → kanban-definition-UXKFOSKX-CK_-Ru7Q.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 +9822 -7824
- package/dist/{mermaid-CHo49Yv-.js → mermaid-DU9ZRmkG.js} +38 -38
- package/dist/mermaid-HWGCJPDP-Du3-HPQA.js +2 -0
- package/dist/{mindmap-definition-YA3MSWOX-CrT0KSfX.js → mindmap-definition-YA3MSWOX-C-hqgUvF.js} +1 -1
- package/dist/{number-overlay-editor-BQN3-Nye.js → number-overlay-editor-BoIkyh6H.js} +3 -3
- package/dist/{objects-CzUgoMIF.js → objects-DCmMvZtn.js} +1 -3
- package/dist/{once-BtE-wKRL.js → once-eG8Vmvjd.js} +1 -1
- package/dist/{pegDiagram-XKGWAZYB-BqvywNJA.js → pegDiagram-XKGWAZYB-BiMejYPB.js} +2 -2
- package/dist/{pieDiagram-E7YTZNPT-BfxJ_XCc.js → pieDiagram-E7YTZNPT-B1zCZ1eq.js} +1 -1
- package/dist/precisionRound-DhAzeRcm.js +49 -0
- package/dist/{process-output-BZg56CCb.js → process-output-DxSCHBWp.js} +4 -4
- package/dist/{quadrantDiagram-AXDQQJYC-Ccw0xMjN.js → quadrantDiagram-AXDQQJYC-Blrm7V7_.js} +1 -1
- package/dist/{railroadDiagram-O6MQD6OU-8vFLVTPu.js → railroadDiagram-O6MQD6OU-BLcfaASl.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-DtBOf52-.js} +1 -1
- package/dist/{reveal-component-nqUW7zgn.js → reveal-component-5M3a2rpj.js} +734 -711
- package/dist/{select-BButFi-d.js → select-2KOiReNY.js} +536 -457
- package/dist/{sequenceDiagram-WJ2MYXX4-CXFMnxGh.js → sequenceDiagram-WJ2MYXX4-DIwF19_n.js} +1 -1
- package/dist/{spec-BwarBpUJ.js → spec-DZDnnlgT.js} +41 -11
- package/dist/{stateDiagram-D77RDMKH-DQeA_CwI.js → stateDiagram-D77RDMKH-sWk1AdYL.js} +2 -2
- package/dist/{stateDiagram-v2-MP3YSRHH-BxxQucm1.js → stateDiagram-v2-MP3YSRHH-CiNo-OI7.js} +2 -2
- package/dist/style.css +1 -1
- package/dist/{swimlanes-42K2YHIH-Do6L-cYg.js → swimlanes-42K2YHIH-Bj3hiOY5.js} +1 -1
- package/dist/{swimlanesDiagram-VR7AAH4N-DUzPvSVU.js → swimlanesDiagram-VR7AAH4N-BzEo2r_N.js} +2 -2
- package/dist/{swiper-component-DKntyn8p.js → swiper-component-BkCm-kLg.js} +2 -2
- package/dist/{time-BieKwdYS.js → time-BaMbJs4z.js} +18 -18
- package/dist/{timeline-definition-24CTP7MA-D3c46WM5.js → timeline-definition-24CTP7MA-CrPQk42H.js} +1 -1
- package/dist/{toDate-UtiwmnH2.js → toDate-Cu2pIZcC.js} +37 -36
- 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-DEhLdRIu.js} +15 -14
- package/dist/{useDateFormatter-D8XruNGG.js → useDateFormatter-D3Tkfzej.js} +2 -2
- package/dist/{useDeepCompareMemoize-DXwzRINI.js → useDeepCompareMemoize-RjZGVhBV.js} +1 -1
- package/dist/{useIframeCapabilities-DBETvvPl.js → useIframeCapabilities-CSdWn6NP.js} +1 -1
- package/dist/{useLifecycle-j7D9uD1o.js → useLifecycle-DtcB2s1z.js} +28 -25
- package/dist/{useTheme-CRnjkku0.js → useTheme-CoEtr4mK.js} +301 -297
- package/dist/{vega-component-BeF9dfyO.js → vega-component-BhjTrP9-.js} +148 -148
- package/dist/{vega-embed-container-BNHE18G9.js → vega-embed-container--LYZqguO.js} +2 -2
- package/dist/{vega-loader.browser-DNST6uVf.js → vega-loader.browser-B9Pz0EGP.js} +298 -507
- package/dist/{vennDiagram-4TSXK5OY-BSZD8JcZ.js → vennDiagram-4TSXK5OY-BaYMoIpj.js} +1 -1
- package/dist/{wardleyDiagram-VM6X3IG4-48cUWkfA.js → wardleyDiagram-VM6X3IG4-DjHeuj8p.js} +1 -1
- package/dist/{xychartDiagram-S5SC5T6Z-CswYgYeu.js → xychartDiagram-S5SC5T6Z-Bc_hcuXS.js} +2 -2
- package/package.json +16 -16
- package/src/__mocks__/document.tsx +54 -0
- package/src/__mocks__/notebook.ts +2 -1
- package/src/__mocks__/requests.ts +0 -3
- package/src/__tests__/module-entry.test.ts +44 -0
- package/src/__tests__/mount.test.ts +1 -21
- package/src/__tests__/{host-imports.test.ts → replica-imports.test.ts} +12 -11
- package/src/components/ai/__tests__/ai-model-dropdown.test.tsx +63 -0
- package/src/components/ai/ai-model-dropdown.tsx +11 -6
- package/src/components/app-config/ai-config.tsx +7 -2
- package/src/components/app-config/user-config-form.tsx +35 -0
- package/src/components/chat/__tests__/message-queue.test.tsx +17 -0
- package/src/components/chat/__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 +55 -42
- 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/minimap-content.tsx +2 -6
- 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 -13
- package/src/components/editor/__tests__/dynamic-favicon.test.tsx +111 -18
- package/src/components/editor/__tests__/output-persistence.test.tsx +6 -1
- 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 +20 -26
- package/src/components/editor/actions/useNotebookActions.tsx +14 -19
- package/src/components/editor/actions/useRestartKernel.tsx +1 -1
- package/src/components/editor/actions/useSetCodeVisibility.ts +10 -11
- package/src/components/editor/actions/useSetOutputsExpanded.ts +13 -18
- package/src/components/editor/ai/add-cell-with-ai.tsx +3 -3
- package/src/components/editor/ai/ai-completion-editor.tsx +1 -0
- package/src/components/editor/alerts/__tests__/connection-notice.test.tsx +1 -1
- package/src/components/editor/alerts/connection-notice.tsx +1 -1
- package/src/components/editor/alerts/startup-logs-alert.tsx +1 -0
- package/src/components/editor/app-container.tsx +1 -1
- package/src/components/editor/boundary/__tests__/ErrorBoundary.test.tsx +1 -1
- package/src/components/editor/cell/CreateCellButton.tsx +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 +22 -36
- 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/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 +2 -1
- package/src/components/editor/chrome/components/__tests__/feedback-button.test.tsx +1 -1
- package/src/components/editor/chrome/components/feedback-button.tsx +1 -1
- package/src/components/editor/chrome/panels/__tests__/packages-panel.test.tsx +31 -2
- package/src/components/editor/chrome/panels/__tests__/runtime-details.test.tsx +1 -1
- package/src/components/editor/chrome/panels/__tests__/sandbox-recovery.test.tsx +1 -1
- package/src/components/editor/chrome/panels/cache-panel.tsx +1 -0
- package/src/components/editor/chrome/panels/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/snippets-panel.tsx +10 -12
- 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/pending-ai-cells.tsx +12 -2
- package/src/components/editor/chrome/wrapper/storage.ts +1 -1
- package/src/components/editor/columns/sortable-column.tsx +1 -1
- package/src/components/editor/connections/components.tsx +5 -10
- package/src/components/editor/controls/Controls.tsx +3 -3
- 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 +9 -23
- 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.tsx +16 -6
- package/src/components/editor/navigation/__tests__/clipboard.test.ts +60 -38
- package/src/components/editor/navigation/__tests__/navigation.test.ts +73 -64
- package/src/components/editor/navigation/clipboard.ts +12 -11
- package/src/components/editor/navigation/focus-utils.ts +4 -4
- package/src/components/editor/navigation/multi-cell-action-toolbar.tsx +11 -20
- package/src/components/editor/navigation/navigation.ts +20 -28
- package/src/components/editor/notebook-banner.tsx +1 -0
- package/src/components/editor/notebook-cell.tsx +19 -13
- 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 +10 -17
- 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/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 +32 -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 -10
- package/src/components/slides/__tests__/minimap-actions.test.tsx +9 -25
- package/src/components/slides/__tests__/slide-scroll-hint.test.tsx +37 -0
- package/src/components/slides/minimap.tsx +7 -3
- package/src/components/slides/reveal-component.tsx +57 -25
- package/src/components/slides/reveal-slides.css +5 -4
- package/src/components/slides/slide-cell-view.tsx +4 -4
- 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 +2 -1
- 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/__tests__/staged-cells.test.ts +26 -25
- 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 +6 -22
- 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 +75 -71
- 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 -0
- package/src/core/cells/__tests__/actions.test.ts +474 -34
- package/src/core/cells/__tests__/add-missing-import.test.ts +7 -8
- package/src/core/cells/__tests__/cell.test.ts +39 -0
- package/src/core/cells/__tests__/cells.test.ts +260 -1165
- package/src/core/cells/__tests__/collapseConsoleOutputs.test.ts +54 -0
- package/src/core/cells/__tests__/document.test.ts +414 -0
- package/src/core/cells/__tests__/flush-document.test.ts +40 -0
- package/src/core/cells/__tests__/notebook-outline.test.ts +114 -0
- package/src/core/cells/__tests__/outputs.test.tsx +71 -53
- package/src/core/cells/__tests__/session.test.ts +117 -36
- package/src/core/cells/__tests__/with-document-save.test.ts +67 -0
- package/src/core/cells/actions.ts +391 -3
- package/src/core/cells/add-missing-import.ts +46 -42
- package/src/core/cells/cell.ts +14 -3
- package/src/core/cells/cells.ts +99 -599
- package/src/core/cells/columns.ts +38 -0
- package/src/core/cells/document.ts +392 -0
- package/src/core/cells/outputs.ts +12 -28
- package/src/core/cells/pending-delete-service.ts +2 -6
- package/src/core/cells/session.ts +1 -1
- package/src/core/cells/types.ts +22 -1
- package/src/core/codemirror/__tests__/setup.test.ts +29 -29
- package/src/core/codemirror/ai/__tests__/resources.test.ts +117 -0
- package/src/core/codemirror/ai/resources.ts +1 -1
- package/src/core/codemirror/cells/__tests__/extensions.test.ts +42 -1
- package/src/core/codemirror/cells/extensions.ts +27 -9
- package/src/core/codemirror/cells/state.ts +1 -1
- 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/notebook-lsp.ts +6 -5
- 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__/config-schema.test.ts +12 -5
- package/src/core/config/config-schema.ts +7 -1
- package/src/core/datasets/__tests__/data-source-discovery.test.ts +5 -5
- package/src/core/datasets/data-source-discovery.ts +4 -6
- package/src/core/edit-app.tsx +19 -23
- package/src/core/errors/error-entries.ts +3 -0
- 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 +73 -43
- package/src/core/islands/__tests__/bridge.test.ts +72 -25
- package/src/core/islands/bootstrap.ts +46 -53
- package/src/core/islands/bridge.ts +74 -23
- 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/kernel/__tests__/handlers.test.ts +7 -153
- package/src/core/kernel/handlers.ts +18 -59
- 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/attachments.ts +38 -0
- package/src/core/notebook/document/__tests__/codemirror.test.ts +552 -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 +18 -0
- package/src/core/notebook/replica/AGENTS.md +11 -0
- package/src/core/notebook/replica/__tests__/attachments.test.ts +56 -0
- package/src/core/notebook/replica/__tests__/document.test.ts +126 -0
- package/src/core/notebook/replica/__tests__/fixtures.ts +79 -0
- package/src/core/notebook/replica/__tests__/replica.test.ts +550 -0
- package/src/core/notebook/replica/backend.ts +19 -0
- package/src/core/notebook/replica/connection.ts +42 -0
- package/src/core/notebook/replica/index.ts +13 -0
- package/src/core/notebook/replica/replica.ts +286 -0
- package/src/core/notebook/replica/resources/attachments.ts +22 -0
- package/src/core/notebook/replica/resources/document.ts +101 -0
- package/src/core/packages/__tests__/useSandboxController.test.tsx +1 -1
- package/src/core/packages/useSandboxController.ts +1 -1
- package/src/core/run-app.tsx +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/filename.ts +1 -1
- package/src/core/saving/save-component.tsx +10 -4
- package/src/core/saving/useAutoSave.ts +1 -1
- package/src/core/session/__tests__/backend.test.ts +235 -0
- package/src/core/session/__tests__/useNotebookReplica.hook.test.tsx +183 -0
- package/src/core/session/__tests__/useNotebookSession.hook.test.tsx +663 -0
- package/src/core/session/active-notebook.ts +11 -0
- package/src/core/session/backend.ts +125 -0
- package/src/core/{websocket → session}/types.ts +2 -2
- package/src/core/session/useNotebookReplica.ts +72 -0
- package/src/core/{websocket → session}/useNotebookSession.tsx +74 -68
- package/src/core/state/__tests__/jotai.test.tsx +108 -0
- package/src/core/state/jotai.ts +1 -1
- package/src/core/static/__tests__/files.test.ts +38 -10
- package/src/core/static/files.ts +2 -0
- package/src/core/{websocket → transports}/__tests__/connection-state.test.ts +1 -13
- package/src/core/transports/__tests__/server.test.ts +408 -0
- package/src/core/transports/__tests__/static.test.ts +175 -0
- package/src/core/transports/__tests__/wasm.test.ts +166 -0
- package/src/core/{websocket → transports}/connection-state.ts +9 -16
- package/src/core/transports/server.ts +152 -0
- package/src/core/transports/static.ts +84 -0
- package/src/core/transports/wasm.ts +97 -0
- package/src/core/wasm/__tests__/bridge.test.ts +213 -50
- package/src/core/wasm/__tests__/worker.test.ts +187 -0
- package/src/core/wasm/bridge.ts +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 +1 -5
- package/src/plugins/__tests__/plugin-object-schemas.test.ts +104 -0
- package/src/plugins/core/registerReactComponent.tsx +1 -1
- package/src/plugins/impl/CodeEditorPlugin.tsx +1 -1
- package/src/plugins/impl/DataEditorPlugin.tsx +1 -1
- package/src/plugins/impl/DataTablePlugin.tsx +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 +1 -1
- 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 +1 -1
- package/src/stories/runtime-story.tsx +23 -16
- 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/mermaid-HWGCJPDP-ByCsZnYF.js +0 -2
- package/dist/precisionRound-DMIVQrt2.js +0 -97
- 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 -6
- package/src/core/host/__tests__/events.test.ts +0 -46
- package/src/core/host/__tests__/notebook-client.test.ts +0 -191
- package/src/core/host/__tests__/protocol.test.ts +0 -214
- package/src/core/host/connection.ts +0 -81
- package/src/core/host/events.ts +0 -60
- package/src/core/host/notebook-client.ts +0 -226
- package/src/core/host/protocol.ts +0 -1943
- package/src/core/state/__tests__/jotai.test.ts +0 -25
- package/src/core/wasm/worker/message-buffer.ts +0 -33
- package/src/core/websocket/__tests__/createConnectionTransport.test.ts +0 -49
- package/src/core/websocket/__tests__/useNotebookClient.hook.test.tsx +0 -140
- package/src/core/websocket/__tests__/useNotebookSession.hook.test.tsx +0 -883
- package/src/core/websocket/transports/__tests__/basic.test.ts +0 -275
- package/src/core/websocket/transports/__tests__/sse.test.ts +0 -335
- package/src/core/websocket/transports/__tests__/transport.test.ts +0 -308
- package/src/core/websocket/transports/__tests__/ws.test.ts +0 -125
- package/src/core/websocket/transports/basic.ts +0 -102
- package/src/core/websocket/transports/create.ts +0 -31
- package/src/core/websocket/transports/sse.ts +0 -308
- package/src/core/websocket/transports/transport.ts +0 -50
- package/src/core/websocket/transports/ws.ts +0 -98
- package/src/core/websocket/useNotebookClient.ts +0 -80
- /package/src/{core/attachments/toast.ts → components/editor/agent-toast.ts} +0 -0
- /package/src/core/{websocket → session}/connection-utils.ts +0 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import type { CellId } from "@marimo-team/client/protocol";
|
|
4
|
+
import { useAtomValue, useSetAtom, useStore } from "jotai";
|
|
5
|
+
import { createContext, type ReactNode, useContext, useMemo } from "react";
|
|
6
|
+
import { cellCodeBinding } from "./codemirror";
|
|
7
|
+
import type { EditableCell } from "./draft";
|
|
8
|
+
import type { DocumentModel } from "./model";
|
|
9
|
+
import { selectCellField, selectOrder } from "./select";
|
|
10
|
+
|
|
11
|
+
const DocumentContext = createContext<DocumentModel | null>(null);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Expose a session-owned model to React. Construct the model with the same store
|
|
15
|
+
* as the enclosing Jotai Provider. The session owner starts it; mounting or
|
|
16
|
+
* unmounting this provider does not change the model's lifetime.
|
|
17
|
+
*
|
|
18
|
+
* ```tsx
|
|
19
|
+
* <Provider store={store}>
|
|
20
|
+
* <DocumentProvider model={model}>
|
|
21
|
+
* <Editor />
|
|
22
|
+
* </DocumentProvider>
|
|
23
|
+
* </Provider>
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export function DocumentProvider({
|
|
27
|
+
model,
|
|
28
|
+
children,
|
|
29
|
+
}: {
|
|
30
|
+
model: DocumentModel;
|
|
31
|
+
children: ReactNode;
|
|
32
|
+
}) {
|
|
33
|
+
return (
|
|
34
|
+
<DocumentContext.Provider value={model}>
|
|
35
|
+
{children}
|
|
36
|
+
</DocumentContext.Provider>
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function useDocumentModel() {
|
|
41
|
+
const model = useContext(DocumentContext);
|
|
42
|
+
if (model === null) {
|
|
43
|
+
throw new Error("Document hooks require a DocumentProvider");
|
|
44
|
+
}
|
|
45
|
+
return model;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Null while the document is unavailable; an empty array for an empty document. */
|
|
49
|
+
export function useNotebookCellOrder() {
|
|
50
|
+
const { documentAtom } = useDocumentModel();
|
|
51
|
+
return useAtomValue(useMemo(() => selectOrder(documentAtom), [documentAtom]));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function useCellField<K extends keyof EditableCell>(id: CellId, field: K) {
|
|
55
|
+
const { documentAtom } = useDocumentModel();
|
|
56
|
+
return useAtomValue(
|
|
57
|
+
useMemo(
|
|
58
|
+
() => selectCellField(documentAtom, id, field),
|
|
59
|
+
[documentAtom, id, field],
|
|
60
|
+
),
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Undefined for an absent cell; null when the host withholds its source. */
|
|
65
|
+
export function useNotebookCellCode(id: CellId) {
|
|
66
|
+
return useCellField(id, "code");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Undefined when the cell or document is unavailable. */
|
|
70
|
+
export function useNotebookCellName(id: CellId) {
|
|
71
|
+
return useCellField(id, "name");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** Undefined when the cell or document is unavailable. */
|
|
75
|
+
export function useNotebookCellConfig(id: CellId) {
|
|
76
|
+
return useCellField(id, "config");
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* A CodeMirror extension that binds the editor's text to a cell's code.
|
|
81
|
+
* Stable until the cell id or document model changes.
|
|
82
|
+
*
|
|
83
|
+
* ```tsx
|
|
84
|
+
* const extension = useNotebookCellCodeExtension(cellId);
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export function useNotebookCellCodeExtension(id: CellId) {
|
|
88
|
+
const model = useDocumentModel();
|
|
89
|
+
const store = useStore();
|
|
90
|
+
return useMemo(
|
|
91
|
+
() => cellCodeBinding({ store, model, cellId: id }),
|
|
92
|
+
[model, store, id],
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* A stable edit function. Synchronous callbacks publish atomically or roll back.
|
|
98
|
+
*
|
|
99
|
+
* ```ts
|
|
100
|
+
* const edit = useNotebookDocumentEdit();
|
|
101
|
+
* edit((tx) => tx.setCode(cellId, code));
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
export function useNotebookDocumentEdit() {
|
|
105
|
+
return useSetAtom(useDocumentModel().editAtom);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Sync status and explicit recovery. flush waits for edits, including newer
|
|
110
|
+
* typing, to reach the confirmed source and returns the revision for Run/Save.
|
|
111
|
+
* Rejections retain local edits; retry explicitly resubmits them. Requests
|
|
112
|
+
* with an unknown outcome reuse their original key within the retry window.
|
|
113
|
+
*/
|
|
114
|
+
export function useNotebookDocumentSync() {
|
|
115
|
+
const model = useDocumentModel();
|
|
116
|
+
const status = useAtomValue(model.syncStatusAtom);
|
|
117
|
+
return { status, flush: model.flush, retry: model.retry };
|
|
118
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
/** The editable document, its drafts, and its synchronization with the host. */
|
|
4
|
+
|
|
5
|
+
export {
|
|
6
|
+
DocumentProvider,
|
|
7
|
+
useNotebookCellCode,
|
|
8
|
+
useNotebookCellCodeExtension,
|
|
9
|
+
useNotebookCellConfig,
|
|
10
|
+
useNotebookCellName,
|
|
11
|
+
useNotebookCellOrder,
|
|
12
|
+
useNotebookDocumentEdit,
|
|
13
|
+
useNotebookDocumentSync,
|
|
14
|
+
} from "./hooks";
|
|
15
|
+
export {
|
|
16
|
+
createDocumentModel,
|
|
17
|
+
type DocumentEdit,
|
|
18
|
+
type DocumentEditor,
|
|
19
|
+
type DocumentModel,
|
|
20
|
+
type DocumentSyncStatus,
|
|
21
|
+
type EditableCell,
|
|
22
|
+
type EditableDocument,
|
|
23
|
+
} from "./model";
|
|
24
|
+
export type { Placement } from "./draft";
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import type * as Protocol from "@marimo-team/client/protocol";
|
|
4
|
+
import {
|
|
5
|
+
type Atom,
|
|
6
|
+
atom,
|
|
7
|
+
type createStore,
|
|
8
|
+
type WritableAtom,
|
|
9
|
+
} from "jotai/vanilla";
|
|
10
|
+
import type { Document, NotebookBackend } from "../replica";
|
|
11
|
+
import type { EditableDocument } from "./draft";
|
|
12
|
+
import {
|
|
13
|
+
createDocumentState,
|
|
14
|
+
type DocumentEdit,
|
|
15
|
+
type DocumentState,
|
|
16
|
+
} from "./state";
|
|
17
|
+
import { createDocumentSync, type DocumentSyncStatus } from "./sync";
|
|
18
|
+
|
|
19
|
+
export type { DocumentEdit, DocumentEditor } from "./state";
|
|
20
|
+
export type { EditableCell, EditableDocument } from "./draft";
|
|
21
|
+
export type { DocumentSyncStatus } from "./sync";
|
|
22
|
+
|
|
23
|
+
/** The editable document and its synchronization with the host. */
|
|
24
|
+
export interface DocumentModel {
|
|
25
|
+
/** Confirmed host state with local drafts applied, null while unavailable or stopped. */
|
|
26
|
+
readonly documentAtom: Atom<EditableDocument | null>;
|
|
27
|
+
/** Ignored while stopped. */
|
|
28
|
+
readonly editAtom: WritableAtom<null, [edit: DocumentEdit], void>;
|
|
29
|
+
readonly syncStatusAtom: Atom<DocumentSyncStatus>;
|
|
30
|
+
/** Drain local edits and return the confirmed revision. */
|
|
31
|
+
flush(): Promise<Protocol.Document>;
|
|
32
|
+
/** Retry a rejection against fresh state, or repeat an uncertain request exactly. */
|
|
33
|
+
retry(): Promise<Protocol.Document>;
|
|
34
|
+
/** Keep edits local until the returned release is called. A no-op while stopped. */
|
|
35
|
+
hold(): () => void;
|
|
36
|
+
/**
|
|
37
|
+
* Edit and synchronize until the signal aborts, which discards local drafts.
|
|
38
|
+
* The model can start again once stopped.
|
|
39
|
+
*/
|
|
40
|
+
start(options: { signal: AbortSignal }): void;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
interface Running {
|
|
44
|
+
readonly state: DocumentState;
|
|
45
|
+
readonly sync: ReturnType<typeof createDocumentSync>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Create without subscribing to anything; editing begins on start. */
|
|
49
|
+
export function createDocumentModel({
|
|
50
|
+
store,
|
|
51
|
+
documentAtom: source,
|
|
52
|
+
backendAtom,
|
|
53
|
+
}: {
|
|
54
|
+
store: ReturnType<typeof createStore>;
|
|
55
|
+
/** The document the host last confirmed. */
|
|
56
|
+
documentAtom: Atom<Document | null>;
|
|
57
|
+
/** The backend that confirmed it, whose commands reach its host. */
|
|
58
|
+
backendAtom: Atom<NotebookBackend | null>;
|
|
59
|
+
}): DocumentModel {
|
|
60
|
+
const runningAtom = atom<Running | null>(null);
|
|
61
|
+
|
|
62
|
+
function stopped(): Promise<never> {
|
|
63
|
+
return Promise.reject(new Error("The document model is not started"));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
documentAtom: atom((get) => {
|
|
68
|
+
const running = get(runningAtom);
|
|
69
|
+
return running ? get(running.state.documentAtom) : null;
|
|
70
|
+
}),
|
|
71
|
+
editAtom: atom(null, (get, set, edit: DocumentEdit) => {
|
|
72
|
+
const running = get(runningAtom);
|
|
73
|
+
if (running) {
|
|
74
|
+
set(running.state.editAtom, edit);
|
|
75
|
+
}
|
|
76
|
+
}),
|
|
77
|
+
syncStatusAtom: atom((get) => {
|
|
78
|
+
const running = get(runningAtom);
|
|
79
|
+
return running ? get(running.sync.statusAtom) : { status: "unavailable" };
|
|
80
|
+
}),
|
|
81
|
+
flush: () => store.get(runningAtom)?.sync.flush() ?? stopped(),
|
|
82
|
+
retry: () => store.get(runningAtom)?.sync.retry() ?? stopped(),
|
|
83
|
+
hold: () => store.get(runningAtom)?.sync.hold() ?? (() => undefined),
|
|
84
|
+
start({ signal }) {
|
|
85
|
+
signal.throwIfAborted();
|
|
86
|
+
if (store.get(runningAtom)) {
|
|
87
|
+
throw new Error("The document model is already started");
|
|
88
|
+
}
|
|
89
|
+
const state = createDocumentState({ store, source, signal });
|
|
90
|
+
const sync = createDocumentSync({
|
|
91
|
+
store,
|
|
92
|
+
documentAtom: source,
|
|
93
|
+
backendAtom,
|
|
94
|
+
state,
|
|
95
|
+
signal,
|
|
96
|
+
});
|
|
97
|
+
const stop = () => store.set(runningAtom, null);
|
|
98
|
+
signal.addEventListener("abort", stop, { once: true });
|
|
99
|
+
store.set(runningAtom, { state, sync });
|
|
100
|
+
if (signal.aborted) {
|
|
101
|
+
stop();
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import type * as Protocol from "@marimo-team/client/protocol";
|
|
4
|
+
import { dequal } from "dequal";
|
|
5
|
+
import type { Atom } from "jotai/vanilla";
|
|
6
|
+
import { selectAtom } from "jotai/vanilla/utils";
|
|
7
|
+
import { type EditableCell, type EditableDocument, sameCell } from "./draft";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Select one cell of a document.
|
|
11
|
+
*
|
|
12
|
+
* The atom notifies when the cell's code, name, or config changes. A new host
|
|
13
|
+
* record with the same values leaves it unchanged. Each call creates an atom,
|
|
14
|
+
* so keep it for as long as its subscription.
|
|
15
|
+
*/
|
|
16
|
+
export function selectCell(
|
|
17
|
+
document: Atom<EditableDocument | null>,
|
|
18
|
+
id: Protocol.CellId,
|
|
19
|
+
): Atom<EditableCell | undefined> {
|
|
20
|
+
return selectAtom(
|
|
21
|
+
document,
|
|
22
|
+
(value) => value?.cells.get(id),
|
|
23
|
+
(a, b) => a === b || (a !== undefined && b !== undefined && sameCell(a, b)),
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Select a document's cell order, null while the document is unavailable. */
|
|
28
|
+
export function selectOrder(
|
|
29
|
+
document: Atom<EditableDocument | null>,
|
|
30
|
+
): Atom<readonly Protocol.CellId[] | null> {
|
|
31
|
+
return selectAtom(document, (value) => value?.order ?? null, dequal);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Select one field of a cell, unchanged until that field's value changes. */
|
|
35
|
+
export function selectCellField<K extends keyof EditableCell>(
|
|
36
|
+
document: Atom<EditableDocument | null>,
|
|
37
|
+
id: Protocol.CellId,
|
|
38
|
+
field: K,
|
|
39
|
+
): Atom<EditableCell[K] | undefined> {
|
|
40
|
+
return selectAtom(document, (value) => value?.cells.get(id)?.[field], dequal);
|
|
41
|
+
}
|
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
atom,
|
|
5
|
+
type Atom,
|
|
6
|
+
type createStore,
|
|
7
|
+
type WritableAtom,
|
|
8
|
+
} from "jotai/vanilla";
|
|
9
|
+
import type { Document } from "../replica";
|
|
10
|
+
import * as Protocol from "@marimo-team/client/protocol";
|
|
11
|
+
import {
|
|
12
|
+
acknowledge,
|
|
13
|
+
type CellEdit,
|
|
14
|
+
createCell,
|
|
15
|
+
deleteCell,
|
|
16
|
+
restoreCell,
|
|
17
|
+
type Draft,
|
|
18
|
+
type EditableDocument,
|
|
19
|
+
editCell,
|
|
20
|
+
EMPTY_DRAFT,
|
|
21
|
+
isEmptyDraft,
|
|
22
|
+
type Placement,
|
|
23
|
+
prune,
|
|
24
|
+
setOrder,
|
|
25
|
+
toChanges,
|
|
26
|
+
viewDocument,
|
|
27
|
+
} from "./draft";
|
|
28
|
+
|
|
29
|
+
/** Operations on a working draft, valid only during the edit callback. */
|
|
30
|
+
export interface DocumentEditor {
|
|
31
|
+
setCode(id: Protocol.CellId, code: string): void;
|
|
32
|
+
setName(id: Protocol.CellId, name: string): void;
|
|
33
|
+
updateConfig(id: Protocol.CellId, patch: Partial<Protocol.CellConfig>): void;
|
|
34
|
+
/** Create a cell, or bring back one this draft deletes with this content. */
|
|
35
|
+
createCell(cell: Protocol.CellInput, placement?: Placement): void;
|
|
36
|
+
deleteCell(id: Protocol.CellId): void;
|
|
37
|
+
/** A permutation of the cells present at this point in the transaction. */
|
|
38
|
+
setOrder(order: readonly Protocol.CellId[]): void;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Synchronous; a thrown error discards the entire transaction. */
|
|
42
|
+
export type DocumentEdit = (editor: DocumentEditor) => void;
|
|
43
|
+
|
|
44
|
+
/** A captured edit request. Return this same object when reporting its result. */
|
|
45
|
+
export interface DocumentSubmission {
|
|
46
|
+
readonly notebookId: Protocol.NotebookId;
|
|
47
|
+
readonly changes: readonly Protocol.Change[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
type ResponseRevision = Pick<Protocol.Document, "notebook_id" | "version">;
|
|
51
|
+
|
|
52
|
+
interface PendingSubmission {
|
|
53
|
+
readonly submission: DocumentSubmission;
|
|
54
|
+
readonly draft: Draft;
|
|
55
|
+
readonly responseRevision: ResponseRevision | null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
interface ModelState {
|
|
59
|
+
readonly confirmed: Document | null;
|
|
60
|
+
readonly drafts: ReadonlyMap<Protocol.NotebookId, Draft>;
|
|
61
|
+
readonly pending: PendingSubmission | null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Local edits over confirmed host state, with one submission in flight.
|
|
66
|
+
*
|
|
67
|
+
* A reset retains the submission so its receipt can reconcile a new snapshot.
|
|
68
|
+
* Switching notebook identity invalidates it, retaining each notebook's draft.
|
|
69
|
+
*/
|
|
70
|
+
export interface DocumentState {
|
|
71
|
+
/** Confirmed host state with local drafts applied, null while unavailable. */
|
|
72
|
+
readonly documentAtom: Atom<EditableDocument | null>;
|
|
73
|
+
/** Null when the document or source needed by a put is unavailable. */
|
|
74
|
+
readonly changesAtom: Atom<readonly Protocol.Change[] | null>;
|
|
75
|
+
/** Remains pending until both the response and its streamed revision arrive. */
|
|
76
|
+
readonly pendingAtom: Atom<DocumentSubmission | null>;
|
|
77
|
+
readonly editAtom: WritableAtom<null, [edit: DocumentEdit], void>;
|
|
78
|
+
/** Capture a request, or null when unavailable, unchanged, or already sending. */
|
|
79
|
+
readonly submitAtom: WritableAtom<null, [], DocumentSubmission | null>;
|
|
80
|
+
/**
|
|
81
|
+
* Report the response revision, or null for a rejected request.
|
|
82
|
+
*
|
|
83
|
+
* Success waits for a complete streamed document at that version or later.
|
|
84
|
+
* Duplicate replies and replies for another notebook are ignored. Retry an
|
|
85
|
+
* uncertain request with the same body and idempotency key; do not reject it
|
|
86
|
+
* or capture a new request until its outcome is known.
|
|
87
|
+
*/
|
|
88
|
+
readonly settleAtom: WritableAtom<
|
|
89
|
+
null,
|
|
90
|
+
[submission: DocumentSubmission, responseRevision: ResponseRevision | null],
|
|
91
|
+
void
|
|
92
|
+
>;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function draftOf(state: ModelState): Draft {
|
|
96
|
+
return state.confirmed === null
|
|
97
|
+
? EMPTY_DRAFT
|
|
98
|
+
: (state.drafts.get(state.confirmed.revision.notebook_id) ?? EMPTY_DRAFT);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function withDraft(state: ModelState, draft: Draft): ModelState {
|
|
102
|
+
if (state.confirmed === null || draft === draftOf(state)) {
|
|
103
|
+
return state;
|
|
104
|
+
}
|
|
105
|
+
const drafts = new Map(state.drafts);
|
|
106
|
+
const notebookId = state.confirmed.revision.notebook_id;
|
|
107
|
+
if (isEmptyDraft(draft)) {
|
|
108
|
+
drafts.delete(notebookId);
|
|
109
|
+
} else {
|
|
110
|
+
drafts.set(notebookId, draft);
|
|
111
|
+
}
|
|
112
|
+
return { ...state, drafts };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Publish the confirmed document and any released fields together. */
|
|
116
|
+
function reconcile(state: ModelState): ModelState {
|
|
117
|
+
const { confirmed, pending } = state;
|
|
118
|
+
if (confirmed === null) {
|
|
119
|
+
return state;
|
|
120
|
+
}
|
|
121
|
+
let draft = draftOf(state);
|
|
122
|
+
if (
|
|
123
|
+
pending !== null &&
|
|
124
|
+
pending.responseRevision !== null &&
|
|
125
|
+
confirmed.revision.version >= pending.responseRevision.version
|
|
126
|
+
) {
|
|
127
|
+
draft = acknowledge(draft, pending.draft);
|
|
128
|
+
state = { ...state, pending: null };
|
|
129
|
+
}
|
|
130
|
+
return withDraft(state, prune(confirmed, draft, state.pending?.draft));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** Internal draft and submission state for one editing lifetime. */
|
|
134
|
+
export function createDocumentState({
|
|
135
|
+
store,
|
|
136
|
+
source,
|
|
137
|
+
signal,
|
|
138
|
+
}: {
|
|
139
|
+
store: ReturnType<typeof createStore>;
|
|
140
|
+
source: Atom<Document | null>;
|
|
141
|
+
signal: AbortSignal;
|
|
142
|
+
}): DocumentState {
|
|
143
|
+
signal.throwIfAborted();
|
|
144
|
+
const stateAtom = atom<ModelState>({
|
|
145
|
+
confirmed: store.get(source),
|
|
146
|
+
drafts: new Map(),
|
|
147
|
+
pending: null,
|
|
148
|
+
});
|
|
149
|
+
const documentAtom = atom((get): EditableDocument | null => {
|
|
150
|
+
const state = get(stateAtom);
|
|
151
|
+
return state.confirmed === null
|
|
152
|
+
? null
|
|
153
|
+
: viewDocument(state.confirmed, draftOf(state));
|
|
154
|
+
});
|
|
155
|
+
const changesAtom = atom((get): readonly Protocol.Change[] | null => {
|
|
156
|
+
const state = get(stateAtom);
|
|
157
|
+
return state.confirmed === null
|
|
158
|
+
? null
|
|
159
|
+
: toChanges(state.confirmed, draftOf(state));
|
|
160
|
+
});
|
|
161
|
+
const pendingAtom = atom((get) => get(stateAtom).pending?.submission ?? null);
|
|
162
|
+
|
|
163
|
+
const unsubscribe = store.sub(source, () => {
|
|
164
|
+
const confirmed = store.get(source);
|
|
165
|
+
store.set(stateAtom, (state) =>
|
|
166
|
+
reconcile({
|
|
167
|
+
...state,
|
|
168
|
+
confirmed,
|
|
169
|
+
pending:
|
|
170
|
+
confirmed !== null &&
|
|
171
|
+
state.pending !== null &&
|
|
172
|
+
confirmed.revision.notebook_id !== state.pending.submission.notebookId
|
|
173
|
+
? null
|
|
174
|
+
: state.pending,
|
|
175
|
+
}),
|
|
176
|
+
);
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
let editing = false;
|
|
180
|
+
const editAtom = atom(null, (get, set, edit: DocumentEdit) => {
|
|
181
|
+
if (editing) {
|
|
182
|
+
throw new Error("Document transactions cannot be nested");
|
|
183
|
+
}
|
|
184
|
+
const state = get(stateAtom);
|
|
185
|
+
if (signal.aborted || state.confirmed === null) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
editing = true;
|
|
189
|
+
try {
|
|
190
|
+
const draft = editDocument(
|
|
191
|
+
state.confirmed,
|
|
192
|
+
draftOf(state),
|
|
193
|
+
edit,
|
|
194
|
+
state.pending?.draft,
|
|
195
|
+
);
|
|
196
|
+
if (
|
|
197
|
+
signal.aborted ||
|
|
198
|
+
get(stateAtom) !== state ||
|
|
199
|
+
get(source) !== state.confirmed
|
|
200
|
+
) {
|
|
201
|
+
throw new Error("The document changed during the transaction");
|
|
202
|
+
}
|
|
203
|
+
set(stateAtom, withDraft(state, draft));
|
|
204
|
+
} finally {
|
|
205
|
+
editing = false;
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
const submitAtom = atom(null, (get, set): DocumentSubmission | null => {
|
|
210
|
+
const state = get(stateAtom);
|
|
211
|
+
if (signal.aborted || state.confirmed === null || state.pending !== null) {
|
|
212
|
+
return null;
|
|
213
|
+
}
|
|
214
|
+
const draft = draftOf(state);
|
|
215
|
+
const changes = toChanges(state.confirmed, draft);
|
|
216
|
+
if (changes === null) {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
if (changes.length === 0) {
|
|
220
|
+
set(stateAtom, withDraft(state, EMPTY_DRAFT));
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
const submission = {
|
|
224
|
+
notebookId: state.confirmed.revision.notebook_id,
|
|
225
|
+
changes,
|
|
226
|
+
};
|
|
227
|
+
set(stateAtom, {
|
|
228
|
+
...state,
|
|
229
|
+
pending: { submission, draft, responseRevision: null },
|
|
230
|
+
});
|
|
231
|
+
return submission;
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
const settleAtom = atom(
|
|
235
|
+
null,
|
|
236
|
+
(
|
|
237
|
+
get,
|
|
238
|
+
set,
|
|
239
|
+
submission: DocumentSubmission,
|
|
240
|
+
responseRevision: ResponseRevision | null,
|
|
241
|
+
) => {
|
|
242
|
+
const state = get(stateAtom);
|
|
243
|
+
if (
|
|
244
|
+
signal.aborted ||
|
|
245
|
+
state.pending?.submission !== submission ||
|
|
246
|
+
state.pending.responseRevision !== null
|
|
247
|
+
) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
if (
|
|
251
|
+
responseRevision !== null &&
|
|
252
|
+
responseRevision.notebook_id !== submission.notebookId
|
|
253
|
+
) {
|
|
254
|
+
throw new Error("Edit response belongs to another notebook");
|
|
255
|
+
}
|
|
256
|
+
set(
|
|
257
|
+
stateAtom,
|
|
258
|
+
reconcile({
|
|
259
|
+
...state,
|
|
260
|
+
pending:
|
|
261
|
+
responseRevision === null
|
|
262
|
+
? null
|
|
263
|
+
: { ...state.pending, responseRevision },
|
|
264
|
+
}),
|
|
265
|
+
);
|
|
266
|
+
},
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
function stop() {
|
|
270
|
+
unsubscribe();
|
|
271
|
+
signal.removeEventListener("abort", stop);
|
|
272
|
+
store.set(stateAtom, {
|
|
273
|
+
confirmed: null,
|
|
274
|
+
drafts: new Map(),
|
|
275
|
+
pending: null,
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
signal.addEventListener("abort", stop, { once: true });
|
|
279
|
+
if (signal.aborted) {
|
|
280
|
+
stop();
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
return {
|
|
284
|
+
documentAtom,
|
|
285
|
+
changesAtom,
|
|
286
|
+
pendingAtom,
|
|
287
|
+
editAtom,
|
|
288
|
+
submitAtom,
|
|
289
|
+
settleAtom,
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function editDocument(
|
|
294
|
+
confirmed: Document,
|
|
295
|
+
draft: Draft,
|
|
296
|
+
edit: DocumentEdit,
|
|
297
|
+
sent: Draft = EMPTY_DRAFT,
|
|
298
|
+
): Draft {
|
|
299
|
+
let next = draft;
|
|
300
|
+
let active = true;
|
|
301
|
+
|
|
302
|
+
function assertActive() {
|
|
303
|
+
if (!active) {
|
|
304
|
+
throw new Error("The document transaction has ended");
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function hasCell(id: Protocol.CellId): boolean {
|
|
309
|
+
const local = next.cells.get(id);
|
|
310
|
+
return (
|
|
311
|
+
local?.kind === "create" ||
|
|
312
|
+
(local?.kind !== "delete" && confirmed.cells.has(id))
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function requireCell(id: Protocol.CellId) {
|
|
317
|
+
assertActive();
|
|
318
|
+
if (!hasCell(id)) {
|
|
319
|
+
throw new Error(`Cell ${id} does not exist`);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function updateCell(id: Protocol.CellId, patch: CellEdit) {
|
|
324
|
+
requireCell(id);
|
|
325
|
+
next = editCell(confirmed, next, id, patch);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const editor: DocumentEditor = {
|
|
329
|
+
setCode: (id, code) => updateCell(id, { code }),
|
|
330
|
+
setName: (id, name) => updateCell(id, { name }),
|
|
331
|
+
updateConfig: (id, patch) =>
|
|
332
|
+
updateCell(id, { config: Protocol.CellConfig.partial().parse(patch) }),
|
|
333
|
+
createCell: (cell, placement = {}) => {
|
|
334
|
+
assertActive();
|
|
335
|
+
if (hasCell(cell.id)) {
|
|
336
|
+
throw new Error(`Cell ${cell.id} already exists`);
|
|
337
|
+
}
|
|
338
|
+
if (placement.after !== undefined && placement.before !== undefined) {
|
|
339
|
+
throw new Error("Specify either before or after for cell placement");
|
|
340
|
+
}
|
|
341
|
+
const anchor = placement.after ?? placement.before;
|
|
342
|
+
if (anchor !== undefined) {
|
|
343
|
+
requireCell(anchor);
|
|
344
|
+
}
|
|
345
|
+
next = confirmed.cells.has(cell.id)
|
|
346
|
+
? restoreCell(confirmed, next, cell, { ...placement }, sent)
|
|
347
|
+
: createCell(next, cell, { ...placement });
|
|
348
|
+
},
|
|
349
|
+
deleteCell: (id) => {
|
|
350
|
+
requireCell(id);
|
|
351
|
+
next = deleteCell(next, id, sent);
|
|
352
|
+
},
|
|
353
|
+
setOrder: (order) => {
|
|
354
|
+
assertActive();
|
|
355
|
+
const { cells } = viewDocument(confirmed, next);
|
|
356
|
+
if (
|
|
357
|
+
order.length !== cells.size ||
|
|
358
|
+
new Set(order).size !== cells.size ||
|
|
359
|
+
order.some((id) => !cells.has(id))
|
|
360
|
+
) {
|
|
361
|
+
throw new Error("Cell order must contain every cell exactly once");
|
|
362
|
+
}
|
|
363
|
+
next = setOrder(next, order);
|
|
364
|
+
},
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
try {
|
|
368
|
+
const result: unknown = edit(editor);
|
|
369
|
+
if (result instanceof Promise) {
|
|
370
|
+
// Observe a rejected async callback without publishing its partial draft.
|
|
371
|
+
result.catch(() => undefined);
|
|
372
|
+
throw new Error("Document edit callbacks must be synchronous");
|
|
373
|
+
}
|
|
374
|
+
return next;
|
|
375
|
+
} finally {
|
|
376
|
+
active = false;
|
|
377
|
+
}
|
|
378
|
+
}
|