@marimo-team/islands 0.25.3-dev21 → 0.25.3-dev210

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.
Files changed (717) hide show
  1. package/dist/{ConnectedDataExplorerComponent-DfG3PRaJ.js → ConnectedDataExplorerComponent-D6RHJV8D.js} +120 -116
  2. package/dist/{ErrorBoundary-ttSr7_91.js → ErrorBoundary-VruaQLnK.js} +16 -16
  3. package/dist/{abnfDiagram-VCTEODGH-B3w-XWX8.js → abnfDiagram-VCTEODGH-0q7Lbmii.js} +2 -2
  4. package/dist/any-language-editor-jGaR0EAo.js +75 -0
  5. package/dist/{architectureDiagram-5GKGNRK7-C18U9A6k.js → architectureDiagram-5GKGNRK7-1PydKPmE.js} +1 -1
  6. package/dist/{arrays-CN1djC4k.js → arrays-DoQ-AILx.js} +15 -27
  7. package/dist/assets/__vite-browser-external-CBRgnYY0.js +1 -0
  8. package/dist/assets/worker-DiPNP__U.js +113 -0
  9. package/dist/{button-CvjkwdSk.js → button-B6RjDKJx.js} +227 -217
  10. package/dist/{capabilities-CQ5IjhzL.js → capabilities-CkVzWJEX.js} +2 -2
  11. package/dist/{chat-ui-w8SVynkn.js → chat-ui-B5pH_aXk.js} +1277 -1275
  12. package/dist/{check-BMKBBrdc.js → check-Z_vtI3OL.js} +1 -1
  13. package/dist/{chunk-IMKFNOWR-CrS5bzqW.js → chunk-IMKFNOWR-DEzZZ1Zc.js} +1 -1
  14. package/dist/{chunk-SHT3W25Y-StpvPvUG.js → chunk-SHT3W25Y-CuHj-hnn.js} +1 -1
  15. package/dist/{chunk-SVP7TREG-CBXjbYZC.js → chunk-SVP7TREG-BPiZK2bA.js} +1 -1
  16. package/dist/{chunk-TICWLB2K-Dp6bIb-q.js → chunk-TICWLB2K-DF6XcIjM.js} +1 -1
  17. package/dist/{chunk-YOKDWASO-DPZk8vhS.js → chunk-YOKDWASO-DKplTrBY.js} +20 -20
  18. package/dist/{classDiagram-ZZMXUADV-BFYuxV5g.js → classDiagram-ZZMXUADV-CMdR-cP4.js} +2 -2
  19. package/dist/{classDiagram-v2-VYDZK3BY-D_tjXVMl.js → classDiagram-v2-VYDZK3BY-DRvc3_7Y.js} +2 -2
  20. package/dist/code-visibility-BdFhHfIC.js +134 -0
  21. package/dist/{common-CeebhhhO.js → common-Ce1SgsX1.js} +9837 -9658
  22. package/dist/config-DbjzjwxX.js +636 -0
  23. package/dist/{copy-icon-BgUO8jsi.js → copy-icon-CG57cxwb.js} +3 -3
  24. package/dist/createReducer-DePYJ0F3.js +63 -0
  25. package/dist/{cynefinDiagram-5FMLGOSQ-DSgYrHB2.js → cynefinDiagram-5FMLGOSQ-BkBjEY9l.js} +1 -1
  26. package/dist/{dagre-GXQ25YYZ-GYlruCBf.js → dagre-GXQ25YYZ-D-HEaW4I.js} +1 -1
  27. package/dist/{data-grid-overlay-editor-vxQ4E6k1.js → data-grid-overlay-editor-Bps1p6jQ.js} +5 -5
  28. package/dist/{data-grid-types-BH_r7g7l.js → data-grid-types-0PJ-9N5n.js} +1 -1
  29. package/dist/{diagram-S7CK7UJ4-DRu5LX5_.js → diagram-S7CK7UJ4-Bn-oF-rB.js} +1 -1
  30. package/dist/{diagram-UQ7AKVKN-DD7uiejP.js → diagram-UQ7AKVKN-BpzzXWBj.js} +1 -1
  31. package/dist/{diagram-VX7I27RA-ByH9KAJJ.js → diagram-VX7I27RA-COOtvfBP.js} +1 -1
  32. package/dist/{diagram-Z3DM3KII-BsQHPRke.js → diagram-Z3DM3KII-K5cXvbrl.js} +1 -1
  33. package/dist/{dialog-Cc479ZEH.js → dialog-DsZ49mmU.js} +26 -26
  34. package/dist/{dist-Bvs24R_E.js → dist-11T5wq3_.js} +31 -30
  35. package/dist/{dist-F8Ep36rk.js → dist-17ugwGZc.js} +59 -58
  36. package/dist/{dist-BMQf5zIS.js → dist-7cRjf--y.js} +123 -122
  37. package/dist/{dist-diIx5qJW.js → dist-B8pkfkzc.js} +31 -30
  38. package/dist/{dist-CN_BeG2I.js → dist-B9UoM_wq.js} +58 -57
  39. package/dist/{dist-CLdpGQVr.js → dist-BGuMTs1i.js} +118 -117
  40. package/dist/{dist-BK4Oj99o.js → dist-BHW11fni.js} +18 -17
  41. package/dist/dist-BLY4m1Wi.js +850 -0
  42. package/dist/{dist-PXYI_yuP.js → dist-BNlcVoxs.js} +24 -23
  43. package/dist/{dist-D6d86eNJ.js → dist-BQYe5Bju.js} +47 -46
  44. package/dist/{dist-CkTTIdBe.js → dist-BX1mn8na.js} +337 -337
  45. package/dist/{dist-DiDibOYr.js → dist-Bh0PTKUW.js} +151 -150
  46. package/dist/{dist-CSJ0MDRw.js → dist-CKaXK92p.js} +56 -55
  47. package/dist/{dist-C8fAKSH1.js → dist-CLhwfhpJ.js} +53 -52
  48. package/dist/{dist-DoE4XJBC.js → dist-CYeqK4Xw.js} +9801 -10649
  49. package/dist/{dist-BLfKmR-l.js → dist-Cxlp3WH6.js} +16 -15
  50. package/dist/{dist-D-wwqlzJ.js → dist-DSJPGj42.js} +158 -157
  51. package/dist/{dist-BorMD-uX.js → dist-DU9ICsWZ.js} +75 -74
  52. package/dist/{dist-DBtSl3sf.js → dist-DWv0ALBi.js} +47 -46
  53. package/dist/{dist-OR1OnN-y.js → dist-DiBpWEsB.js} +31 -30
  54. package/dist/{dist-CrSP_H1M.js → dist-DiLFTlnl.js} +242 -242
  55. package/dist/{dist-DpBpA_n1.js → dist-Lm-D-Vr6.js} +3 -3
  56. package/dist/{dist-CSbh1PNP.js → dist-cVDV5IuI.js} +23 -22
  57. package/dist/{dist-BuaRHxOc.js → dist-fRfaOoq8.js} +44 -43
  58. package/dist/{dist-Cg7gzw-a.js → dist-gTTI-9Px.js} +78 -77
  59. package/dist/dropdown-menu-CSNdPSnS.js +6083 -0
  60. package/dist/{ebnfDiagram-PWID7BFC-CQRK5_eT.js → ebnfDiagram-PWID7BFC-BI1ZmjVm.js} +2 -2
  61. package/dist/{erDiagram-RLTQ6QDP-BKtWrDVh.js → erDiagram-RLTQ6QDP-BtWjj9xy.js} +1 -1
  62. package/dist/{error-banner-CFPHFw4h.js → error-banner-IsonnvA0.js} +84 -83
  63. package/dist/error-entries-CRPfxMqm.js +2505 -0
  64. package/dist/{esm-D2gTsXEV.js → esm-BgKjMvWw.js} +530 -529
  65. package/dist/{esm-AMFssoNp.js → esm-CHjVSexr.js} +328 -329
  66. package/dist/feedback-button-2ycmR9GG.js +374 -0
  67. package/dist/{flowDiagram-HODETNUW-1IN-ih2E.js → flowDiagram-HODETNUW-DQvZh96A.js} +2 -2
  68. package/dist/{formats-X4mMQWzX.js → formats-BK4VefeF.js} +6 -6
  69. package/dist/{ganttDiagram-EL5Y4UJY-BQT16JSc.js → ganttDiagram-EL5Y4UJY-Dh_4cBJZ.js} +2 -2
  70. package/dist/{glide-data-editor-CSYHMRDu.js → glide-data-editor-Buj2OZjL.js} +417 -415
  71. package/dist/{glide-utils-DM9zBO4W.js → glide-utils-CQddGpa-.js} +16 -16
  72. package/dist/{globals-Fpiwkv4D.js → globals-B-14fUeb.js} +3 -3
  73. package/dist/{highlighted-body-KPVGNVTW-zwjq21tf.js → highlighted-body-KPVGNVTW-3Ziwfz-V.js} +2 -2
  74. package/dist/{error-entries-Damuuclv.js → html-to-image-CgAnxFi8.js} +26911 -26769
  75. package/dist/{infoDiagram-27XIBGKW-CkB-zr4p.js → infoDiagram-27XIBGKW-BdAObnc_.js} +1 -1
  76. package/dist/{ishikawaDiagram-5VMMS53U-wlyLjBmM.js → ishikawaDiagram-5VMMS53U-DP-jE8dw.js} +1 -1
  77. package/dist/{kanban-definition-UXKFOSKX-C2usY0i-.js → kanban-definition-UXKFOSKX-BkMgPjfm.js} +1 -1
  78. package/dist/{linear-Cnaq3Tfb.js → linear-DWERh7eI.js} +121 -73
  79. package/dist/{loader-BQOfjTIJ.js → loader-BisjOLiW.js} +12 -12
  80. package/dist/main.js +9981 -8001
  81. package/dist/{mermaid-BA-Z6wGL.js → mermaid-B-OFqheA.js} +52 -52
  82. package/dist/mermaid-HWGCJPDP-Du3-HPQA.js +2 -0
  83. package/dist/{mindmap-definition-YA3MSWOX-nKOWS8RR.js → mindmap-definition-YA3MSWOX-Du7toAZX.js} +1 -1
  84. package/dist/{number-overlay-editor-BOjqsq7D.js → number-overlay-editor-ZVFcJ7_u.js} +3 -3
  85. package/dist/{dist-CN8zI-XC.js → objectWithoutPropertiesLoose-ai5NUqGa.js} +262 -240
  86. package/dist/{objects-CzUgoMIF.js → objects-DCmMvZtn.js} +1 -3
  87. package/dist/{once-BtE-wKRL.js → once-NnpX_HnX.js} +1 -1
  88. package/dist/{pegDiagram-XKGWAZYB-Dac9EIKD.js → pegDiagram-XKGWAZYB-CX_729j0.js} +2 -2
  89. package/dist/{pieDiagram-E7YTZNPT-B7S-DsW_.js → pieDiagram-E7YTZNPT-dtTFJcVI.js} +1 -1
  90. package/dist/precisionRound-DhAzeRcm.js +49 -0
  91. package/dist/{process-output-CTPTtxXB.js → process-output-Bmev5azU.js} +4 -4
  92. package/dist/{quadrantDiagram-AXDQQJYC-Ccw0xMjN.js → quadrantDiagram-AXDQQJYC-Blrm7V7_.js} +1 -1
  93. package/dist/{railroadDiagram-O6MQD6OU-Cfa5Q-hr.js → railroadDiagram-O6MQD6OU-Dsc2Cf4c.js} +2 -2
  94. package/dist/{react-vega-BED0DjiB.js → react-vega-C4T9Rb_w.js} +12284 -12270
  95. package/dist/{requirementDiagram-BXWQKSXE-d8zXCJIk.js → requirementDiagram-BXWQKSXE-D3g0c60I.js} +1 -1
  96. package/dist/{reveal-component-Brpo7CP8.js → reveal-component-BWz1KjWe.js} +426 -403
  97. package/dist/schemas-CdscWNy_.js +4747 -0
  98. package/dist/select-BSxlITBo.js +1200 -0
  99. package/dist/{sequenceDiagram-WJ2MYXX4-b6pei3lJ.js → sequenceDiagram-WJ2MYXX4-w1pWbIpk.js} +1 -1
  100. package/dist/{spec-BJzgmvVa.js → spec-Dq8RNplp.js} +41 -11
  101. package/dist/{stateDiagram-D77RDMKH-Be-xSpaZ.js → stateDiagram-D77RDMKH-BCv7kP4H.js} +2 -2
  102. package/dist/{stateDiagram-v2-MP3YSRHH-5Y-FxesJ.js → stateDiagram-v2-MP3YSRHH-D1cTOt0x.js} +2 -2
  103. package/dist/static-state-BldGd99T.js +72 -0
  104. package/dist/strings-BGW-fXVJ.js +507 -0
  105. package/dist/style.css +1 -1
  106. package/dist/{swimlanes-42K2YHIH-nRRl4NU0.js → swimlanes-42K2YHIH-DNO6jDnd.js} +1 -1
  107. package/dist/{swimlanesDiagram-VR7AAH4N-BS79510V.js → swimlanesDiagram-VR7AAH4N-CkSWsxYJ.js} +2 -2
  108. package/dist/{swiper-component-DKntyn8p.js → swiper-component-Dir1o8ml.js} +2 -2
  109. package/dist/{time-BieKwdYS.js → time-BaMbJs4z.js} +18 -18
  110. package/dist/{timeline-definition-24CTP7MA-Cfzf8WPf.js → timeline-definition-24CTP7MA-DQvqGFM9.js} +1 -1
  111. package/dist/toast-BWIPi3aF.js +491 -0
  112. package/dist/{tooltip-CtBZ5q8p.js → tooltip-C3UnvsRe.js} +329 -305
  113. package/dist/use-restore-focus-BWO0z1lo.js +1672 -0
  114. package/dist/{useAsyncData-BD534XmW.js → useAsyncData-DsZMvNXn.js} +15 -14
  115. package/dist/{useDateFormatter-DkajGwwd.js → useDateFormatter-ChB4eyim.js} +2 -2
  116. package/dist/{useDeepCompareMemoize-C72_RNsu.js → useDeepCompareMemoize-KMBBux8C.js} +1 -1
  117. package/dist/{useIframeCapabilities-DBETvvPl.js → useIframeCapabilities-cMNQ80CK.js} +1 -1
  118. package/dist/useLifecycle-BquH9ET-.js +112 -0
  119. package/dist/useTheme-B9C1JIy9.js +307 -0
  120. package/dist/utils-DXkj82sK.js +813 -0
  121. package/dist/{vega-component-DfcYgj-Y.js → vega-component-9NOEITbg.js} +170 -169
  122. package/dist/{vega-embed-container-BNHE18G9.js → vega-embed-container--LYZqguO.js} +2 -2
  123. package/dist/{vega-loader.browser-DNST6uVf.js → vega-loader.browser-B9Pz0EGP.js} +298 -507
  124. package/dist/{vennDiagram-4TSXK5OY-CeY6Z1xZ.js → vennDiagram-4TSXK5OY-BfzXp4SH.js} +1 -1
  125. package/dist/{wardleyDiagram-VM6X3IG4-Cxs9NtVi.js → wardleyDiagram-VM6X3IG4-CiqEE8eq.js} +1 -1
  126. package/dist/{xychartDiagram-S5SC5T6Z-DNWbvPK7.js → xychartDiagram-S5SC5T6Z-BTIHCVOI.js} +2 -2
  127. package/package.json +16 -20
  128. package/src/__mocks__/document.tsx +63 -0
  129. package/src/__mocks__/notebook.ts +3 -4
  130. package/src/__mocks__/partial.ts +26 -0
  131. package/src/__mocks__/requests.ts +1 -4
  132. package/src/__tests__/main.test.tsx +24 -1
  133. package/src/__tests__/module-entry.test.ts +44 -0
  134. package/src/__tests__/mount.test.ts +1 -21
  135. package/src/__tests__/{host-imports.test.ts → replica-imports.test.ts} +12 -11
  136. package/src/components/ai/__tests__/ai-model-dropdown.test.tsx +63 -0
  137. package/src/components/ai/ai-model-dropdown.tsx +11 -6
  138. package/src/components/app-config/ai-config.tsx +7 -2
  139. package/src/components/app-config/app-config-form.tsx +5 -9
  140. package/src/components/app-config/user-config-form.tsx +35 -56
  141. package/src/components/chat/__tests__/message-queue.test.tsx +17 -0
  142. package/src/components/chat/__tests__/notebook-access-selector.test.tsx +64 -0
  143. package/src/components/chat/acp/__tests__/session-tabs.test.tsx +43 -0
  144. package/src/components/chat/acp/__tests__/state.test.ts +2 -2
  145. package/src/components/chat/acp/blocks.tsx +3 -2
  146. package/src/components/chat/acp/session-tabs.tsx +8 -3
  147. package/src/components/chat/chat-components.tsx +2 -0
  148. package/src/components/chat/chat-panel.tsx +20 -101
  149. package/src/components/chat/chat-utils.ts +4 -8
  150. package/src/components/chat/notebook-access-selector.stories.tsx +22 -0
  151. package/src/components/chat/notebook-access-selector.tsx +100 -0
  152. package/src/components/data-table/TableBottomBar.tsx +4 -1
  153. package/src/components/data-table/TableTopBar.tsx +2 -0
  154. package/src/components/data-table/__tests__/chart-spec-model.test.ts +195 -195
  155. package/src/components/data-table/__tests__/column-explorer.test.tsx +27 -1
  156. package/src/components/data-table/__tests__/columns.test.tsx +105 -0
  157. package/src/components/data-table/__tests__/context-menu-interaction.test.tsx +130 -0
  158. package/src/components/data-table/__tests__/data-table.test.tsx +1 -0
  159. package/src/components/data-table/__tests__/date-popover.test.tsx +72 -0
  160. package/src/components/data-table/__tests__/export-actions.test.tsx +105 -0
  161. package/src/components/data-table/__tests__/keyboard-selection.test.tsx +188 -0
  162. package/src/components/data-table/__tests__/pagination.test.tsx +28 -1
  163. package/src/components/data-table/__tests__/search-highlight.test.tsx +109 -0
  164. package/src/components/data-table/__tests__/url-detector.test.tsx +74 -0
  165. package/src/components/data-table/cell-selection/feature.ts +2 -2
  166. package/src/components/data-table/cell-selection/types.ts +2 -2
  167. package/src/components/data-table/charts/__tests__/chart-panel.test.tsx +74 -1
  168. package/src/components/data-table/charts/__tests__/spec-snapshot.test.ts +20 -20
  169. package/src/components/data-table/charts/__tests__/spec.test.ts +78 -52
  170. package/src/components/data-table/charts/__tests__/storage.test.ts +4 -1
  171. package/src/components/data-table/charts/chart-spec/spec.ts +68 -43
  172. package/src/components/data-table/charts/charts.tsx +40 -30
  173. package/src/components/data-table/charts/storage.ts +16 -5
  174. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +1 -1
  175. package/src/components/data-table/column-summary/chart-spec-model.tsx +23 -16
  176. package/src/components/data-table/column-summary/column-summary.tsx +2 -4
  177. package/src/components/data-table/column-visibility-dropdown.tsx +8 -13
  178. package/src/components/data-table/columns.tsx +45 -46
  179. package/src/components/data-table/context-menu.tsx +36 -20
  180. package/src/components/data-table/data-table.tsx +17 -1
  181. package/src/components/data-table/date-popover.tsx +6 -4
  182. package/src/components/data-table/export-actions.tsx +76 -48
  183. package/src/components/data-table/pagination.tsx +44 -33
  184. package/src/components/data-table/range-focus/atoms.ts +4 -6
  185. package/src/components/data-table/range-focus/use-cell-range-selection.ts +65 -38
  186. package/src/components/data-table/range-focus/use-scroll-into-view.ts +21 -2
  187. package/src/components/data-table/renderers.tsx +16 -7
  188. package/src/components/data-table/row-viewer-panel/__tests__/row-viewer.test.tsx +24 -1
  189. package/src/components/data-table/row-viewer-panel/row-viewer.tsx +4 -4
  190. package/src/components/data-table/search-highlight.tsx +79 -0
  191. package/src/components/data-table/types.ts +1 -0
  192. package/src/components/data-table/url-detector.tsx +49 -9
  193. package/src/components/datasources/__tests__/column-actions.test.tsx +97 -0
  194. package/src/components/datasources/__tests__/column-preview.test.tsx +96 -5
  195. package/src/components/datasources/__tests__/datasources-interactions.test.tsx +181 -0
  196. package/src/components/datasources/__tests__/table-list.test.tsx +118 -0
  197. package/src/components/datasources/__tests__/utils.test.ts +57 -6
  198. package/src/components/datasources/column-preview.tsx +17 -12
  199. package/src/components/datasources/datasources.tsx +56 -43
  200. package/src/components/datasources/utils.ts +32 -23
  201. package/src/components/debugger/debugger-code.tsx +5 -0
  202. package/src/components/dependency-graph/custom-node.tsx +1 -1
  203. package/src/components/dependency-graph/dependency-graph-tree.tsx +8 -8
  204. package/src/components/dependency-graph/elements.ts +24 -21
  205. package/src/components/dependency-graph/minimap-content.tsx +13 -19
  206. package/src/components/dependency-graph/panels.tsx +4 -2
  207. package/src/components/dependency-graph/utils/__tests__/layout.test.ts +18 -11
  208. package/src/components/editor/SortableCell.tsx +1 -3
  209. package/src/components/editor/__tests__/Output.test.tsx +50 -32
  210. package/src/{core/attachments/__tests__/toast.test.tsx → components/editor/__tests__/agent-toast.test.tsx} +1 -1
  211. package/src/components/editor/__tests__/data-attributes.test.tsx +28 -14
  212. package/src/components/editor/__tests__/dynamic-favicon.test.tsx +111 -18
  213. package/src/components/editor/__tests__/output-persistence.test.tsx +6 -2
  214. package/src/components/editor/__tests__/package-alert.test.tsx +22 -1
  215. package/src/components/editor/actions/__tests__/name-cell-input.test.tsx +69 -0
  216. package/src/components/editor/actions/__tests__/pair-with-agent-modal.test.tsx +34 -8
  217. package/src/components/editor/actions/__tests__/pair-with-agent.test.tsx +2 -6
  218. package/src/components/editor/actions/__tests__/useCellActionButton.test.tsx +113 -0
  219. package/src/components/editor/actions/name-cell-input.tsx +4 -3
  220. package/src/components/editor/actions/pair-with-agent-commands.ts +2 -2
  221. package/src/components/editor/actions/pair-with-agent-modal.tsx +19 -16
  222. package/src/components/editor/actions/useCellActionButton.tsx +36 -31
  223. package/src/components/editor/actions/useConfigActions.tsx +3 -4
  224. package/src/components/editor/actions/useNotebookActions.tsx +19 -23
  225. package/src/components/editor/actions/useRestartKernel.tsx +1 -1
  226. package/src/components/editor/actions/useSetCodeVisibility.ts +11 -12
  227. package/src/components/editor/actions/useSetOutputsExpanded.ts +14 -19
  228. package/src/components/editor/ai/add-cell-with-ai.tsx +3 -3
  229. package/src/components/editor/ai/ai-completion-editor.tsx +1 -0
  230. package/src/components/editor/alerts/__tests__/connection-notice.test.tsx +1 -1
  231. package/src/components/editor/alerts/connection-notice.tsx +1 -1
  232. package/src/components/editor/alerts/startup-logs-alert.tsx +1 -0
  233. package/src/components/editor/alerts/stdin-blocking-alert.tsx +1 -1
  234. package/src/components/editor/app-container.tsx +1 -1
  235. package/src/components/editor/boundary/__tests__/ErrorBoundary.test.tsx +1 -1
  236. package/src/components/editor/cell/CreateCellButton.tsx +15 -21
  237. package/src/components/editor/cell/DeleteButton.tsx +3 -2
  238. package/src/components/editor/cell/RunButton.tsx +2 -2
  239. package/src/components/editor/cell/StagedAICell.tsx +10 -2
  240. package/src/components/editor/cell/StopButton.tsx +2 -2
  241. package/src/components/editor/cell/__tests__/StagedAICell.test.tsx +4 -2
  242. package/src/components/editor/cell/__tests__/useShouldShowInterrupt.test.ts +39 -0
  243. package/src/components/editor/cell/cell-actions.tsx +12 -1
  244. package/src/components/editor/cell/code/__tests__/language-toggle.test.tsx +54 -0
  245. package/src/components/editor/cell/code/cell-editor.tsx +46 -165
  246. package/src/components/editor/cell/code/language-toggle.tsx +8 -7
  247. package/src/components/editor/cell/collapse.tsx +11 -4
  248. package/src/components/editor/cell/useAddCell.ts +4 -8
  249. package/src/components/editor/cell/useDeleteCell.tsx +10 -36
  250. package/src/components/editor/cell/useRunCells.ts +2 -5
  251. package/src/components/editor/cell/useShouldShowInterrupt.ts +2 -12
  252. package/src/components/editor/cell/useSplitCell.tsx +10 -6
  253. package/src/components/editor/chrome/components/__tests__/feedback-button.test.tsx +1 -1
  254. package/src/components/editor/chrome/components/feedback-button.tsx +2 -8
  255. package/src/components/editor/chrome/panels/__tests__/packages-panel.test.tsx +31 -2
  256. package/src/components/editor/chrome/panels/__tests__/runtime-details.test.tsx +1 -1
  257. package/src/components/editor/chrome/panels/__tests__/sandbox-recovery.test.tsx +1 -1
  258. package/src/components/editor/chrome/panels/cache-panel.tsx +1 -0
  259. package/src/components/editor/chrome/panels/dependency-graph-panel.tsx +1 -1
  260. package/src/components/editor/chrome/panels/logs-panel.tsx +2 -1
  261. package/src/components/editor/chrome/panels/outline/__tests__/outline-keyboard.test.tsx +84 -0
  262. package/src/components/editor/chrome/panels/outline/floating-outline.tsx +39 -14
  263. package/src/components/editor/chrome/panels/outline/useActiveOutline.tsx +3 -2
  264. package/src/components/editor/chrome/panels/packages-panel.tsx +4 -7
  265. package/src/components/editor/chrome/panels/secrets-panel.tsx +1 -0
  266. package/src/components/editor/chrome/panels/session-panel.tsx +1 -1
  267. package/src/components/editor/chrome/panels/snippets-panel.tsx +10 -12
  268. package/src/components/editor/chrome/panels/variable-panel.tsx +1 -5
  269. package/src/components/editor/chrome/wrapper/__tests__/attachment-status.test.tsx +6 -9
  270. package/src/components/editor/chrome/wrapper/__tests__/document-sync-status.test.tsx +92 -0
  271. package/src/components/editor/chrome/wrapper/__tests__/pending-ai-cells.test.tsx +62 -3
  272. package/src/components/editor/chrome/wrapper/footer-items/attachment-status.tsx +4 -4
  273. package/src/components/editor/chrome/wrapper/footer-items/backend-status.tsx +1 -1
  274. package/src/components/editor/chrome/wrapper/footer-items/document-sync-status.tsx +54 -0
  275. package/src/components/editor/chrome/wrapper/footer-items/lsp-status.tsx +1 -1
  276. package/src/components/editor/chrome/wrapper/footer-items/machine-stats.tsx +1 -1
  277. package/src/components/editor/chrome/wrapper/footer-items/runtime-settings.tsx +1 -7
  278. package/src/components/editor/chrome/wrapper/footer.tsx +2 -2
  279. package/src/components/editor/chrome/wrapper/minimap-state.ts +1 -1
  280. package/src/components/editor/chrome/wrapper/pending-ai-cells.tsx +12 -2
  281. package/src/components/editor/chrome/wrapper/storage.ts +1 -1
  282. package/src/components/editor/columns/__tests__/cell-column.test.tsx +1 -1
  283. package/src/components/editor/columns/cell-column.tsx +1 -1
  284. package/src/components/editor/columns/sortable-column.tsx +2 -2
  285. package/src/components/editor/connections/components.tsx +5 -10
  286. package/src/components/editor/controls/Controls.tsx +4 -4
  287. package/src/components/editor/controls/__tests__/command-palette.test.tsx +53 -0
  288. package/src/components/editor/controls/__tests__/keyboard-shortcuts.test.tsx +61 -0
  289. package/src/components/editor/controls/__tests__/notebook-menu-dropdown.test.tsx +10 -4
  290. package/src/components/editor/controls/command-palette.tsx +22 -10
  291. package/src/components/editor/controls/keyboard-shortcuts.tsx +14 -5
  292. package/src/components/editor/documentation.css +34 -11
  293. package/src/components/editor/dynamic-favicon.tsx +21 -40
  294. package/src/components/editor/errors/__tests__/send-error-report-button.test.tsx +25 -20
  295. package/src/components/editor/errors/auto-fix.tsx +4 -8
  296. package/src/components/editor/errors/send-error-report-button.tsx +3 -6
  297. package/src/components/editor/file-tree/__tests__/file-explorer-interactions.test.tsx +6 -0
  298. package/src/components/editor/file-tree/__tests__/file-explorer-navigation.test.tsx +47 -0
  299. package/src/components/editor/file-tree/__tests__/use-file-search.test.tsx +91 -0
  300. package/src/components/editor/file-tree/file-explorer.tsx +48 -15
  301. package/src/components/editor/file-tree/file-name-input.tsx +1 -0
  302. package/src/components/editor/file-tree/file-viewer.tsx +4 -2
  303. package/src/components/editor/file-tree/use-file-search.ts +35 -21
  304. package/src/components/editor/header/__tests__/filename-form.test.tsx +1 -4
  305. package/src/components/editor/header/__tests__/status.test.tsx +5 -3
  306. package/src/components/editor/header/app-header.tsx +1 -1
  307. package/src/components/editor/header/filename-form.tsx +1 -1
  308. package/src/components/editor/header/status.tsx +40 -20
  309. package/src/components/editor/links/__tests__/cell-link.test.tsx +148 -0
  310. package/src/components/editor/links/cell-link-list.tsx +1 -1
  311. package/src/components/editor/links/cell-link.tsx +17 -7
  312. package/src/components/editor/navigation/__tests__/clipboard.test.ts +60 -38
  313. package/src/components/editor/navigation/__tests__/navigation.test.ts +108 -85
  314. package/src/components/editor/navigation/__tests__/selection.test.ts +43 -21
  315. package/src/components/editor/navigation/clipboard.ts +17 -14
  316. package/src/components/editor/navigation/focus-utils.ts +23 -4
  317. package/src/components/editor/navigation/multi-cell-action-toolbar.tsx +17 -33
  318. package/src/components/editor/navigation/navigation.ts +71 -70
  319. package/src/components/editor/navigation/selection.ts +30 -29
  320. package/src/components/editor/notebook-banner.tsx +1 -0
  321. package/src/components/editor/notebook-cell.tsx +29 -32
  322. package/src/components/editor/output/MarimoErrorOutput.tsx +2 -1
  323. package/src/components/editor/output/MarimoTracebackOutput.tsx +19 -17
  324. package/src/components/editor/output/Outputs.css +8 -0
  325. package/src/components/editor/output/__tests__/traceback.test.tsx +27 -1
  326. package/src/components/editor/output/ansi-reduce.ts +33 -20
  327. package/src/components/editor/output/console/ConsoleOutput.tsx +19 -25
  328. package/src/components/editor/output/console/__tests__/ConsoleOutput.test.tsx +125 -69
  329. package/src/components/editor/package-alert.tsx +14 -7
  330. package/src/components/editor/renderers/cell-array.tsx +22 -33
  331. package/src/components/editor/renderers/grid-layout/grid-layout.tsx +12 -6
  332. package/src/components/editor/renderers/slides-layout/__tests__/plugin.test.ts +0 -1
  333. package/src/components/editor/renderers/slides-layout/slides-layout.tsx +1 -1
  334. package/src/components/editor/renderers/vertical-layout/__tests__/useFocusFirstEditor.test.ts +4 -4
  335. package/src/components/editor/renderers/vertical-layout/sidebar/toggle.tsx +7 -1
  336. package/src/components/editor/renderers/vertical-layout/useFocusFirstEditor.ts +1 -1
  337. package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +1 -1
  338. package/src/components/editor/stdin-blocking-alert.tsx +1 -1
  339. package/src/components/home/components.tsx +17 -31
  340. package/src/components/icons/__tests__/large-spinner.test.tsx +39 -0
  341. package/src/components/icons/large-spinner.tsx +3 -14
  342. package/src/components/icons/spinner.tsx +1 -1
  343. package/src/components/markdown/markdown-renderer.tsx +4 -8
  344. package/src/components/mcp/mcp-status-indicator.tsx +1 -1
  345. package/src/components/pages/__tests__/home-page.test.tsx +116 -0
  346. package/src/components/pages/edit-page.tsx +19 -17
  347. package/src/components/pages/home-page.tsx +164 -91
  348. package/src/components/scratchpad/scratchpad.test.tsx +89 -0
  349. package/src/components/scratchpad/scratchpad.tsx +43 -32
  350. package/src/components/scratchpad/state.ts +7 -0
  351. package/src/components/slides/__tests__/minimap-actions.test.tsx +22 -29
  352. package/src/components/slides/__tests__/minimap.test.ts +38 -19
  353. package/src/components/slides/__tests__/slide-scroll-hint.test.tsx +37 -0
  354. package/src/components/slides/minimap.tsx +17 -12
  355. package/src/components/slides/reveal-component.tsx +58 -26
  356. package/src/components/slides/reveal-slides.css +5 -4
  357. package/src/components/slides/slide-cell-view.tsx +4 -5
  358. package/src/components/slides/slide-form.tsx +1 -0
  359. package/src/components/slides/slide-scroll-hint.tsx +3 -1
  360. package/src/components/sort/SortableCellsProvider.tsx +8 -25
  361. package/src/components/tracing/tracing-keyboard.test.tsx +85 -0
  362. package/src/components/tracing/tracing.tsx +46 -42
  363. package/src/components/ui/__tests__/draggable-popover.test.tsx +24 -0
  364. package/src/components/ui/__tests__/range-slider.test.tsx +165 -0
  365. package/src/components/ui/alert-dialog.tsx +1 -1
  366. package/src/components/ui/draggable-popover.tsx +24 -2
  367. package/src/components/ui/range-slider.tsx +22 -9
  368. package/src/core/MarimoApp.tsx +1 -1
  369. package/src/core/ai/__tests__/staged-cells.test.ts +32 -33
  370. package/src/core/ai/context/providers/__tests__/cell-output.test.ts +8 -12
  371. package/src/core/ai/context/providers/cell-output.ts +2 -2
  372. package/src/core/ai/context/providers/datasource.ts +6 -2
  373. package/src/core/ai/staged-cells.ts +18 -19
  374. package/src/core/ai/tools/__tests__/edit-notebook-tool.test.ts +40 -88
  375. package/src/core/ai/tools/__tests__/registry.test.ts +17 -0
  376. package/src/core/ai/tools/base.ts +18 -15
  377. package/src/core/ai/tools/edit-notebook-tool.ts +86 -80
  378. package/src/core/ai/tools/registry.ts +13 -10
  379. package/src/core/ai/tools/sample-tool.ts +6 -7
  380. package/src/core/cells/__tests__/__snapshots__/cells.test.ts.snap +4 -37
  381. package/src/core/cells/__tests__/actions.test.ts +624 -35
  382. package/src/core/cells/__tests__/add-missing-import.test.ts +7 -8
  383. package/src/core/cells/__tests__/arrange.test.ts +432 -0
  384. package/src/core/cells/__tests__/cell.test.ts +39 -0
  385. package/src/core/cells/__tests__/cells.test.ts +251 -2540
  386. package/src/core/cells/__tests__/collapseConsoleOutputs.test.ts +54 -0
  387. package/src/core/cells/__tests__/document.test.ts +164 -0
  388. package/src/core/cells/__tests__/editor.test.ts +57 -0
  389. package/src/core/cells/__tests__/flush-document.test.ts +40 -0
  390. package/src/core/cells/__tests__/harness.ts +106 -0
  391. package/src/core/cells/__tests__/layout.test.ts +177 -0
  392. package/src/core/cells/__tests__/notebook-outline.test.ts +122 -0
  393. package/src/core/cells/__tests__/outputs.test.tsx +71 -53
  394. package/src/core/cells/__tests__/session.test.ts +445 -211
  395. package/src/core/cells/__tests__/utils.test.ts +9 -108
  396. package/src/core/cells/actions.ts +675 -6
  397. package/src/core/cells/add-missing-import.ts +47 -43
  398. package/src/core/cells/arrange.ts +529 -0
  399. package/src/core/cells/cell.ts +14 -3
  400. package/src/core/cells/cells.ts +126 -1363
  401. package/src/core/cells/columns.ts +38 -0
  402. package/src/core/cells/document.ts +178 -0
  403. package/src/core/cells/edit.ts +30 -0
  404. package/src/core/cells/editor.ts +82 -0
  405. package/src/core/cells/layout.ts +221 -0
  406. package/src/core/cells/outputs.ts +12 -28
  407. package/src/core/cells/pending-delete-service.ts +3 -7
  408. package/src/core/cells/session.ts +76 -53
  409. package/src/core/cells/types.ts +22 -6
  410. package/src/core/cells/utils.ts +10 -8
  411. package/src/core/codemirror/__tests__/format.test.ts +0 -34
  412. package/src/core/codemirror/__tests__/setup.test.ts +29 -29
  413. package/src/core/codemirror/ai/__tests__/resources.test.ts +117 -0
  414. package/src/core/codemirror/ai/resources.ts +1 -1
  415. package/src/core/codemirror/cells/__tests__/extensions.test.ts +2 -6
  416. package/src/core/codemirror/cells/extensions.ts +30 -28
  417. package/src/core/codemirror/cells/state.ts +1 -6
  418. package/src/core/codemirror/copilot/__tests__/getCodes.test.ts +6 -7
  419. package/src/core/codemirror/copilot/getCodes.ts +2 -2
  420. package/src/core/codemirror/format.ts +6 -23
  421. package/src/core/codemirror/keymaps/vim.ts +4 -8
  422. package/src/core/codemirror/language/__tests__/sql.test.ts +22 -20
  423. package/src/core/codemirror/language/__tests__/utils.test.ts +187 -15
  424. package/src/core/codemirror/language/cell-code.ts +114 -0
  425. package/src/core/codemirror/language/extension.ts +52 -35
  426. package/src/core/codemirror/language/languages/markdown.ts +8 -6
  427. package/src/core/codemirror/language/languages/python.ts +16 -10
  428. package/src/core/codemirror/language/languages/sql/sql.ts +16 -24
  429. package/src/core/codemirror/language/panel/panel.tsx +1 -0
  430. package/src/core/codemirror/language/types.ts +7 -7
  431. package/src/core/codemirror/language/utils.ts +9 -39
  432. package/src/core/codemirror/lsp/__tests__/notebook-lsp.test.ts +1 -2
  433. package/src/core/codemirror/lsp/notebook-lsp.ts +6 -5
  434. package/src/core/codemirror/lsp/utils.ts +1 -1
  435. package/src/core/codemirror/misc/__tests__/paste.test.ts +3 -1
  436. package/src/core/codemirror/misc/paste.ts +1 -1
  437. package/src/core/codemirror/readonly/__tests__/extension.test.ts +1 -1
  438. package/src/core/codemirror/readonly/extension.ts +2 -2
  439. package/src/core/codemirror/utils.ts +1 -0
  440. package/src/core/config/__tests__/app-config.test.ts +64 -0
  441. package/src/core/config/__tests__/config-schema.test.ts +13 -6
  442. package/src/core/config/config-schema.ts +13 -4
  443. package/src/core/config/config.ts +26 -12
  444. package/src/core/config/feature-flag.tsx +0 -2
  445. package/src/core/datasets/__tests__/data-source-discovery.test.ts +5 -5
  446. package/src/core/datasets/data-source-discovery.ts +4 -6
  447. package/src/core/documentation/doc-lookup.ts +1 -1
  448. package/src/core/edit-app.tsx +21 -28
  449. package/src/core/errors/error-entries.ts +4 -1
  450. package/src/core/export/hooks.ts +1 -1
  451. package/src/core/export/layout.ts +2 -2
  452. package/src/core/hotkeys/actions.ts +2 -4
  453. package/src/core/islands/__tests__/bootstrap.test.ts +69 -17
  454. package/src/core/islands/__tests__/bridge.test.ts +72 -25
  455. package/src/core/islands/bootstrap.ts +46 -53
  456. package/src/core/islands/bridge.ts +75 -24
  457. package/src/core/islands/components/__tests__/IslandControls.test.tsx +7 -5
  458. package/src/core/islands/components/web-components.tsx +1 -1
  459. package/src/core/islands/worker/__tests__/controller.test.ts +62 -4
  460. package/src/core/islands/worker/controller.ts +4 -10
  461. package/src/core/islands/worker/worker.tsx +33 -33
  462. package/src/core/kernel/__tests__/RuntimeState.test.ts +1 -1
  463. package/src/core/kernel/__tests__/handlers.test.ts +7 -153
  464. package/src/core/kernel/handlers.ts +19 -72
  465. package/src/core/meta/__tests__/code-visibility.test.tsx +78 -70
  466. package/src/core/meta/code-visibility.ts +18 -9
  467. package/src/core/network/__tests__/connection.test.ts +1 -1
  468. package/src/core/network/__tests__/requests-lazy.test.ts +1 -3
  469. package/src/core/network/connection-notice.ts +1 -1
  470. package/src/core/network/connection.ts +1 -1
  471. package/src/core/network/requests-lazy.ts +2 -5
  472. package/src/core/network/requests-network.ts +5 -31
  473. package/src/core/network/requests-static.ts +1 -4
  474. package/src/core/network/requests-toasting.tsx +1 -4
  475. package/src/core/network/types.ts +6 -14
  476. package/src/core/network/useConnectionNotice.ts +8 -2
  477. package/src/core/notebook/__tests__/operations.test.ts +51 -0
  478. package/src/core/notebook/attachments.ts +38 -0
  479. package/src/core/notebook/document/__tests__/codemirror.test.ts +758 -0
  480. package/src/core/notebook/document/__tests__/draft.test.ts +363 -0
  481. package/src/core/notebook/document/__tests__/fixtures.ts +92 -0
  482. package/src/core/notebook/document/__tests__/hooks.test.tsx +391 -0
  483. package/src/core/notebook/document/__tests__/lifecycle-scenarios.test.ts +61 -0
  484. package/src/core/notebook/document/__tests__/model.test.ts +247 -0
  485. package/src/core/notebook/document/__tests__/protocol-fixtures.ts +38 -0
  486. package/src/core/notebook/document/__tests__/recovery-scenarios.test.ts +230 -0
  487. package/src/core/notebook/document/__tests__/scenario-fixture.ts +43 -0
  488. package/src/core/notebook/document/__tests__/scenarios.test.ts +205 -0
  489. package/src/core/notebook/document/__tests__/state.test.ts +459 -0
  490. package/src/core/notebook/document/__tests__/submission.test.ts +203 -0
  491. package/src/core/notebook/document/__tests__/test-host.test.ts +92 -0
  492. package/src/core/notebook/document/__tests__/test-host.ts +247 -0
  493. package/src/core/notebook/document/__tests__/test-notebook.ts +149 -0
  494. package/src/core/notebook/document/__tests__/user.ts +61 -0
  495. package/src/core/notebook/document/codemirror.ts +216 -0
  496. package/src/core/notebook/document/draft.ts +502 -0
  497. package/src/core/notebook/document/hooks.tsx +118 -0
  498. package/src/core/notebook/document/index.ts +24 -0
  499. package/src/core/notebook/document/model.ts +102 -0
  500. package/src/core/notebook/document/select.ts +41 -0
  501. package/src/core/notebook/document/state.ts +378 -0
  502. package/src/core/notebook/document/sync.ts +369 -0
  503. package/src/core/notebook/index.ts +19 -0
  504. package/src/core/notebook/operations.ts +30 -0
  505. package/src/core/notebook/replica/AGENTS.md +11 -0
  506. package/src/core/{host → notebook/replica}/__tests__/attachments.test.ts +9 -10
  507. package/src/core/{host → notebook/replica}/__tests__/document.test.ts +18 -16
  508. package/src/core/notebook/replica/__tests__/fixtures.ts +79 -0
  509. package/src/core/notebook/replica/__tests__/replica.test.ts +550 -0
  510. package/src/core/notebook/replica/backend.ts +19 -0
  511. package/src/core/notebook/replica/connection.ts +42 -0
  512. package/src/core/notebook/replica/index.ts +13 -0
  513. package/src/core/notebook/replica/replica.ts +286 -0
  514. package/src/core/{host → notebook/replica}/resources/attachments.ts +6 -3
  515. package/src/core/{host → notebook/replica}/resources/document.ts +4 -4
  516. package/src/core/packages/__tests__/useSandboxController.test.tsx +1 -1
  517. package/src/core/packages/useSandboxController.ts +1 -1
  518. package/src/core/run-app.tsx +48 -51
  519. package/src/core/runtime/__tests__/adapter.test.ts +1 -1
  520. package/src/core/runtime/__tests__/createWsUrl.test.ts +77 -7
  521. package/src/core/runtime/__tests__/runtime.test.ts +32 -74
  522. package/src/core/runtime/adapter.ts +1 -1
  523. package/src/core/runtime/config.ts +2 -2
  524. package/src/core/runtime/runtime.ts +33 -46
  525. package/src/core/runtime/types.ts +0 -2
  526. package/src/core/saving/__tests__/document.test.tsx +123 -0
  527. package/src/core/saving/__tests__/state.test.ts +111 -0
  528. package/src/core/saving/__tests__/useAutoSave.test.tsx +67 -0
  529. package/src/core/saving/document.ts +33 -0
  530. package/src/core/saving/filename.ts +1 -1
  531. package/src/core/saving/save-component.tsx +39 -60
  532. package/src/core/saving/state.ts +38 -39
  533. package/src/core/saving/useAutoSave.ts +17 -53
  534. package/src/core/session/__tests__/backend.test.ts +236 -0
  535. package/src/core/session/__tests__/useNotebookReplica.hook.test.tsx +184 -0
  536. package/src/core/{websocket → session}/__tests__/useNotebookSession.hook.test.tsx +213 -262
  537. package/src/core/session/active-notebook.ts +28 -0
  538. package/src/core/session/backend.ts +123 -0
  539. package/src/core/session/embedded.ts +7 -0
  540. package/src/core/{websocket → session}/types.ts +2 -2
  541. package/src/core/session/useNotebookReplica.ts +74 -0
  542. package/src/core/{websocket → session}/useNotebookSession.tsx +77 -64
  543. package/src/core/state/__tests__/jotai.test.tsx +108 -0
  544. package/src/core/state/jotai.ts +1 -1
  545. package/src/core/static/__tests__/files.test.ts +38 -10
  546. package/src/core/static/files.ts +2 -0
  547. package/src/core/{websocket → transports}/__tests__/connection-state.test.ts +1 -13
  548. package/src/core/transports/__tests__/server.test.ts +408 -0
  549. package/src/core/transports/__tests__/static.test.ts +306 -0
  550. package/src/core/transports/__tests__/wasm.test.ts +166 -0
  551. package/src/core/{websocket → transports}/connection-state.ts +9 -16
  552. package/src/core/transports/server.ts +152 -0
  553. package/src/core/transports/static.ts +166 -0
  554. package/src/core/transports/wasm.ts +97 -0
  555. package/src/core/wasm/__tests__/bridge.test.ts +105 -65
  556. package/src/core/wasm/__tests__/worker.test.ts +187 -0
  557. package/src/core/wasm/bridge.ts +60 -71
  558. package/src/core/wasm/rpc.ts +15 -3
  559. package/src/core/wasm/store.ts +3 -3
  560. package/src/core/wasm/worker/bootstrap.ts +55 -51
  561. package/src/core/wasm/worker/getMarimoWheel.ts +1 -1
  562. package/src/core/wasm/worker/save-worker.ts +9 -10
  563. package/src/core/wasm/worker/types.ts +29 -18
  564. package/src/core/wasm/worker/worker.ts +89 -45
  565. package/src/css/app/codemirror.css +1 -1
  566. package/src/css/globals.css +66 -22
  567. package/src/hooks/__tests__/useAsyncData.test.tsx +148 -0
  568. package/src/hooks/__tests__/useDebounce.test.tsx +51 -0
  569. package/src/hooks/__tests__/useDeepCompareMemoize.test.tsx +39 -0
  570. package/src/hooks/__tests__/useDelayElapsed.test.tsx +28 -0
  571. package/src/hooks/__tests__/useInternalStateWithSync.test.tsx +20 -0
  572. package/src/hooks/__tests__/useScript.test.tsx +77 -0
  573. package/src/hooks/__tests__/useStateForKey.test.tsx +257 -0
  574. package/src/hooks/useAsyncData.ts +3 -3
  575. package/src/hooks/useDataSourceDiscovery.ts +6 -4
  576. package/src/hooks/useDebounce.ts +6 -10
  577. package/src/hooks/useDeepCompareMemoize.ts +1 -1
  578. package/src/hooks/useDelayElapsed.ts +14 -10
  579. package/src/hooks/useElapsedTime.ts +3 -3
  580. package/src/hooks/useEventListener.ts +1 -2
  581. package/src/hooks/useInputHistory.ts +4 -7
  582. package/src/hooks/useInternalStateWithSync.ts +6 -6
  583. package/src/hooks/useResizeObserver.ts +4 -7
  584. package/src/hooks/useScript.ts +67 -70
  585. package/src/hooks/useStateForKey.ts +93 -0
  586. package/src/mount.tsx +20 -15
  587. package/src/plugins/__tests__/plugin-object-schemas.test.ts +104 -0
  588. package/src/plugins/core/registerReactComponent.tsx +1 -1
  589. package/src/plugins/impl/CodeEditorPlugin.tsx +1 -1
  590. package/src/plugins/impl/DataEditorPlugin.tsx +1 -1
  591. package/src/plugins/impl/DataTablePlugin.tsx +69 -37
  592. package/src/plugins/impl/DropdownPlugin.tsx +2 -6
  593. package/src/plugins/impl/FileBrowserPlugin.tsx +4 -16
  594. package/src/plugins/impl/FormPlugin.tsx +1 -1
  595. package/src/plugins/impl/RangeSliderPlugin.tsx +16 -2
  596. package/src/plugins/impl/RefreshPlugin.tsx +1 -0
  597. package/src/plugins/impl/SliderPlugin.tsx +6 -8
  598. package/src/plugins/impl/__tests__/DataTablePlugin.test.tsx +387 -1
  599. package/src/plugins/impl/__tests__/FileBrowserPlugin.test.tsx +45 -0
  600. package/src/plugins/impl/__tests__/RangeSliderPlugin.test.tsx +109 -0
  601. package/src/plugins/impl/__tests__/SliderPlugin.test.tsx +24 -3
  602. package/src/plugins/impl/anywidget/__tests__/registry.test.ts +153 -0
  603. package/src/plugins/impl/anywidget/__tests__/widget-binding.test.ts +241 -2
  604. package/src/plugins/impl/anywidget/model.ts +3 -1
  605. package/src/plugins/impl/anywidget/registry.ts +18 -14
  606. package/src/plugins/impl/anywidget/runtime.ts +21 -9
  607. package/src/plugins/impl/anywidget/widget-binding.ts +160 -82
  608. package/src/plugins/impl/chat/__tests__/chat-prompts.test.tsx +93 -0
  609. package/src/plugins/impl/chat/chat-ui.tsx +14 -11
  610. package/src/plugins/impl/code/any-language-editor.tsx +2 -2
  611. package/src/plugins/impl/data-editor/glide-data-editor.tsx +8 -5
  612. package/src/plugins/impl/data-editor/glide-utils.ts +3 -1
  613. package/src/plugins/impl/data-explorer/ConnectedDataExplorerComponent.tsx +1 -1
  614. package/src/plugins/impl/data-explorer/components/column-summary.tsx +4 -2
  615. package/src/plugins/impl/data-explorer/state/reducer.ts +1 -1
  616. package/src/plugins/impl/data-frames/DataFramePlugin.tsx +1 -2
  617. package/src/plugins/impl/data-frames/__tests__/sidebar.test.tsx +160 -0
  618. package/src/plugins/impl/data-frames/forms/__tests__/__snapshots__/form.test.tsx.snap +66 -66
  619. package/src/plugins/impl/data-frames/panel.tsx +43 -16
  620. package/src/plugins/impl/mpl-interactive/MplInteractivePlugin.tsx +5 -3
  621. package/src/plugins/impl/panel/PanelPlugin.tsx +16 -17
  622. package/src/plugins/impl/panel/__tests__/utils.test.ts +39 -1
  623. package/src/plugins/impl/panel/utils.ts +17 -0
  624. package/src/plugins/impl/plotly/PlotlyPlugin.tsx +2 -5
  625. package/src/plugins/impl/plotly/selection.ts +25 -19
  626. package/src/plugins/impl/vega/VegaPlugin.tsx +2 -3
  627. package/src/plugins/impl/vega/make-selectable.ts +4 -7
  628. package/src/plugins/layout/RoutesPlugin.tsx +1 -1
  629. package/src/stories/__tests__/editor-story.test.tsx +33 -0
  630. package/src/stories/button.stories.tsx +1 -0
  631. package/src/stories/cell.stories.tsx +2 -5
  632. package/src/stories/data-table.stories.tsx +31 -0
  633. package/src/stories/editor.stories.tsx +24 -17
  634. package/src/stories/form-wrapper.stories.tsx +2 -2
  635. package/src/stories/layout/vertical/one-column.stories.tsx +28 -23
  636. package/src/stories/runtime-story.tsx +23 -17
  637. package/src/stories/select.stories.tsx +2 -2
  638. package/src/stories/switchable-multi-select.stories.tsx +1 -1
  639. package/src/utils/__tests__/arrays.test.ts +35 -0
  640. package/src/utils/__tests__/batch-requests.test.ts +3 -3
  641. package/src/utils/__tests__/{createReducer.test.ts → createReducer.test.tsx} +29 -0
  642. package/src/utils/__tests__/numbers.test.ts +105 -1
  643. package/src/utils/__tests__/objects.test.ts +21 -0
  644. package/src/utils/arrays.ts +11 -2
  645. package/src/utils/blob.ts +1 -1
  646. package/src/utils/createReducer.ts +53 -26
  647. package/src/utils/maps.ts +0 -3
  648. package/src/utils/numbers.ts +79 -18
  649. package/src/utils/objects.ts +4 -9
  650. package/src/utils/once.ts +19 -19
  651. package/src/utils/tracer.ts +9 -5
  652. package/src/utils/zod-utils.ts +1 -3
  653. package/dist/any-language-editor-D4q-IFcM.js +0 -76
  654. package/dist/assets/__vite-browser-external-BXYkiFsk.js +0 -1
  655. package/dist/assets/worker-HPY9fbhz.js +0 -114
  656. package/dist/code-visibility-DPm4oWK1.js +0 -138
  657. package/dist/dropdown-menu-DHP9P4VE.js +0 -4678
  658. package/dist/feedback-button-DVgw4Y7F.js +0 -379
  659. package/dist/html-to-image-BdA59IUD.js +0 -3251
  660. package/dist/label-DoysmLMW.js +0 -281
  661. package/dist/mermaid-HWGCJPDP-ByCsZnYF.js +0 -2
  662. package/dist/objectWithoutPropertiesLoose-BRDcTsfB.js +0 -23
  663. package/dist/precisionRound-DMIVQrt2.js +0 -97
  664. package/dist/select-DemoKT4G.js +0 -1344
  665. package/dist/toDate-B5mIgxwZ.js +0 -1185
  666. package/dist/toast-PkdZraM8.js +0 -1830
  667. package/dist/use-restore-focus-CKjfFjLM.js +0 -6369
  668. package/dist/useLifecycle-BGWzTwHK.js +0 -169
  669. package/dist/useTheme-BhQvec43.js +0 -904
  670. package/src/components/editor/cell/code/__tests__/rtc-editor-config.test.ts +0 -50
  671. package/src/components/editor/chrome/wrapper/footer-items/rtc-status.tsx +0 -65
  672. package/src/components/editor/navigation/__tests__/state.test.ts +0 -81
  673. package/src/components/editor/navigation/state.ts +0 -65
  674. package/src/core/ai/tools/__tests__/run-cells-tool.test.ts +0 -656
  675. package/src/core/ai/tools/run-cells-tool.ts +0 -303
  676. package/src/core/attachments/state.ts +0 -18
  677. package/src/core/cells/__tests__/apply-transaction.test.ts +0 -991
  678. package/src/core/cells/__tests__/document-changes.test.ts +0 -1140
  679. package/src/core/cells/__tests__/document-roundtrip.test.ts +0 -392
  680. package/src/core/cells/document-changes.ts +0 -944
  681. package/src/core/codemirror/rtc/extension.ts +0 -453
  682. package/src/core/codemirror/rtc/loro/__tests__/sync.test.ts +0 -52
  683. package/src/core/codemirror/rtc/loro/awareness.ts +0 -531
  684. package/src/core/codemirror/rtc/loro/colors.ts +0 -38
  685. package/src/core/codemirror/rtc/loro/sync.ts +0 -168
  686. package/src/core/host/AGENTS.md +0 -11
  687. package/src/core/host/__tests__/events.test.ts +0 -46
  688. package/src/core/host/__tests__/fixtures.ts +0 -39
  689. package/src/core/host/__tests__/notebook-client.test.ts +0 -433
  690. package/src/core/host/__tests__/protocol.test.ts +0 -214
  691. package/src/core/host/__tests__/stream.test.ts +0 -211
  692. package/src/core/host/connection.ts +0 -81
  693. package/src/core/host/events.ts +0 -61
  694. package/src/core/host/notebook-client.ts +0 -290
  695. package/src/core/host/protocol.ts +0 -1943
  696. package/src/core/host/resources/resource.ts +0 -59
  697. package/src/core/host/stream.ts +0 -213
  698. package/src/core/rtc/state.ts +0 -34
  699. package/src/core/state/__tests__/jotai.test.ts +0 -25
  700. package/src/core/wasm/worker/message-buffer.ts +0 -33
  701. package/src/core/websocket/__tests__/createConnectionTransport.test.ts +0 -49
  702. package/src/core/websocket/__tests__/useNotebookClient.hook.test.tsx +0 -170
  703. package/src/core/websocket/state.ts +0 -7
  704. package/src/core/websocket/transports/__tests__/basic.test.ts +0 -275
  705. package/src/core/websocket/transports/__tests__/sse.test.ts +0 -335
  706. package/src/core/websocket/transports/__tests__/transport.test.ts +0 -308
  707. package/src/core/websocket/transports/__tests__/ws.test.ts +0 -125
  708. package/src/core/websocket/transports/basic.ts +0 -102
  709. package/src/core/websocket/transports/create.ts +0 -31
  710. package/src/core/websocket/transports/sse.ts +0 -308
  711. package/src/core/websocket/transports/transport.ts +0 -50
  712. package/src/core/websocket/transports/ws.ts +0 -98
  713. package/src/core/websocket/useNotebookClient.ts +0 -88
  714. package/src/utils/__tests__/id-tree.test.ts +0 -2145
  715. package/src/utils/id-tree.tsx +0 -1134
  716. /package/src/{core/attachments/toast.ts → components/editor/agent-toast.ts} +0 -0
  717. /package/src/core/{websocket → session}/connection-utils.ts +0 -0
@@ -2,13 +2,11 @@
2
2
 
3
3
  import { useAtom, useSetAtom } from "jotai";
4
4
  import {
5
- BookTextIcon,
6
5
  ChevronDownIcon,
7
6
  ChevronRightIcon,
8
7
  ChevronsDownUpIcon,
9
- ClockIcon,
10
8
  ExternalLinkIcon,
11
- PlayCircleIcon,
9
+ PlusIcon,
12
10
  PowerOffIcon,
13
11
  RefreshCcwIcon,
14
12
  SearchIcon,
@@ -44,6 +42,7 @@ import { Button } from "@/components/ui/button";
44
42
  import { Checkbox } from "@/components/ui/checkbox";
45
43
  import { DropdownMenuSeparator } from "@/components/ui/dropdown-menu";
46
44
  import { Label } from "@/components/ui/label";
45
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
47
46
  import { Tooltip } from "@/components/ui/tooltip";
48
47
  import { toast } from "@/components/ui/use-toast";
49
48
  import { getSessionId, isSessionId } from "@/core/kernel/session";
@@ -64,7 +63,6 @@ import { ConfigButton } from "../app-config/app-config-button";
64
63
  import { ErrorBoundary } from "../editor/boundary/ErrorBoundary";
65
64
  import { ShutdownButton } from "../editor/controls/shutdown-button";
66
65
  import {
67
- Header,
68
66
  OpenTutorialDropDown,
69
67
  ResourceLinks,
70
68
  TruncatedWorkspaceBanner,
@@ -83,6 +81,9 @@ function tabTarget(path: string) {
83
81
  return `${getSessionId()}-${encodeURIComponent(path)}`;
84
82
  }
85
83
 
84
+ const NOTEBOOK_TAB_CLASS =
85
+ "-mb-px rounded-none border-b-2 border-transparent px-1 py-3 text-(--gray-11) transition-colors hover:text-foreground focus-visible:ring-inset focus-visible:ring-offset-0 data-[state=active]:border-(--green-11) data-[state=active]:bg-transparent data-[state=active]:text-(--green-11) data-[state=active]:shadow-none";
86
+
86
87
  const HomePage: React.FC = () => {
87
88
  const [nonce, setNonce] = useState(0);
88
89
  const { getRecentFiles, getRunningNotebooks } = useRequestClient();
@@ -123,28 +124,75 @@ const HomePage: React.FC = () => {
123
124
  setRunningNotebooks: runningResponse.setData,
124
125
  }}
125
126
  >
126
- <div className="absolute top-3 right-5 flex gap-3 z-50">
127
- <OpenTutorialDropDown />
128
- <ConfigButton showAppConfig={false} />
129
- <ShutdownButton
130
- description={`This will shutdown the notebook server and terminate all running notebooks (${running.size}). You'll lose all data that's in memory.`}
131
- />
132
- </div>
133
- <div className="flex flex-col gap-6 max-w-6xl container pt-5 pb-20 z-10">
134
- <img src="logo.png" alt="marimo logo" className="w-48 mb-2" />
135
- <CreateNewNotebook />
136
- <ResourceLinks />
137
- <NotebookList
138
- header={<Header Icon={PlayCircleIcon}>Running notebooks</Header>}
139
- files={[...running.values()]}
140
- />
141
- <NotebookList
142
- header={<Header Icon={ClockIcon}>Recent notebooks</Header>}
143
- files={recents.files}
144
- />
145
- <ErrorBoundary>
146
- <WorkspaceNotebooks onRefreshRecents={recentsResponse.refetch} />
147
- </ErrorBoundary>
127
+ <div className="min-h-screen bg-background">
128
+ <header className="border-b border-border/60">
129
+ <div className="mx-auto flex max-w-7xl items-center justify-between gap-4 px-5 py-5 sm:px-10">
130
+ <img src="logo.png" alt="marimo" className="w-28" />
131
+ <div className="flex items-center gap-3">
132
+ <ConfigButton showAppConfig={false} />
133
+ <ShutdownButton
134
+ description={`This will shutdown the notebook server and terminate all running notebooks (${running.size}). You'll lose all data that's in memory.`}
135
+ />
136
+ </div>
137
+ </div>
138
+ </header>
139
+ <main className="mx-auto max-w-7xl px-5 py-8 sm:px-10 sm:py-10">
140
+ <div className="mb-8">
141
+ <h1 className="text-2xl font-semibold tracking-tight">
142
+ Your notebooks
143
+ </h1>
144
+ <p className="mt-2 text-sm text-muted-foreground">
145
+ Pick up where you left off, or start something new.
146
+ </p>
147
+ <div className="mt-5 flex items-center gap-3">
148
+ <CreateNewNotebook />
149
+ <OpenTutorialDropDown />
150
+ </div>
151
+ </div>
152
+ <Tabs defaultValue="workspace">
153
+ <TabsList
154
+ aria-label="Notebooks"
155
+ className="mb-5 flex h-auto w-full justify-start gap-6 rounded-none border-b border-border/70 bg-transparent p-0"
156
+ >
157
+ <TabsTrigger value="workspace" className={NOTEBOOK_TAB_CLASS}>
158
+ Workspace
159
+ </TabsTrigger>
160
+ <TabsTrigger value="recent" className={NOTEBOOK_TAB_CLASS}>
161
+ Recent
162
+ </TabsTrigger>
163
+ <TabsTrigger value="running" className={NOTEBOOK_TAB_CLASS}>
164
+ Running
165
+ <span className="ml-1.5 text-xs font-normal tabular-nums text-(--gray-11)">
166
+ {running.size}
167
+ </span>
168
+ </TabsTrigger>
169
+ </TabsList>
170
+ <TabsContent
171
+ value="workspace"
172
+ forceMount={true}
173
+ className="mt-0 data-[state=inactive]:hidden"
174
+ >
175
+ <ErrorBoundary>
176
+ <WorkspaceNotebooks
177
+ onRefreshRecents={recentsResponse.refetch}
178
+ />
179
+ </ErrorBoundary>
180
+ </TabsContent>
181
+ <TabsContent value="recent" className="mt-0">
182
+ <NotebookList
183
+ files={recents.files}
184
+ emptyMessage="Notebooks you open will appear here."
185
+ />
186
+ </TabsContent>
187
+ <TabsContent value="running" className="mt-0">
188
+ <NotebookList
189
+ files={[...running.values()]}
190
+ emptyMessage="No notebooks are running."
191
+ />
192
+ </TabsContent>
193
+ </Tabs>
194
+ <ResourceLinks />
195
+ </main>
148
196
  </div>
149
197
  </RunningNotebooksContext>
150
198
  </Suspense>
@@ -195,23 +243,37 @@ const WorkspaceNotebooks: React.FC<{ onRefreshRecents: () => void }> = ({
195
243
 
196
244
  return (
197
245
  <WorkspaceContext value={workspaceContextValue}>
198
- <div className="flex flex-col gap-2">
246
+ <div className="flex min-w-0 flex-col gap-4">
199
247
  {workspace.hasMore && (
200
248
  <TruncatedWorkspaceBanner fileCount={workspace.fileCount} />
201
249
  )}
202
- <Header
203
- Icon={BookTextIcon}
204
- control={
205
- <div className="flex items-center gap-2">
250
+ <div className="overflow-hidden rounded-lg border border-border/70 bg-background">
251
+ <div className="flex flex-wrap items-center gap-3 border-b border-border/60 bg-muted/20 p-3">
252
+ <div className="min-w-40 flex-1">
206
253
  <Input
207
254
  id="search"
255
+ aria-label="Search workspace"
208
256
  value={searchText}
209
- icon={<SearchIcon size={13} />}
257
+ icon={<SearchIcon size={15} />}
210
258
  onChange={(e) => setSearchText(e.target.value)}
211
- placeholder="Search"
212
- className="mb-0 border-border"
259
+ placeholder="Find a notebook…"
260
+ className="mb-0 h-9 rounded-md border-border/60 bg-background font-sans shadow-none hover:shadow-none focus-visible:shadow-none"
213
261
  />
214
- <CollapseAllButton />
262
+ </div>
263
+ <Button
264
+ variant="ghost"
265
+ size="icon"
266
+ onClick={() => refetch()}
267
+ aria-label="Refresh workspace"
268
+ >
269
+ {isFetching ? (
270
+ <Spinner size="small" />
271
+ ) : (
272
+ <RefreshCcwIcon className="w-4 h-4" />
273
+ )}
274
+ </Button>
275
+ <CollapseAllButton />
276
+ <div className="flex items-center gap-2">
215
277
  <Checkbox
216
278
  data-testid="include-markdown-checkbox"
217
279
  id="include-markdown"
@@ -220,23 +282,14 @@ const WorkspaceNotebooks: React.FC<{ onRefreshRecents: () => void }> = ({
220
282
  setIncludeMarkdown(Boolean(checked))
221
283
  }
222
284
  />
223
- <Label htmlFor="include-markdown">Include markdown</Label>
285
+ <Label
286
+ htmlFor="include-markdown"
287
+ className="text-xs text-muted-foreground"
288
+ >
289
+ Include markdown
290
+ </Label>
224
291
  </div>
225
- }
226
- >
227
- Workspace
228
- <Button
229
- variant="text"
230
- size="icon"
231
- className="w-4 h-4 ml-1 p-0 opacity-70 hover:opacity-100"
232
- onClick={() => refetch()}
233
- aria-label="Refresh workspace"
234
- >
235
- <RefreshCcwIcon className="w-4 h-4" />
236
- </Button>
237
- {isFetching && <Spinner size="small" />}
238
- </Header>
239
- <div className="flex flex-col divide-y divide-(--slate-3) border rounded overflow-hidden max-h-192 overflow-y-auto shadow-sm bg-background">
292
+ </div>
240
293
  <NotebookFileTree searchText={searchText} files={workspace.files} />
241
294
  </div>
242
295
  </div>
@@ -322,7 +375,7 @@ const NotebookFileTree: React.FC<{
322
375
  await handleRename(id, name);
323
376
  }}
324
377
  padding={5}
325
- rowHeight={35}
378
+ rowHeight={44}
326
379
  indent={15}
327
380
  overscanCount={1000}
328
381
  // Hide the drop cursor
@@ -343,13 +396,15 @@ const Node = ({ node, style }: NodeRendererProps<FileInfo>) => {
343
396
  : guessFileType(node.data.name);
344
397
 
345
398
  const Icon = FILE_TYPE_ICONS[fileType];
346
- const iconEl = <Icon className="w-5 h-5 shrink-0" strokeWidth={1.5} />;
399
+ const iconEl = (
400
+ <Icon className="w-4 h-4 shrink-0 text-(--gray-11)" strokeWidth={1.5} />
401
+ );
347
402
  const { root } = use(WorkspaceContext);
348
403
  const { runningNotebooks } = use(RunningNotebooksContext);
349
404
 
350
405
  const renderItem = () => {
351
406
  const itemClassName =
352
- "flex items-center pl-1 cursor-pointer hover:bg-accent/50 hover:text-accent-foreground rounded-l flex-1 overflow-hidden h-full pr-3 gap-2";
407
+ "flex items-center pl-1 cursor-pointer hover:bg-(--sage-3) hover:text-foreground rounded-l flex-1 overflow-hidden h-full pr-3 gap-2";
353
408
 
354
409
  // Inline rename input; react-arborist flips `node.isEditing` when
355
410
  // `node.edit()` is called from the FileActions menu.
@@ -413,7 +468,7 @@ const Node = ({ node, style }: NodeRendererProps<FileInfo>) => {
413
468
  <div
414
469
  style={style}
415
470
  className={cn(
416
- "flex items-center cursor-pointer ml-1 text-muted-foreground whitespace-nowrap group h-full",
471
+ "flex items-center cursor-pointer ml-1 text-sm text-foreground whitespace-nowrap group h-full",
417
472
  )}
418
473
  onClick={(evt) => {
419
474
  evt.stopPropagation();
@@ -479,21 +534,19 @@ const FolderArrow = ({ node }: { node: NodeApi<FileInfo> }) => {
479
534
  };
480
535
 
481
536
  const NotebookList: React.FC<{
482
- header: React.ReactNode;
483
537
  files: MarimoFile[];
484
- }> = ({ header, files }) => {
485
- if (files.length === 0) {
486
- return null;
487
- }
488
-
538
+ emptyMessage: string;
539
+ }> = ({ files, emptyMessage }) => {
489
540
  return (
490
- <div className="flex flex-col gap-2">
491
- {header}
492
- <div className="flex flex-col divide-y divide-(--slate-3) border rounded overflow-hidden max-h-192 overflow-y-auto shadow-sm bg-background">
493
- {files.map((file) => {
494
- return <MarimoFileComponent key={file.path} file={file} />;
495
- })}
496
- </div>
541
+ <div className="flex max-h-[500px] min-h-40 min-w-0 flex-col divide-y divide-border/50 overflow-y-auto rounded-lg border border-border/60">
542
+ {files.length === 0 && (
543
+ <p className="px-4 py-6 text-sm text-muted-foreground">
544
+ {emptyMessage}
545
+ </p>
546
+ )}
547
+ {files.map((file) => {
548
+ return <MarimoFileComponent key={file.path} file={file} />;
549
+ })}
497
550
  </div>
498
551
  );
499
552
  };
@@ -511,17 +564,19 @@ const MarimoFileComponent = ({ file }: { file: MarimoFile }) => {
511
564
  : asURL(`?file=${encodeURIComponent(file.path)}`);
512
565
 
513
566
  const isMarkdown = file.path.endsWith(".md");
567
+ const Icon = FILE_TYPE_ICONS[guessFileType(file.name)];
514
568
 
515
569
  return (
516
570
  <a
517
- className="py-1.5 px-4 hover:bg-(--blue-2) hover:text-primary transition-all duration-300 cursor-pointer group relative flex gap-4 items-center"
571
+ className="py-3 px-4 hover:bg-(--sage-3) transition-colors cursor-pointer group relative flex gap-3 items-center focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ring"
518
572
  key={file.path}
519
573
  href={href.toString()}
520
574
  target={tabTarget(file.initializationId || file.path)}
521
575
  >
522
- <div className="flex flex-col justify-between flex-1">
523
- <span className="flex items-center gap-2">
524
- {file.name}
576
+ <Icon className="h-4 w-4 shrink-0 text-(--gray-11)" strokeWidth={1.5} />
577
+ <div className="flex min-w-0 flex-col gap-1 flex-1">
578
+ <span className="flex items-center gap-2 text-sm font-medium">
579
+ <span className="truncate">{file.name}</span>
525
580
  {isMarkdown && (
526
581
  <span className="opacity-80">
527
582
  <MarkdownIcon />
@@ -530,7 +585,7 @@ const MarimoFileComponent = ({ file }: { file: MarimoFile }) => {
530
585
  </span>
531
586
  <p
532
587
  title={file.path}
533
- className="text-sm text-muted-foreground overflow-hidden whitespace-nowrap text-ellipsis"
588
+ className="text-xs text-muted-foreground overflow-hidden whitespace-nowrap text-ellipsis"
534
589
  >
535
590
  {file.path}
536
591
  </p>
@@ -541,8 +596,8 @@ const MarimoFileComponent = ({ file }: { file: MarimoFile }) => {
541
596
  <SessionShutdownButton filePath={file.path} />
542
597
  </div>
543
598
  <ExternalLinkIcon
544
- size={20}
545
- className="group-hover:opacity-100 opacity-0 transition-all duration-300 text-primary"
599
+ size={14}
600
+ className="opacity-40 group-hover:opacity-100"
546
601
  />
547
602
  </div>
548
603
  {!!file.lastModified && (
@@ -571,7 +626,8 @@ const SessionShutdownButton: React.FC<{ filePath: string }> = ({
571
626
  <Button
572
627
  size={"icon"}
573
628
  variant="outline"
574
- className="opacity-80 hover:opacity-100 hover:bg-accent text-destructive border-destructive hover:border-destructive hover:text-destructive bg-background hover:bg-(--red-1)"
629
+ aria-label="Shutdown notebook"
630
+ className="border-transparent text-muted-foreground shadow-none hover:border-destructive hover:bg-(--red-1) hover:text-destructive"
575
631
  onClick={(e) => {
576
632
  e.stopPropagation();
577
633
  e.preventDefault();
@@ -611,23 +667,40 @@ const SessionShutdownButton: React.FC<{ filePath: string }> = ({
611
667
  );
612
668
  };
613
669
 
614
- const CreateNewNotebook: React.FC = () => {
615
- const url = newNotebookURL();
670
+ export const CreateNewNotebook: React.FC = () => {
671
+ // Reusing a `__new__` key reattaches to an old session; rotate it per open
672
+ const [url, setUrl] = useState(newNotebookURL);
673
+ const rotateUrl = () => {
674
+ const next = newNotebookURL();
675
+ setUrl(next);
676
+ return next;
677
+ };
678
+ const rotateDragPayload = (event: React.DragEvent<HTMLAnchorElement>) => {
679
+ // The browser copies the href into the drag payload before this handler
680
+ // runs, so the rotated URL must be written into the payload by hand
681
+ const next = rotateUrl();
682
+ event.dataTransfer.setData("text/uri-list", next);
683
+ event.dataTransfer.setData("text/plain", next);
684
+ };
616
685
  return (
617
- <a
618
- className="relative rounded-lg p-6 group
619
- text-primary hover:bg-(--blue-2) shadow-md-solid shadow-accent border bg-(--blue-1)
620
- transition-all duration-300 cursor-pointer
621
- "
622
- href={url}
623
- target="_blank"
624
- rel="noreferrer"
686
+ <Button
687
+ asChild={true}
688
+ size="sm"
689
+ className="gap-2 rounded-md border-(--brand) bg-(--brand) text-(--brand-foreground) shadow-none hover:bg-(--brand-hover)"
625
690
  >
626
- <h2 className="text-lg font-semibold">Create a new notebook</h2>
627
- <div className="group-hover:opacity-100 opacity-0 absolute right-5 top-0 bottom-0 rounded-lg flex items-center justify-center transition-all duration-300">
628
- <ExternalLinkIcon size={24} />
629
- </div>
630
- </a>
691
+ <a
692
+ href={url}
693
+ target="_blank"
694
+ rel="noreferrer"
695
+ onClick={rotateUrl}
696
+ onAuxClick={rotateUrl}
697
+ onContextMenu={rotateUrl}
698
+ onDragStart={rotateDragPayload}
699
+ >
700
+ <PlusIcon className="h-4 w-4" />
701
+ New notebook
702
+ </a>
703
+ </Button>
631
704
  );
632
705
  };
633
706
 
@@ -0,0 +1,89 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import { EditorView } from "@codemirror/view";
4
+ import { act, fireEvent, render, screen } from "@testing-library/react";
5
+ import { createStore, Provider } from "jotai";
6
+ import { type ComponentProps, useEffect, useRef } from "react";
7
+ import { expect, it, vi } from "vitest";
8
+ import type { CellEditor } from "@/components/editor/cell/code/cell-editor";
9
+ import { TooltipProvider } from "@/components/ui/tooltip";
10
+ import { ScratchPad } from "./scratchpad";
11
+ import {
12
+ historyVisibleAtom,
13
+ scratchpadHistoryAtom,
14
+ } from "./scratchpad-history";
15
+ import { scratchpadCodeAtom } from "./state";
16
+
17
+ const state = vi.hoisted(() => ({
18
+ editor: null as EditorView | null,
19
+ }));
20
+
21
+ vi.mock("@/core/cells/cells", () => ({
22
+ useNotebook: () => ({ cellRuntime: {}, cellData: {} }),
23
+ }));
24
+ vi.mock("@/core/cells/actions", () => ({
25
+ useCellActions: () => ({ createCell: vi.fn() }),
26
+ }));
27
+ vi.mock("@/core/cells/focus", () => ({ useLastFocusedCellId: () => null }));
28
+ vi.mock("@/core/network/requests", () => ({
29
+ useRequestClient: () => ({ sendRunScratchpad: vi.fn() }),
30
+ }));
31
+ vi.mock("@/components/editor/chrome/panels/panel-context", () => ({
32
+ usePanelOrientation: () => "vertical",
33
+ usePanelSection: () => "sidebar",
34
+ }));
35
+ vi.mock("@/components/editor/Output", () => ({ OutputArea: () => null }));
36
+ vi.mock("@/components/editor/output/console/ConsoleOutput", () => ({
37
+ ConsoleOutput: () => null,
38
+ }));
39
+ vi.mock("@/plugins/impl/code/LazyAnyLanguageCodeMirror", () => ({
40
+ LazyAnyLanguageCodeMirror: () => null,
41
+ }));
42
+ vi.mock("@/components/shortcuts/renderShortcut", () => ({
43
+ renderShortcut: () => "",
44
+ }));
45
+ vi.mock("@/components/editor/cell/code/cell-editor", () => ({
46
+ CellEditor: ({ setEditorView }: ComponentProps<typeof CellEditor>) => {
47
+ const parent = useRef<HTMLDivElement>(null);
48
+ const setView = useRef(setEditorView);
49
+ useEffect(() => {
50
+ const view = new EditorView({
51
+ parent: parent.current ?? undefined,
52
+ extensions: [
53
+ EditorView.contentAttributes.of({
54
+ "aria-label": "Scratchpad editor",
55
+ }),
56
+ ],
57
+ });
58
+ state.editor = view;
59
+ setView.current(view);
60
+ return () => {
61
+ view.destroy();
62
+ state.editor = null;
63
+ };
64
+ }, []);
65
+ return <div ref={parent} />;
66
+ },
67
+ }));
68
+
69
+ it("focuses the editor after recalling history", () => {
70
+ const store = createStore();
71
+ store.set(scratchpadHistoryAtom, ["print(42)"]);
72
+ store.set(historyVisibleAtom, true);
73
+ render(
74
+ <Provider store={store}>
75
+ <TooltipProvider>
76
+ <ScratchPad />
77
+ </TooltipProvider>
78
+ </Provider>,
79
+ );
80
+ const recall = screen.getByRole("button", { name: "Recall code" });
81
+ act(() => recall.focus());
82
+ fireEvent.click(recall, { detail: 0 });
83
+ expect(recall).not.toBeInTheDocument();
84
+ expect(
85
+ screen.getByRole("textbox", { name: "Scratchpad editor" }),
86
+ ).toHaveFocus();
87
+ expect(state.editor?.state.doc.toString()).toBe("print(42)");
88
+ expect(store.get(scratchpadCodeAtom)).toBe("print(42)");
89
+ });
@@ -1,6 +1,6 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
- import type { EditorView } from "@codemirror/view";
3
+ import { EditorView } from "@codemirror/view";
4
4
  import { useAtom, useAtomValue, useSetAtom } from "jotai";
5
5
  import {
6
6
  BetweenHorizontalStartIcon,
@@ -10,14 +10,17 @@ import {
10
10
  PlayIcon,
11
11
  } from "lucide-react";
12
12
  import type React from "react";
13
- import { Suspense, useRef, useState } from "react";
13
+ import { Suspense, useMemo, useRef, useState } from "react";
14
14
  import { Panel, PanelGroup, PanelResizeHandle } from "react-resizable-panels";
15
15
  import useEvent from "react-use-event-hook";
16
- import { useCellActions, useNotebook } from "@/core/cells/cells";
16
+ import { useNotebook } from "@/core/cells/cells";
17
+ import { useCellActions } from "@/core/cells/actions";
17
18
  import { useLastFocusedCellId } from "@/core/cells/focus";
18
19
  import { HTMLCellId, SCRATCH_CELL_ID } from "@/core/cells/ids";
19
20
  import { DEFAULT_CELL_NAME } from "@/core/cells/names";
20
21
  import type { LanguageAdapterType } from "@/core/codemirror/language/types";
22
+ import { prepareCellCodeUpdate } from "@/core/codemirror/language/cell-code";
23
+ import { getEditorCodeAsPython } from "@/core/codemirror/language/utils";
21
24
  import { useResolvedMarimoConfig } from "@/core/config/config";
22
25
  import { CSSClasses } from "@/core/constants";
23
26
  import { useRequestClient } from "@/core/network/requests";
@@ -43,6 +46,7 @@ import {
43
46
  historyVisibleAtom,
44
47
  scratchpadHistoryAtom,
45
48
  } from "./scratchpad-history";
49
+ import { scratchpadCodeAtom } from "./state";
46
50
 
47
51
  const scratchpadCellConfig: CellConfig = {
48
52
  hide_code: false,
@@ -55,7 +59,7 @@ export const ScratchPad: React.FC = () => {
55
59
  const { theme } = useTheme();
56
60
  const ref = useRef<EditorView | null>(null);
57
61
  const lastFocusedCellId = useLastFocusedCellId();
58
- const { createNewCell, updateCellCode } = useCellActions();
62
+ const { createCell } = useCellActions();
59
63
  const { sendRunScratchpad } = useRequestClient();
60
64
  const orientation = usePanelOrientation();
61
65
  const section = usePanelSection();
@@ -65,8 +69,17 @@ export const ScratchPad: React.FC = () => {
65
69
  const output = cellRuntime?.output;
66
70
  const status = cellRuntime?.status;
67
71
  const consoleOutputs = cellRuntime?.consoleOutputs;
68
- const cellData = notebookState.cellData[cellId];
69
- const code = cellData?.code ?? "";
72
+ const [code, setCode] = useAtom(scratchpadCodeAtom);
73
+ const codeListener = useMemo(
74
+ () => [
75
+ EditorView.updateListener.of((update) => {
76
+ if (update.docChanged) {
77
+ setCode(getEditorCodeAsPython(update.view));
78
+ }
79
+ }),
80
+ ],
81
+ [setCode],
82
+ );
70
83
 
71
84
  const addToHistory = useSetAtom(addToHistoryAtom);
72
85
  const [historyVisible, setHistoryVisible] = useAtom(historyVisibleAtom);
@@ -81,19 +94,11 @@ export const ScratchPad: React.FC = () => {
81
94
  if (!code.trim()) {
82
95
  return;
83
96
  }
84
- createNewCell({
85
- code,
86
- before: false,
87
- cellId: lastFocusedCellId ?? "__end__",
88
- });
97
+ createCell({ after: lastFocusedCellId, code });
89
98
  });
90
99
 
91
100
  const handleClearCode = useEvent(() => {
92
- updateCellCode({
93
- cellId,
94
- code: "",
95
- formattingChange: false,
96
- });
101
+ setCode("");
97
102
  void sendRunScratchpad({ code: "" });
98
103
  const ev = ref.current;
99
104
  if (ev) {
@@ -109,20 +114,14 @@ export const ScratchPad: React.FC = () => {
109
114
 
110
115
  const handleSelectHistoryItem = useEvent((item: string) => {
111
116
  setHistoryVisible(false);
112
- updateCellCode({
113
- cellId,
114
- code: item,
115
- formattingChange: false,
116
- });
117
+ setCode(item);
117
118
  const ev = ref.current;
118
119
  if (ev) {
119
- ev.dispatch({
120
- changes: {
121
- from: 0,
122
- to: ev.state.doc.length,
123
- insert: item,
124
- },
125
- });
120
+ const update = prepareCellCodeUpdate(ev.state, item);
121
+ if (update) {
122
+ ev.dispatch(update);
123
+ }
124
+ ev.focus();
126
125
  }
127
126
  });
128
127
 
@@ -135,12 +134,24 @@ export const ScratchPad: React.FC = () => {
135
134
  return (
136
135
  <div className="absolute inset-0 z-100 bg-background p-3 border-none overflow-auto">
137
136
  <div className="overflow-auto flex flex-col gap-3">
138
- {history.map((item, index) => (
137
+ {history.map((item) => (
138
+ // The Recall code button provides keyboard access without making the code preview a button.
139
+ // react-doctor-disable-next-line react-doctor/click-events-have-key-events, react-doctor/no-static-element-interactions
139
140
  <div
140
- key={index}
141
- className="border rounded-md hover:shadow-sm cursor-pointer hover:border-input overflow-hidden"
141
+ key={item}
142
+ className="relative border rounded-md hover:shadow-sm cursor-pointer hover:border-input overflow-hidden"
142
143
  onClick={() => handleSelectHistoryItem(item)}
143
144
  >
145
+ <button
146
+ type="button"
147
+ className="sr-only focus:not-sr-only focus:absolute focus:right-1 focus:top-1 focus:z-10 focus:bg-background focus:px-2 focus:py-1 focus:outline focus:outline-ring"
148
+ onClick={(e) => {
149
+ e.stopPropagation();
150
+ handleSelectHistoryItem(item);
151
+ }}
152
+ >
153
+ Recall code
154
+ </button>
144
155
  <Suspense>
145
156
  <LazyAnyLanguageCodeMirror
146
157
  language="python"
@@ -249,7 +260,6 @@ export const ScratchPad: React.FC = () => {
249
260
  code={code}
250
261
  config={scratchpadCellConfig}
251
262
  status="idle"
252
- serializedEditorState={null}
253
263
  runCell={handleRun}
254
264
  userConfig={userConfig}
255
265
  editorViewRef={ref}
@@ -260,6 +270,7 @@ export const ScratchPad: React.FC = () => {
260
270
  showHiddenCode={Functions.NOOP}
261
271
  languageAdapter={languageAdapter}
262
272
  setLanguageAdapter={setLanguageAdapter}
273
+ extensions={codeListener}
263
274
  />
264
275
  </div>
265
276
  {renderHistory()}
@@ -0,0 +1,7 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ /** The scratchpad's editor state, kept while its panel is closed. */
4
+
5
+ import { atom } from "jotai";
6
+
7
+ export const scratchpadCodeAtom = atom("");