@marimo-team/islands 0.25.3-dev28 → 0.25.3-dev281

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 (840) hide show
  1. package/dist/{ConnectedDataExplorerComponent-7EaP9VWb.js → ConnectedDataExplorerComponent-CErm132k.js} +116 -113
  2. package/dist/{ErrorBoundary-CUdSBv06.js → ErrorBoundary-fSq1YI-S.js} +76 -82
  3. package/dist/_baseSet-BfI5FjBM.js +328 -0
  4. package/dist/{abnfDiagram-VCTEODGH-z_OSynK8.js → abnfDiagram-VCTEODGH-d-Qn2fwb.js} +2 -2
  5. package/dist/any-language-editor-6k6F12Z3.js +75 -0
  6. package/dist/{architectureDiagram-5GKGNRK7-Cs8J8BZr.js → architectureDiagram-5GKGNRK7-DxragHYv.js} +1 -1
  7. package/dist/{arrays-CN1djC4k.js → arrays-DoQ-AILx.js} +15 -27
  8. package/dist/assertNever-B-YzWzbL.js +507 -0
  9. package/dist/assets/__vite-browser-external-BKBpimif.js +1 -0
  10. package/dist/assets/worker-CgoMtD-_.js +113 -0
  11. package/dist/{blockDiagram-I7D4REHJ-Cg25UrxT.js → blockDiagram-I7D4REHJ-Dkhe6_PP.js} +1 -1
  12. package/dist/{button-CvjkwdSk.js → button-DZuNnIZO.js} +56 -48
  13. package/dist/{capabilities-CQ5IjhzL.js → capabilities-D9FskwsK.js} +2 -2
  14. package/dist/{chat-ui-BzjAsTFN.js → chat-ui-ByGe2rP1.js} +2100 -1810
  15. package/dist/{check-BMKBBrdc.js → check-XFzZeH-y.js} +1 -1
  16. package/dist/{chunk-IMKFNOWR-aoSFasqF.js → chunk-IMKFNOWR-C0x0feFg.js} +1 -1
  17. package/dist/{chunk-SHT3W25Y-CMaybO3O.js → chunk-SHT3W25Y-D0ZdASqB.js} +1 -1
  18. package/dist/{chunk-SVP7TREG-BNBrTAw1.js → chunk-SVP7TREG-BHjL96zx.js} +1 -1
  19. package/dist/{chunk-TICWLB2K-DXNxvUJn.js → chunk-TICWLB2K-CzcrwGfp.js} +1 -1
  20. package/dist/{classDiagram-ZZMXUADV-DXdCCDOg.js → classDiagram-ZZMXUADV-BTqFAZTP.js} +2 -2
  21. package/dist/{classDiagram-v2-VYDZK3BY-DyZqrtLP.js → classDiagram-v2-VYDZK3BY-EPXb0Elt.js} +2 -2
  22. package/dist/{code-visibility-BuxqA3v5.js → code-visibility-BhtW7mrV.js} +43 -50
  23. package/dist/{common-xtZHxsM2.js → common-BIZJLLSc.js} +10605 -10045
  24. package/dist/config-C8MFHQ2E.js +637 -0
  25. package/dist/{copy-icon-BgUO8jsi.js → copy-icon-CtllOdmg.js} +3 -3
  26. package/dist/createReducer-DRqwmaTc.js +67 -0
  27. package/dist/{cynefinDiagram-5FMLGOSQ-DWHuKJs8.js → cynefinDiagram-5FMLGOSQ-CBSD344q.js} +1 -1
  28. package/dist/{dagre-GXQ25YYZ-DYLu-OCU.js → dagre-GXQ25YYZ-JItjh3Ge.js} +3 -3
  29. package/dist/{dagre-BGSfXNEb.js → dagre-mqiMAsFY.js} +531 -680
  30. package/dist/{data-grid-overlay-editor-qnbf5J94.js → data-grid-overlay-editor-B8b_mHmv.js} +1 -1
  31. package/dist/{debounce-C3jyATpc.js → debounce-DrhhziJv.js} +2 -2
  32. package/dist/{diagram-S7CK7UJ4-PwwcUOHP.js → diagram-S7CK7UJ4-CTD9xTVb.js} +1 -1
  33. package/dist/{diagram-UQ7AKVKN-CvJbL_IM.js → diagram-UQ7AKVKN-DTfnFai8.js} +1 -1
  34. package/dist/{diagram-VX7I27RA-B5RkqnzN.js → diagram-VX7I27RA-BcSnucV-.js} +1 -1
  35. package/dist/{diagram-Z3DM3KII-CyijwTR2.js → diagram-Z3DM3KII-C2ATIE8A.js} +1 -1
  36. package/dist/{dialog-Cc479ZEH.js → dialog-CaYm5imE.js} +32 -32
  37. package/dist/{dist-Bvs24R_E.js → dist-11T5wq3_.js} +31 -30
  38. package/dist/{dist-F8Ep36rk.js → dist-17ugwGZc.js} +59 -58
  39. package/dist/{dist-BMQf5zIS.js → dist-7cRjf--y.js} +123 -122
  40. package/dist/{dist-diIx5qJW.js → dist-B8pkfkzc.js} +31 -30
  41. package/dist/{dist-CN_BeG2I.js → dist-B9UoM_wq.js} +58 -57
  42. package/dist/{dist-CLdpGQVr.js → dist-BGuMTs1i.js} +118 -117
  43. package/dist/{dist-BK4Oj99o.js → dist-BHW11fni.js} +18 -17
  44. package/dist/dist-BLY4m1Wi.js +850 -0
  45. package/dist/{dist-PXYI_yuP.js → dist-BNlcVoxs.js} +24 -23
  46. package/dist/{dist-D6d86eNJ.js → dist-BQYe5Bju.js} +47 -46
  47. package/dist/{dist-CkTTIdBe.js → dist-BX1mn8na.js} +337 -337
  48. package/dist/{dist-DiDibOYr.js → dist-Bh0PTKUW.js} +151 -150
  49. package/dist/{dist-CSJ0MDRw.js → dist-CKaXK92p.js} +56 -55
  50. package/dist/{dist-C8fAKSH1.js → dist-CLhwfhpJ.js} +53 -52
  51. package/dist/{dist-DoE4XJBC.js → dist-CYeqK4Xw.js} +9801 -10649
  52. package/dist/{dist-BLfKmR-l.js → dist-Cxlp3WH6.js} +16 -15
  53. package/dist/{dist-D-wwqlzJ.js → dist-DSJPGj42.js} +158 -157
  54. package/dist/{dist-BorMD-uX.js → dist-DU9ICsWZ.js} +75 -74
  55. package/dist/{dist-DBtSl3sf.js → dist-DWv0ALBi.js} +47 -46
  56. package/dist/{dist-OR1OnN-y.js → dist-DiBpWEsB.js} +31 -30
  57. package/dist/{dist-CrSP_H1M.js → dist-DiLFTlnl.js} +242 -242
  58. package/dist/{dist-CN8zI-XC.js → dist-X9CsotJl.js} +239 -239
  59. package/dist/{dist-CSbh1PNP.js → dist-cVDV5IuI.js} +23 -22
  60. package/dist/{dist-BuaRHxOc.js → dist-fRfaOoq8.js} +44 -43
  61. package/dist/{dist-Cg7gzw-a.js → dist-gTTI-9Px.js} +78 -77
  62. package/dist/{dropdown-menu-BuE2b8Yb.js → dropdown-menu-Bb0bFOIk.js} +2904 -1493
  63. package/dist/{ebnfDiagram-PWID7BFC-DG90ELFp.js → ebnfDiagram-PWID7BFC-B7B9JPxc.js} +2 -2
  64. package/dist/{erDiagram-RLTQ6QDP-FMo_SpyX.js → erDiagram-RLTQ6QDP-v6hDno1O.js} +1 -1
  65. package/dist/{error-banner-CFPHFw4h.js → error-banner-CHCdHVFB.js} +87 -87
  66. package/dist/error-entries-9U4BFHjf.js +2586 -0
  67. package/dist/{esm-AMFssoNp.js → esm-BDqqT86j.js} +329 -329
  68. package/dist/{esm-D2gTsXEV.js → esm-BgKjMvWw.js} +530 -529
  69. package/dist/feedback-button-CY92zeC6.js +374 -0
  70. package/dist/{flowDiagram-HODETNUW-DQ4JuadE.js → flowDiagram-HODETNUW-aIFlAtOy.js} +2 -2
  71. package/dist/{formats-Bv_5N2Ff.js → formats-PzBQMUnr.js} +6 -6
  72. package/dist/{glide-data-editor-DQ_cEi05.js → glide-data-editor-BdgfR8uu.js} +6630 -2846
  73. package/dist/{glide-utils-pisbYVjH.js → glide-utils-BSQr4d90.js} +107 -76
  74. package/dist/{globals-D7vITxEX.js → globals-CjnqsurJ.js} +3 -3
  75. package/dist/{graphlib-BmY_CCV9.js → graphlib-nlwT3Wvy.js} +177 -220
  76. package/dist/hasIn-C20JsQ2m.js +28 -0
  77. package/dist/{error-entries-j85LP88u.js → html-to-image-BYh_MorV.js} +26294 -26451
  78. package/dist/{infoDiagram-27XIBGKW-CRSDtRrd.js → infoDiagram-27XIBGKW-D6YHLeCP.js} +1 -1
  79. package/dist/isArrayLikeObject-B-HXCsex.js +626 -0
  80. package/dist/isEmpty-CdX7MTE1.js +14 -0
  81. package/dist/{ishikawaDiagram-5VMMS53U-DxLEUldB.js → ishikawaDiagram-5VMMS53U-D1ZvprOX.js} +1 -1
  82. package/dist/{kanban-definition-UXKFOSKX-BLhvu8o4.js → kanban-definition-UXKFOSKX-Bna_3BMr.js} +1 -1
  83. package/dist/{loader-BPdQhmlq.js → loader-DZvtzQoD.js} +3 -3
  84. package/dist/main.js +10276 -8171
  85. package/dist/{mermaid-Bjm6C1qN.js → mermaid-A36unKXJ.js} +62 -62
  86. package/dist/{mindmap-definition-YA3MSWOX-g2LwxnYQ.js → mindmap-definition-YA3MSWOX-CyVCs__G.js} +1 -1
  87. package/dist/{now-jM8-M7IR.js → now-BKZCLE5P.js} +12 -13
  88. package/dist/{number-overlay-editor-DJHB-CGK.js → number-overlay-editor-BQBhWG2O.js} +1 -1
  89. package/dist/{objects-CzUgoMIF.js → objects-DCmMvZtn.js} +1 -3
  90. package/dist/{once-BtE-wKRL.js → once-NnpX_HnX.js} +1 -1
  91. package/dist/{pegDiagram-XKGWAZYB-CpMAt3Qs.js → pegDiagram-XKGWAZYB-9hNBD2wZ.js} +2 -2
  92. package/dist/pencil-DYUlSKxZ.js +10 -0
  93. package/dist/pick-tCszMUbm.js +35 -0
  94. package/dist/{pieDiagram-E7YTZNPT-CVTthoZo.js → pieDiagram-E7YTZNPT-8tr-NYo7.js} +1 -1
  95. package/dist/{process-output-DGzGHArA.js → process-output-bS3MGJ3f.js} +4 -4
  96. package/dist/{railroadDiagram-O6MQD6OU-ao8cqqFB.js → railroadDiagram-O6MQD6OU-Dzg1dyyp.js} +2 -2
  97. package/dist/{react-vega-BDpbvBCb.js → react-vega-C4T9Rb_w.js} +1 -1
  98. package/dist/{requirementDiagram-BXWQKSXE--J8vyfm-.js → requirementDiagram-BXWQKSXE-B7sNqwGG.js} +1 -1
  99. package/dist/{reveal-component-BxYUpAPg.js → reveal-component-BqyL-_xE.js} +1151 -1128
  100. package/dist/select-DsoP1qe8.js +1200 -0
  101. package/dist/{sequenceDiagram-WJ2MYXX4-CiQbn62x.js → sequenceDiagram-WJ2MYXX4-oP9shbaG.js} +1 -1
  102. package/dist/{spec-D_u2ipzF.js → spec-BZMDxAu7.js} +41 -11
  103. package/dist/{stateDiagram-D77RDMKH-DVEeGs5b.js → stateDiagram-D77RDMKH-CjCv4ogv.js} +4 -4
  104. package/dist/{stateDiagram-v2-MP3YSRHH-1OQRe6iA.js → stateDiagram-v2-MP3YSRHH-BW9X162a.js} +2 -2
  105. package/dist/static-state-D-Q-Ajaa.js +72 -0
  106. package/dist/style.css +1 -1
  107. package/dist/{swimlanes-42K2YHIH-CqkGoGqn.js → swimlanes-42K2YHIH-Ckfs9Wrn.js} +1 -1
  108. package/dist/{swimlanesDiagram-VR7AAH4N-CszjkrKo.js → swimlanesDiagram-VR7AAH4N-DpTNG9YP.js} +2 -2
  109. package/dist/{swiper-component-DKntyn8p.js → swiper-component-DQbK_ZWm.js} +7 -7
  110. package/dist/{timeline-definition-24CTP7MA-DLRUNVAx.js → timeline-definition-24CTP7MA-BXaBlV6U.js} +1 -1
  111. package/dist/toast-BhjIy3Tq.js +491 -0
  112. package/dist/{tooltip-CtBZ5q8p.js → tooltip-DMMiOn2f.js} +321 -297
  113. package/dist/use-restore-focus-CosX7-gx.js +7568 -0
  114. package/dist/{useAsyncData-BneN349z.js → useAsyncData-Ci4AvJff.js} +18 -17
  115. package/dist/{useDateFormatter-DkajGwwd.js → useDateFormatter-CPlava52.js} +2 -2
  116. package/dist/{useDeepCompareMemoize-Z_7R8wTt.js → useDeepCompareMemoize-NaaWoFlX.js} +1 -1
  117. package/dist/useEvent-BRH-aCqi.js +19 -0
  118. package/dist/{useIframeCapabilities-DBETvvPl.js → useIframeCapabilities-BXhDDoCG.js} +1 -1
  119. package/dist/useLifecycle-SniivYmC.js +112 -0
  120. package/dist/{vega-component-DPd52jvr.js → vega-component-DIxaDQNs.js} +161 -160
  121. package/dist/{vega-embed-container-BgKnsDbB.js → vega-embed-container--LYZqguO.js} +2 -2
  122. package/dist/{vega-loader.browser-CpbZAXub.js → vega-loader.browser-B9Pz0EGP.js} +1 -1
  123. package/dist/{vennDiagram-4TSXK5OY-CypgoBVZ.js → vennDiagram-4TSXK5OY-C-hQ4iNJ.js} +1 -1
  124. package/dist/{wardleyDiagram-VM6X3IG4-B6xjiQ_g.js → wardleyDiagram-VM6X3IG4-C2MQ_Umv.js} +1 -1
  125. package/dist/{xychartDiagram-S5SC5T6Z-e0PefDVs.js → xychartDiagram-S5SC5T6Z-BtTTBn7Q.js} +1 -1
  126. package/package.json +16 -20
  127. package/src/__mocks__/document.tsx +63 -0
  128. package/src/__mocks__/executions.ts +197 -0
  129. package/src/__mocks__/notebook.ts +3 -7
  130. package/src/__mocks__/partial.ts +26 -0
  131. package/src/__mocks__/requests.ts +1 -4
  132. package/src/__tests__/CellStatus.test.tsx +25 -26
  133. package/src/__tests__/fixtures/pair-config.ts +1 -1
  134. package/src/__tests__/main.test.tsx +24 -1
  135. package/src/__tests__/module-entry.test.ts +44 -0
  136. package/src/__tests__/mount.test.ts +1 -21
  137. package/src/__tests__/{host-imports.test.ts → replica-imports.test.ts} +12 -11
  138. package/src/components/ai/__tests__/ai-model-dropdown.test.tsx +63 -0
  139. package/src/components/ai/ai-model-dropdown.tsx +11 -6
  140. package/src/components/app-config/__tests__/state.test.tsx +50 -0
  141. package/src/components/app-config/ai-config.tsx +156 -150
  142. package/src/components/app-config/app-config-button.tsx +6 -5
  143. package/src/components/app-config/app-config-form.tsx +5 -9
  144. package/src/components/app-config/common.tsx +7 -9
  145. package/src/components/app-config/data-form.tsx +112 -113
  146. package/src/components/app-config/mcp-config.tsx +30 -53
  147. package/src/components/app-config/user-config-form.css +91 -0
  148. package/src/components/app-config/user-config-form.tsx +266 -349
  149. package/src/components/chat/__tests__/capabilities-popover.test.tsx +0 -1
  150. package/src/components/chat/__tests__/chat-display.test.tsx +196 -0
  151. package/src/components/chat/__tests__/chat-markdown.test.tsx +43 -0
  152. package/src/components/chat/__tests__/chat-utils.test.ts +93 -1
  153. package/src/components/chat/__tests__/message-queue.test.tsx +17 -0
  154. package/src/components/chat/__tests__/notebook-access-selector.test.tsx +64 -0
  155. package/src/components/chat/__tests__/turn-timing.test.ts +84 -0
  156. package/src/components/chat/__tests__/use-assistant-turn.test.ts +95 -0
  157. package/src/components/chat/__tests__/user-message.test.tsx +27 -0
  158. package/src/components/chat/acp/__tests__/agent-panel-initialization.test.tsx +1 -1
  159. package/src/components/chat/acp/__tests__/agent-panel.test.tsx +22 -17
  160. package/src/components/chat/acp/__tests__/session-tabs.test.tsx +43 -0
  161. package/src/components/chat/acp/__tests__/state.test.ts +2 -2
  162. package/src/components/chat/acp/agent-panel.tsx +6 -3
  163. package/src/components/chat/acp/blocks.tsx +13 -12
  164. package/src/components/chat/acp/common.tsx +4 -5
  165. package/src/components/chat/acp/model-selector.tsx +1 -1
  166. package/src/components/chat/acp/session-tabs.tsx +8 -3
  167. package/src/components/chat/agent-activity.tsx +132 -0
  168. package/src/components/chat/capabilities-popover.tsx +2 -11
  169. package/src/components/chat/chat-components.tsx +9 -4
  170. package/src/components/chat/chat-display.tsx +131 -57
  171. package/src/components/chat/chat-history-popover.tsx +6 -1
  172. package/src/components/chat/chat-markdown.tsx +15 -0
  173. package/src/components/chat/chat-panel.tsx +216 -294
  174. package/src/components/chat/chat-typography.css +108 -0
  175. package/src/components/chat/chat-utils.ts +24 -35
  176. package/src/components/chat/notebook-access-selector.stories.tsx +22 -0
  177. package/src/components/chat/notebook-access-selector.tsx +100 -0
  178. package/src/components/chat/tool-call/__tests__/tool-labels.test.ts +76 -0
  179. package/src/components/chat/tool-call/__tests__/tool-step.test.tsx +57 -0
  180. package/src/components/chat/tool-call/shared.ts +6 -0
  181. package/src/components/chat/tool-call/tool-call-view.tsx +22 -76
  182. package/src/components/chat/tool-call/tool-labels.ts +172 -0
  183. package/src/components/chat/tool-call/tool-result.tsx +1 -1
  184. package/src/components/chat/tool-call/tool-step.tsx +145 -0
  185. package/src/components/chat/turn-timing.ts +73 -0
  186. package/src/components/chat/use-assistant-turn.ts +65 -0
  187. package/src/components/chat/use-chat-generation.ts +20 -0
  188. package/src/components/chat/user-message.tsx +145 -0
  189. package/src/components/data-table/TableBottomBar.tsx +4 -1
  190. package/src/components/data-table/TableTopBar.tsx +2 -0
  191. package/src/components/data-table/__tests__/chart-spec-model.test.ts +195 -195
  192. package/src/components/data-table/__tests__/column-explorer.test.tsx +27 -1
  193. package/src/components/data-table/__tests__/columns.test.tsx +105 -0
  194. package/src/components/data-table/__tests__/context-menu-interaction.test.tsx +130 -0
  195. package/src/components/data-table/__tests__/data-table.test.tsx +1 -0
  196. package/src/components/data-table/__tests__/date-popover.test.tsx +72 -0
  197. package/src/components/data-table/__tests__/export-actions.test.tsx +105 -0
  198. package/src/components/data-table/__tests__/keyboard-selection.test.tsx +188 -0
  199. package/src/components/data-table/__tests__/pagination.test.tsx +28 -1
  200. package/src/components/data-table/__tests__/search-highlight.test.tsx +109 -0
  201. package/src/components/data-table/__tests__/url-detector.test.tsx +74 -0
  202. package/src/components/data-table/cell-selection/feature.ts +2 -2
  203. package/src/components/data-table/cell-selection/types.ts +2 -2
  204. package/src/components/data-table/charts/__tests__/chart-panel.test.tsx +74 -1
  205. package/src/components/data-table/charts/__tests__/spec-snapshot.test.ts +20 -20
  206. package/src/components/data-table/charts/__tests__/spec.test.ts +78 -52
  207. package/src/components/data-table/charts/__tests__/storage.test.ts +4 -1
  208. package/src/components/data-table/charts/chart-spec/spec.ts +68 -43
  209. package/src/components/data-table/charts/charts.tsx +40 -30
  210. package/src/components/data-table/charts/storage.ts +16 -5
  211. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +1 -1
  212. package/src/components/data-table/column-formatting/types.ts +1 -2
  213. package/src/components/data-table/column-summary/chart-spec-model.tsx +23 -16
  214. package/src/components/data-table/column-summary/column-summary.tsx +2 -4
  215. package/src/components/data-table/column-visibility-dropdown.tsx +8 -13
  216. package/src/components/data-table/columns.tsx +45 -46
  217. package/src/components/data-table/context-menu.tsx +36 -20
  218. package/src/components/data-table/data-table.tsx +17 -1
  219. package/src/components/data-table/date-popover.tsx +6 -4
  220. package/src/components/data-table/export-actions.tsx +76 -48
  221. package/src/components/data-table/pagination.tsx +44 -33
  222. package/src/components/data-table/range-focus/atoms.ts +4 -6
  223. package/src/components/data-table/range-focus/use-cell-range-selection.ts +65 -38
  224. package/src/components/data-table/range-focus/use-scroll-into-view.ts +21 -2
  225. package/src/components/data-table/renderers.tsx +16 -7
  226. package/src/components/data-table/row-viewer-panel/__tests__/row-viewer.test.tsx +24 -1
  227. package/src/components/data-table/row-viewer-panel/row-viewer.tsx +4 -4
  228. package/src/components/data-table/search-highlight.tsx +79 -0
  229. package/src/components/data-table/types.ts +1 -0
  230. package/src/components/data-table/url-detector.tsx +49 -9
  231. package/src/components/datasources/__tests__/column-actions.test.tsx +97 -0
  232. package/src/components/datasources/__tests__/column-preview.test.tsx +96 -5
  233. package/src/components/datasources/__tests__/datasources-interactions.test.tsx +181 -0
  234. package/src/components/datasources/__tests__/table-list.test.tsx +118 -0
  235. package/src/components/datasources/__tests__/utils.test.ts +57 -6
  236. package/src/components/datasources/column-preview.tsx +17 -12
  237. package/src/components/datasources/datasources.tsx +56 -43
  238. package/src/components/datasources/utils.ts +32 -23
  239. package/src/components/debugger/debugger-code.tsx +5 -0
  240. package/src/components/dependency-graph/custom-node.tsx +1 -1
  241. package/src/components/dependency-graph/dependency-graph-tree.tsx +8 -8
  242. package/src/components/dependency-graph/elements.ts +24 -21
  243. package/src/components/dependency-graph/minimap-content.tsx +15 -20
  244. package/src/components/dependency-graph/panels.tsx +4 -2
  245. package/src/components/dependency-graph/utils/__tests__/layout.test.ts +18 -11
  246. package/src/components/editor/SortableCell.tsx +1 -3
  247. package/src/components/editor/__tests__/Output.test.tsx +50 -32
  248. package/src/{core/attachments/__tests__/toast.test.tsx → components/editor/__tests__/agent-toast.test.tsx} +1 -1
  249. package/src/components/editor/__tests__/data-attributes.test.tsx +28 -23
  250. package/src/components/editor/__tests__/dynamic-favicon.test.tsx +111 -18
  251. package/src/components/editor/__tests__/output-persistence.test.tsx +28 -9
  252. package/src/components/editor/__tests__/package-alert.test.tsx +22 -1
  253. package/src/components/editor/actions/__tests__/name-cell-input.test.tsx +69 -0
  254. package/src/components/editor/actions/__tests__/pair-with-agent-commands.test.ts +21 -40
  255. package/src/components/editor/actions/__tests__/pair-with-agent-modal.test.tsx +41 -14
  256. package/src/components/editor/actions/__tests__/pair-with-agent.test.tsx +6 -24
  257. package/src/components/editor/actions/__tests__/useCellActionButton.test.tsx +131 -0
  258. package/src/components/editor/actions/name-cell-input.tsx +4 -3
  259. package/src/components/editor/actions/pair-with-agent-commands.ts +10 -7
  260. package/src/components/editor/actions/pair-with-agent-modal.tsx +29 -30
  261. package/src/components/editor/actions/pair-with-agent.tsx +16 -39
  262. package/src/components/editor/actions/useCellActionButton.tsx +47 -35
  263. package/src/components/editor/actions/useConfigActions.tsx +3 -4
  264. package/src/components/editor/actions/useNotebookActions.tsx +25 -29
  265. package/src/components/editor/actions/useRestartKernel.tsx +1 -1
  266. package/src/components/editor/actions/useSetCodeVisibility.ts +11 -12
  267. package/src/components/editor/actions/useSetOutputsExpanded.ts +14 -19
  268. package/src/components/editor/ai/ai-completion-editor.tsx +2 -1
  269. package/src/components/editor/ai/completion-handlers.tsx +0 -37
  270. package/src/components/editor/ai/prompt-input.tsx +189 -0
  271. package/src/components/editor/alerts/__tests__/connection-notice.test.tsx +1 -1
  272. package/src/components/editor/alerts/connection-notice.tsx +1 -1
  273. package/src/components/editor/alerts/startup-logs-alert.tsx +1 -0
  274. package/src/components/editor/alerts/stdin-blocking-alert.tsx +4 -2
  275. package/src/components/editor/app-container.tsx +1 -1
  276. package/src/components/editor/boundary/__tests__/ErrorBoundary.test.tsx +1 -1
  277. package/src/components/editor/cell/CellStatus.tsx +28 -23
  278. package/src/components/editor/cell/CreateCellButton.tsx +15 -21
  279. package/src/components/editor/cell/DeleteButton.tsx +3 -2
  280. package/src/components/editor/cell/RunButton.tsx +18 -8
  281. package/src/components/editor/cell/StagedAICell.tsx +52 -137
  282. package/src/components/editor/cell/StopButton.tsx +2 -2
  283. package/src/components/editor/cell/__tests__/useRunCells.test.tsx +169 -0
  284. package/src/components/editor/cell/__tests__/useShouldShowInterrupt.test.ts +39 -0
  285. package/src/components/editor/cell/cell-actions.tsx +12 -1
  286. package/src/components/editor/cell/cell-context-menu.tsx +4 -1
  287. package/src/components/editor/cell/code/__tests__/language-toggle.test.tsx +54 -0
  288. package/src/components/editor/cell/code/cell-editor.tsx +65 -169
  289. package/src/components/editor/cell/code/language-toggle.tsx +8 -7
  290. package/src/components/editor/cell/collapse.tsx +16 -6
  291. package/src/components/editor/cell/useAddCell.ts +4 -8
  292. package/src/components/editor/cell/useDeleteCell.tsx +10 -36
  293. package/src/components/editor/cell/useRunCells.ts +49 -8
  294. package/src/components/editor/cell/useShouldShowInterrupt.ts +2 -12
  295. package/src/components/editor/cell/useSplitCell.tsx +10 -6
  296. package/src/components/editor/chrome/components/__tests__/feedback-button.test.tsx +1 -1
  297. package/src/components/editor/chrome/components/feedback-button.tsx +2 -8
  298. package/src/components/editor/chrome/panels/__tests__/packages-panel.test.tsx +31 -2
  299. package/src/components/editor/chrome/panels/__tests__/runtime-details.test.tsx +1 -1
  300. package/src/components/editor/chrome/panels/__tests__/sandbox-recovery.test.tsx +1 -1
  301. package/src/components/editor/chrome/panels/cache-panel.tsx +1 -0
  302. package/src/components/editor/chrome/panels/dependency-graph-panel.tsx +1 -1
  303. package/src/components/editor/chrome/panels/logs-panel.tsx +2 -1
  304. package/src/components/editor/chrome/panels/outline/__tests__/outline-keyboard.test.tsx +84 -0
  305. package/src/components/editor/chrome/panels/outline/floating-outline.tsx +39 -14
  306. package/src/components/editor/chrome/panels/outline/useActiveOutline.tsx +3 -2
  307. package/src/components/editor/chrome/panels/packages-panel.tsx +4 -7
  308. package/src/components/editor/chrome/panels/panel-header.tsx +13 -0
  309. package/src/components/editor/chrome/panels/secrets-panel.tsx +1 -0
  310. package/src/components/editor/chrome/panels/session-panel.tsx +1 -1
  311. package/src/components/editor/chrome/panels/snippets-panel.tsx +10 -12
  312. package/src/components/editor/chrome/panels/variable-panel.tsx +1 -5
  313. package/src/components/editor/chrome/types.ts +1 -1
  314. package/src/components/editor/chrome/wrapper/__tests__/attachment-status.test.tsx +7 -9
  315. package/src/components/editor/chrome/wrapper/__tests__/document-sync-status.test.tsx +92 -0
  316. package/src/components/editor/chrome/wrapper/__tests__/pending-ai-cells.test.tsx +265 -37
  317. package/src/components/editor/chrome/wrapper/__tests__/useAskAiAboutCell.test.tsx +58 -0
  318. package/src/components/editor/chrome/wrapper/app-chrome.tsx +91 -74
  319. package/src/components/editor/chrome/wrapper/footer-items/attachment-status.tsx +4 -4
  320. package/src/components/editor/chrome/wrapper/footer-items/backend-status.tsx +1 -1
  321. package/src/components/editor/chrome/wrapper/footer-items/document-sync-status.tsx +54 -0
  322. package/src/components/editor/chrome/wrapper/footer-items/lsp-status.tsx +1 -1
  323. package/src/components/editor/chrome/wrapper/footer-items/machine-stats.tsx +1 -1
  324. package/src/components/editor/chrome/wrapper/footer-items/runtime-settings.tsx +1 -7
  325. package/src/components/editor/chrome/wrapper/footer.tsx +2 -2
  326. package/src/components/editor/chrome/wrapper/minimap-state.ts +1 -1
  327. package/src/components/editor/chrome/wrapper/pending-ai-cells.tsx +143 -72
  328. package/src/components/editor/chrome/wrapper/pending-ai-changes-badge.tsx +25 -0
  329. package/src/components/editor/chrome/wrapper/sidebar.tsx +8 -4
  330. package/src/components/editor/chrome/wrapper/storage.ts +1 -1
  331. package/src/components/editor/chrome/wrapper/useAskAiAboutCell.ts +36 -0
  332. package/src/components/editor/columns/__tests__/cell-column.test.tsx +1 -1
  333. package/src/components/editor/columns/cell-column.tsx +1 -1
  334. package/src/components/editor/columns/sortable-column.tsx +2 -2
  335. package/src/components/editor/connections/components.tsx +5 -10
  336. package/src/components/editor/controls/Controls.tsx +4 -4
  337. package/src/components/editor/controls/__tests__/command-palette.test.tsx +53 -0
  338. package/src/components/editor/controls/__tests__/keyboard-shortcuts.test.tsx +61 -0
  339. package/src/components/editor/controls/__tests__/notebook-menu-dropdown.test.tsx +10 -4
  340. package/src/components/editor/controls/command-palette.tsx +22 -10
  341. package/src/components/editor/controls/keyboard-shortcuts.tsx +14 -5
  342. package/src/components/editor/documentation.css +34 -11
  343. package/src/components/editor/dynamic-favicon.tsx +21 -40
  344. package/src/components/editor/errors/__tests__/send-error-report-button.test.tsx +26 -22
  345. package/src/components/editor/errors/auto-fix.tsx +4 -8
  346. package/src/components/editor/errors/send-error-report-button.tsx +3 -6
  347. package/src/components/editor/file-tree/__tests__/file-explorer-interactions.test.tsx +6 -0
  348. package/src/components/editor/file-tree/__tests__/file-explorer-navigation.test.tsx +47 -0
  349. package/src/components/editor/file-tree/__tests__/use-file-search.test.tsx +91 -0
  350. package/src/components/editor/file-tree/file-explorer.tsx +48 -15
  351. package/src/components/editor/file-tree/file-name-input.tsx +1 -0
  352. package/src/components/editor/file-tree/file-viewer.tsx +4 -2
  353. package/src/components/editor/file-tree/use-file-search.ts +35 -21
  354. package/src/components/editor/header/__tests__/filename-form.test.tsx +1 -4
  355. package/src/components/editor/header/__tests__/status.test.tsx +5 -3
  356. package/src/components/editor/header/app-header.tsx +1 -1
  357. package/src/components/editor/header/filename-form.tsx +1 -1
  358. package/src/components/editor/header/status.tsx +44 -22
  359. package/src/components/editor/links/__tests__/cell-link.test.tsx +148 -0
  360. package/src/components/editor/links/cell-link-list.tsx +1 -1
  361. package/src/components/editor/links/cell-link.tsx +21 -11
  362. package/src/components/editor/navigation/__tests__/clipboard.test.ts +60 -38
  363. package/src/components/editor/navigation/__tests__/navigation.test.ts +108 -85
  364. package/src/components/editor/navigation/__tests__/selection.test.ts +43 -21
  365. package/src/components/editor/navigation/clipboard.ts +17 -14
  366. package/src/components/editor/navigation/focus-utils.ts +23 -4
  367. package/src/components/editor/navigation/multi-cell-action-toolbar.tsx +17 -33
  368. package/src/components/editor/navigation/navigation.ts +74 -72
  369. package/src/components/editor/navigation/selection.ts +30 -29
  370. package/src/components/editor/notebook-banner.tsx +1 -0
  371. package/src/components/editor/notebook-cell.tsx +126 -152
  372. package/src/components/editor/output/MarimoErrorOutput.tsx +2 -1
  373. package/src/components/editor/output/MarimoTracebackOutput.tsx +19 -17
  374. package/src/components/editor/output/Outputs.css +8 -0
  375. package/src/components/editor/output/VideoOutput.tsx +6 -0
  376. package/src/components/editor/output/__tests__/VideoOutput.test.tsx +131 -0
  377. package/src/components/editor/output/__tests__/traceback.test.tsx +27 -1
  378. package/src/components/editor/output/ansi-reduce.ts +33 -20
  379. package/src/components/editor/output/console/ConsoleOutput.tsx +19 -25
  380. package/src/components/editor/output/console/__tests__/ConsoleOutput.test.tsx +125 -69
  381. package/src/components/editor/package-alert.tsx +14 -7
  382. package/src/components/editor/renderers/__tests__/add-cell-buttons.test.tsx +18 -0
  383. package/src/components/editor/renderers/cell-array.tsx +32 -100
  384. package/src/components/editor/renderers/grid-layout/__tests__/grid-layout.test.tsx +75 -0
  385. package/src/components/editor/renderers/grid-layout/grid-layout.tsx +28 -22
  386. package/src/components/editor/renderers/slides-layout/__tests__/plugin.test.ts +0 -4
  387. package/src/components/editor/renderers/slides-layout/slides-layout.tsx +1 -1
  388. package/src/components/editor/renderers/vertical-layout/__tests__/useFocusFirstEditor.test.ts +4 -4
  389. package/src/components/editor/renderers/vertical-layout/sidebar/toggle.tsx +7 -1
  390. package/src/components/editor/renderers/vertical-layout/useFocusFirstEditor.ts +1 -1
  391. package/src/components/editor/renderers/vertical-layout/vertical-layout.tsx +19 -37
  392. package/src/components/editor/stdin-blocking-alert.tsx +4 -2
  393. package/src/components/home/components.tsx +17 -31
  394. package/src/components/icons/__tests__/large-spinner.test.tsx +39 -0
  395. package/src/components/icons/large-spinner.tsx +3 -14
  396. package/src/components/icons/spinner.tsx +1 -1
  397. package/src/components/markdown/markdown-renderer.tsx +39 -28
  398. package/src/components/mcp/mcp-status-indicator.tsx +18 -14
  399. package/src/components/pages/__tests__/home-page.test.tsx +116 -0
  400. package/src/components/pages/edit-page.tsx +19 -17
  401. package/src/components/pages/home-page.tsx +164 -91
  402. package/src/components/scratchpad/scratchpad.test.tsx +89 -0
  403. package/src/components/scratchpad/scratchpad.tsx +47 -33
  404. package/src/components/scratchpad/state.ts +7 -0
  405. package/src/components/slides/__tests__/minimap-actions.test.tsx +22 -29
  406. package/src/components/slides/__tests__/minimap.test.ts +38 -19
  407. package/src/components/slides/__tests__/slide-scroll-hint.test.tsx +37 -0
  408. package/src/components/slides/minimap.tsx +22 -14
  409. package/src/components/slides/reveal-component.tsx +73 -36
  410. package/src/components/slides/reveal-slides.css +5 -4
  411. package/src/components/slides/slide-cell-view.tsx +37 -34
  412. package/src/components/slides/slide-form.tsx +1 -0
  413. package/src/components/slides/slide-scroll-hint.tsx +3 -1
  414. package/src/components/slides/slide.tsx +3 -4
  415. package/src/components/sort/SortableCellsProvider.tsx +8 -25
  416. package/src/components/tracing/tracing-keyboard.test.tsx +85 -0
  417. package/src/components/tracing/tracing.tsx +46 -42
  418. package/src/components/ui/__tests__/draggable-popover.test.tsx +24 -0
  419. package/src/components/ui/__tests__/fullscreen.test.tsx +44 -2
  420. package/src/components/ui/__tests__/range-slider.test.tsx +165 -0
  421. package/src/components/ui/alert-dialog.tsx +1 -1
  422. package/src/components/ui/draggable-popover.tsx +24 -2
  423. package/src/components/ui/fullscreen.tsx +25 -1
  424. package/src/components/ui/range-slider.tsx +22 -9
  425. package/src/components/ui/toast.tsx +1 -1
  426. package/src/core/MarimoApp.tsx +3 -1
  427. package/src/core/ai/__tests__/staged-cells.test.ts +89 -608
  428. package/src/core/ai/context/context.ts +2 -0
  429. package/src/core/ai/context/providers/__tests__/cell-output.test.ts +8 -12
  430. package/src/core/ai/context/providers/__tests__/cell.test.ts +49 -0
  431. package/src/core/ai/context/providers/cell-output.ts +2 -2
  432. package/src/core/ai/context/providers/cell.ts +54 -0
  433. package/src/core/ai/context/providers/datasource.ts +6 -2
  434. package/src/core/ai/staged-cells.ts +56 -323
  435. package/src/core/ai/state.ts +3 -0
  436. package/src/core/ai/tools/__tests__/edit-notebook-tool.test.ts +40 -88
  437. package/src/core/ai/tools/__tests__/registry.test.ts +17 -0
  438. package/src/core/ai/tools/base.ts +18 -15
  439. package/src/core/ai/tools/edit-notebook-tool.ts +86 -80
  440. package/src/core/ai/tools/registry.ts +13 -10
  441. package/src/core/ai/tools/sample-tool.ts +6 -7
  442. package/src/core/cells/__tests__/__snapshots__/cells.test.ts.snap +4 -527
  443. package/src/core/cells/__tests__/actions.test.ts +623 -35
  444. package/src/core/cells/__tests__/add-missing-import.test.ts +7 -8
  445. package/src/core/cells/__tests__/arrange.test.ts +432 -0
  446. package/src/core/cells/__tests__/cell.test.ts +148 -150
  447. package/src/core/cells/__tests__/cells.test.ts +225 -2723
  448. package/src/core/cells/__tests__/collapseConsoleOutputs.test.ts +54 -0
  449. package/src/core/cells/__tests__/document.test.ts +158 -0
  450. package/src/core/cells/__tests__/editor.test.ts +57 -0
  451. package/src/core/cells/__tests__/flush-document.test.ts +40 -0
  452. package/src/core/cells/__tests__/harness.ts +106 -0
  453. package/src/core/cells/__tests__/layout.test.ts +177 -0
  454. package/src/core/cells/__tests__/notebook-outline.test.ts +122 -0
  455. package/src/core/cells/__tests__/outputs.test.tsx +71 -53
  456. package/src/core/cells/__tests__/pending-delete-service.test.tsx +11 -20
  457. package/src/core/cells/__tests__/session.test.ts +445 -211
  458. package/src/core/cells/__tests__/utils.test.ts +135 -337
  459. package/src/core/cells/actions.ts +677 -6
  460. package/src/core/cells/add-missing-import.ts +47 -43
  461. package/src/core/cells/arrange.ts +529 -0
  462. package/src/core/cells/cell.ts +78 -146
  463. package/src/core/cells/cells.ts +116 -1457
  464. package/src/core/cells/columns.ts +38 -0
  465. package/src/core/cells/document.ts +167 -0
  466. package/src/core/cells/edit.ts +30 -0
  467. package/src/core/cells/editor.ts +82 -0
  468. package/src/core/cells/focus.ts +27 -6
  469. package/src/core/cells/layout.ts +221 -0
  470. package/src/core/cells/outputs.ts +12 -28
  471. package/src/core/cells/pending-delete-service.ts +8 -14
  472. package/src/core/cells/scrollCellIntoView.ts +6 -0
  473. package/src/core/cells/session.ts +76 -53
  474. package/src/core/cells/types.ts +21 -51
  475. package/src/core/cells/utils.ts +85 -87
  476. package/src/core/codemirror/__tests__/format.test.ts +0 -34
  477. package/src/core/codemirror/__tests__/setup.test.ts +61 -29
  478. package/src/core/codemirror/ai/__tests__/resources.test.ts +117 -0
  479. package/src/core/codemirror/ai/resources.ts +1 -1
  480. package/src/core/codemirror/cells/__tests__/extensions.test.ts +2 -6
  481. package/src/core/codemirror/cells/extensions.ts +18 -30
  482. package/src/core/codemirror/cells/state.ts +2 -6
  483. package/src/core/codemirror/cm.ts +5 -1
  484. package/src/core/codemirror/config/types.ts +1 -1
  485. package/src/core/codemirror/copilot/__tests__/getCodes.test.ts +6 -7
  486. package/src/core/codemirror/copilot/getCodes.ts +2 -2
  487. package/src/core/codemirror/format.ts +6 -23
  488. package/src/core/codemirror/keymaps/vim.ts +4 -8
  489. package/src/core/codemirror/language/__tests__/sql.test.ts +22 -20
  490. package/src/core/codemirror/language/__tests__/utils.test.ts +187 -15
  491. package/src/core/codemirror/language/cell-code.ts +114 -0
  492. package/src/core/codemirror/language/extension.ts +52 -35
  493. package/src/core/codemirror/language/languages/markdown.ts +8 -6
  494. package/src/core/codemirror/language/languages/python.ts +19 -13
  495. package/src/core/codemirror/language/languages/sql/sql.ts +16 -24
  496. package/src/core/codemirror/language/panel/panel.tsx +1 -0
  497. package/src/core/codemirror/language/types.ts +7 -7
  498. package/src/core/codemirror/language/utils.ts +9 -39
  499. package/src/core/codemirror/lsp/__tests__/notebook-lsp.test.ts +1 -2
  500. package/src/core/codemirror/lsp/notebook-lsp.ts +6 -5
  501. package/src/core/codemirror/lsp/utils.ts +1 -1
  502. package/src/core/codemirror/misc/__tests__/paste.test.ts +3 -1
  503. package/src/core/codemirror/misc/paste.ts +1 -1
  504. package/src/core/codemirror/placeholder/__tests__/extensions.test.ts +75 -0
  505. package/src/core/codemirror/placeholder/extensions.ts +80 -19
  506. package/src/core/codemirror/readonly/__tests__/extension.test.ts +1 -1
  507. package/src/core/codemirror/readonly/extension.ts +2 -2
  508. package/src/core/codemirror/utils.ts +1 -0
  509. package/src/core/config/__tests__/app-config.test.ts +64 -0
  510. package/src/core/config/__tests__/config-schema.test.ts +56 -6
  511. package/src/core/config/config-schema.ts +17 -4
  512. package/src/core/config/config.ts +65 -20
  513. package/src/core/config/feature-flag.tsx +0 -2
  514. package/src/core/datasets/__tests__/data-source-discovery.test.ts +5 -5
  515. package/src/core/datasets/data-source-discovery.ts +4 -6
  516. package/src/core/documentation/doc-lookup.ts +1 -1
  517. package/src/core/edit-app.tsx +22 -28
  518. package/src/core/errors/__tests__/error-entries.test.ts +40 -1
  519. package/src/core/errors/error-entries.ts +6 -4
  520. package/src/core/executions/__tests__/atoms.test.ts +99 -0
  521. package/src/core/executions/__tests__/freshness.test.ts +482 -0
  522. package/src/core/executions/__tests__/hooks.test.tsx +106 -0
  523. package/src/core/executions/__tests__/select.test.ts +268 -0
  524. package/src/core/executions/atoms.ts +228 -0
  525. package/src/core/executions/freshness.ts +171 -0
  526. package/src/core/executions/hooks.ts +47 -0
  527. package/src/core/executions/index.ts +33 -0
  528. package/src/core/executions/select.ts +175 -0
  529. package/src/core/export/__tests__/hooks.test.ts +0 -5
  530. package/src/core/export/hooks.ts +1 -1
  531. package/src/core/export/layout.ts +2 -2
  532. package/src/core/hotkeys/actions.ts +2 -4
  533. package/src/core/hotkeys/hotkeys.ts +2 -1
  534. package/src/core/islands/__tests__/bootstrap.test.ts +69 -17
  535. package/src/core/islands/__tests__/bridge.test.ts +85 -27
  536. package/src/core/islands/bootstrap.ts +49 -54
  537. package/src/core/islands/bridge.ts +84 -25
  538. package/src/core/islands/components/__tests__/IslandControls.test.tsx +7 -5
  539. package/src/core/islands/components/__tests__/web-components.test.tsx +63 -0
  540. package/src/core/islands/components/output-wrapper.tsx +5 -5
  541. package/src/core/islands/components/web-components.tsx +12 -1
  542. package/src/core/islands/worker/__tests__/controller.test.ts +62 -4
  543. package/src/core/islands/worker/controller.ts +4 -10
  544. package/src/core/islands/worker/worker.tsx +33 -33
  545. package/src/core/kernel/__tests__/RuntimeState.test.ts +1 -1
  546. package/src/core/kernel/__tests__/handlers.test.ts +7 -153
  547. package/src/core/kernel/handlers.ts +13 -79
  548. package/src/core/kernel/state.ts +0 -15
  549. package/src/core/lifecycle/render-policy.ts +12 -26
  550. package/src/core/meta/__tests__/code-visibility.test.tsx +78 -70
  551. package/src/core/meta/code-visibility.ts +18 -9
  552. package/src/core/network/__tests__/connection.test.ts +1 -1
  553. package/src/core/network/__tests__/requests-lazy.test.ts +6 -8
  554. package/src/core/network/connection-notice.ts +1 -1
  555. package/src/core/network/connection.ts +1 -1
  556. package/src/core/network/requests-lazy.ts +5 -8
  557. package/src/core/network/requests-network.ts +5 -31
  558. package/src/core/network/requests-static.ts +1 -4
  559. package/src/core/network/requests-toasting.tsx +1 -4
  560. package/src/core/network/types.ts +6 -14
  561. package/src/core/network/useConnectionNotice.ts +8 -2
  562. package/src/core/notebook/__tests__/operations.test.ts +51 -0
  563. package/src/core/notebook/attachments.ts +38 -0
  564. package/src/core/notebook/document/__tests__/codemirror.test.ts +759 -0
  565. package/src/core/notebook/document/__tests__/draft.test.ts +363 -0
  566. package/src/core/notebook/document/__tests__/fixtures.ts +92 -0
  567. package/src/core/notebook/document/__tests__/hooks.test.tsx +391 -0
  568. package/src/core/notebook/document/__tests__/lifecycle-scenarios.test.ts +61 -0
  569. package/src/core/notebook/document/__tests__/model.test.ts +247 -0
  570. package/src/core/notebook/document/__tests__/protocol-fixtures.ts +38 -0
  571. package/src/core/notebook/document/__tests__/recovery-scenarios.test.ts +230 -0
  572. package/src/core/notebook/document/__tests__/scenario-fixture.ts +43 -0
  573. package/src/core/notebook/document/__tests__/scenarios.test.ts +205 -0
  574. package/src/core/notebook/document/__tests__/state.test.ts +459 -0
  575. package/src/core/notebook/document/__tests__/submission.test.ts +203 -0
  576. package/src/core/notebook/document/__tests__/test-host.test.ts +92 -0
  577. package/src/core/notebook/document/__tests__/test-host.ts +247 -0
  578. package/src/core/notebook/document/__tests__/test-notebook.ts +149 -0
  579. package/src/core/notebook/document/__tests__/user.ts +61 -0
  580. package/src/core/notebook/document/codemirror.ts +216 -0
  581. package/src/core/notebook/document/draft.ts +502 -0
  582. package/src/core/notebook/document/hooks.tsx +118 -0
  583. package/src/core/notebook/document/index.ts +24 -0
  584. package/src/core/notebook/document/model.ts +102 -0
  585. package/src/core/notebook/document/select.ts +41 -0
  586. package/src/core/notebook/document/state.ts +378 -0
  587. package/src/core/notebook/document/sync.ts +369 -0
  588. package/src/core/notebook/index.ts +19 -0
  589. package/src/core/notebook/operations.ts +30 -0
  590. package/src/core/notebook/replica/AGENTS.md +11 -0
  591. package/src/core/{host → notebook/replica}/__tests__/attachments.test.ts +9 -10
  592. package/src/core/{host → notebook/replica}/__tests__/document.test.ts +18 -16
  593. package/src/core/notebook/replica/__tests__/executions.test.ts +200 -0
  594. package/src/core/notebook/replica/__tests__/fixtures.ts +79 -0
  595. package/src/core/notebook/replica/__tests__/replica.test.ts +559 -0
  596. package/src/core/notebook/replica/__tests__/results.test.ts +193 -0
  597. package/src/core/notebook/replica/__tests__/runtime.test.ts +78 -0
  598. package/src/core/notebook/replica/backend.ts +19 -0
  599. package/src/core/notebook/replica/connection.ts +42 -0
  600. package/src/core/notebook/replica/index.ts +20 -0
  601. package/src/core/notebook/replica/replica.ts +336 -0
  602. package/src/core/{host → notebook/replica}/resources/attachments.ts +6 -3
  603. package/src/core/{host → notebook/replica}/resources/document.ts +3 -3
  604. package/src/core/notebook/replica/resources/executions.ts +157 -0
  605. package/src/core/notebook/replica/resources/results.ts +48 -0
  606. package/src/core/notebook/replica/resources/runtime.ts +14 -0
  607. package/src/core/packages/__tests__/useSandboxController.test.tsx +1 -1
  608. package/src/core/packages/useSandboxController.ts +1 -1
  609. package/src/core/run-app.tsx +49 -51
  610. package/src/core/runtime/__tests__/adapter.test.ts +4 -4
  611. package/src/core/runtime/__tests__/createWsUrl.test.ts +77 -7
  612. package/src/core/runtime/__tests__/runtime.test.ts +32 -74
  613. package/src/core/runtime/adapter.ts +5 -5
  614. package/src/core/runtime/config.ts +2 -2
  615. package/src/core/runtime/runtime.ts +33 -46
  616. package/src/core/runtime/types.ts +0 -2
  617. package/src/core/saving/__tests__/document.test.tsx +123 -0
  618. package/src/core/saving/__tests__/state.test.ts +111 -0
  619. package/src/core/saving/__tests__/useAutoSave.test.tsx +67 -0
  620. package/src/core/saving/document.ts +33 -0
  621. package/src/core/saving/filename.ts +1 -1
  622. package/src/core/saving/save-component.tsx +39 -60
  623. package/src/core/saving/state.ts +38 -39
  624. package/src/core/saving/useAutoSave.ts +17 -53
  625. package/src/core/session/__tests__/backend.test.ts +236 -0
  626. package/src/core/session/__tests__/useNotebookReplica.hook.test.tsx +186 -0
  627. package/src/core/{websocket → session}/__tests__/useNotebookSession.hook.test.tsx +247 -262
  628. package/src/core/session/active-notebook.ts +28 -0
  629. package/src/core/session/backend.ts +123 -0
  630. package/src/core/session/embedded.ts +7 -0
  631. package/src/core/{websocket → session}/types.ts +2 -2
  632. package/src/core/session/useNotebookReplica.ts +74 -0
  633. package/src/core/{websocket → session}/useNotebookSession.tsx +80 -67
  634. package/src/core/state/__tests__/jotai.test.tsx +108 -0
  635. package/src/core/state/jotai.ts +1 -1
  636. package/src/core/static/__tests__/files.test.ts +38 -10
  637. package/src/core/static/files.ts +2 -0
  638. package/src/core/{websocket → transports}/__tests__/connection-state.test.ts +1 -13
  639. package/src/core/transports/__tests__/server.test.ts +408 -0
  640. package/src/core/transports/__tests__/static.test.ts +306 -0
  641. package/src/core/transports/__tests__/wasm.test.ts +166 -0
  642. package/src/core/{websocket → transports}/connection-state.ts +9 -16
  643. package/src/core/transports/server.ts +152 -0
  644. package/src/core/transports/static.ts +166 -0
  645. package/src/core/transports/wasm.ts +97 -0
  646. package/src/core/vscode/__tests__/vscode-bindings.test.ts +125 -0
  647. package/src/core/vscode/vscode-bindings.ts +14 -2
  648. package/src/core/wasm/__tests__/bridge.test.ts +210 -64
  649. package/src/core/wasm/__tests__/worker.test.ts +188 -0
  650. package/src/core/wasm/bridge.ts +120 -73
  651. package/src/core/wasm/rpc.ts +15 -3
  652. package/src/core/wasm/store.ts +3 -3
  653. package/src/core/wasm/worker/bootstrap.ts +55 -51
  654. package/src/core/wasm/worker/getMarimoWheel.ts +1 -1
  655. package/src/core/wasm/worker/save-worker.ts +9 -10
  656. package/src/core/wasm/worker/types.ts +30 -18
  657. package/src/core/wasm/worker/worker.ts +118 -72
  658. package/src/css/app/Cell.css +7 -36
  659. package/src/css/app/codemirror.css +1 -1
  660. package/src/css/common.css +1 -1
  661. package/src/css/globals.css +72 -24
  662. package/src/hooks/__tests__/useAsyncData.test.tsx +148 -0
  663. package/src/hooks/__tests__/useDebounce.test.tsx +51 -0
  664. package/src/hooks/__tests__/useDeepCompareMemoize.test.tsx +39 -0
  665. package/src/hooks/__tests__/useDelayElapsed.test.tsx +28 -0
  666. package/src/hooks/__tests__/useInternalStateWithSync.test.tsx +20 -0
  667. package/src/hooks/__tests__/useScript.test.tsx +77 -0
  668. package/src/hooks/__tests__/useStateForKey.test.tsx +257 -0
  669. package/src/hooks/useAsyncData.ts +3 -3
  670. package/src/hooks/useDataSourceDiscovery.ts +6 -4
  671. package/src/hooks/useDebounce.ts +6 -10
  672. package/src/hooks/useDeepCompareMemoize.ts +1 -1
  673. package/src/hooks/useDelayElapsed.ts +14 -10
  674. package/src/hooks/useElapsedTime.ts +3 -3
  675. package/src/hooks/useEventListener.ts +1 -2
  676. package/src/hooks/useInputHistory.ts +4 -7
  677. package/src/hooks/useInternalStateWithSync.ts +6 -6
  678. package/src/hooks/useResizeObserver.ts +4 -7
  679. package/src/hooks/useScript.ts +67 -70
  680. package/src/hooks/useStateForKey.ts +93 -0
  681. package/src/mount.tsx +20 -15
  682. package/src/plugins/__tests__/plugin-object-schemas.test.ts +104 -0
  683. package/src/plugins/core/RenderHTML.tsx +3 -5
  684. package/src/plugins/core/__test__/RenderHTML-copy.test.tsx +60 -0
  685. package/src/plugins/core/registerReactComponent.tsx +5 -14
  686. package/src/plugins/impl/CodeEditorPlugin.tsx +1 -1
  687. package/src/plugins/impl/DataEditorPlugin.tsx +34 -13
  688. package/src/plugins/impl/DataTablePlugin.tsx +69 -37
  689. package/src/plugins/impl/DropdownPlugin.tsx +2 -6
  690. package/src/plugins/impl/FileBrowserPlugin.tsx +4 -16
  691. package/src/plugins/impl/FormPlugin.tsx +1 -1
  692. package/src/plugins/impl/RangeSliderPlugin.tsx +16 -2
  693. package/src/plugins/impl/RefreshPlugin.tsx +1 -0
  694. package/src/plugins/impl/SliderPlugin.tsx +6 -8
  695. package/src/plugins/impl/__tests__/DataEditorPlugin.test.ts +93 -4
  696. package/src/plugins/impl/__tests__/DataTablePlugin.test.tsx +387 -1
  697. package/src/plugins/impl/__tests__/FileBrowserPlugin.test.tsx +45 -0
  698. package/src/plugins/impl/__tests__/RangeSliderPlugin.test.tsx +109 -0
  699. package/src/plugins/impl/__tests__/SliderPlugin.test.tsx +24 -3
  700. package/src/plugins/impl/anywidget/__tests__/registry.test.ts +153 -0
  701. package/src/plugins/impl/anywidget/__tests__/widget-binding.test.ts +241 -2
  702. package/src/plugins/impl/anywidget/model.ts +3 -1
  703. package/src/plugins/impl/anywidget/registry.ts +18 -14
  704. package/src/plugins/impl/anywidget/runtime.ts +21 -9
  705. package/src/plugins/impl/anywidget/widget-binding.ts +160 -82
  706. package/src/plugins/impl/chat/__tests__/chat-prompts.test.tsx +93 -0
  707. package/src/plugins/impl/chat/chat-ui.tsx +17 -15
  708. package/src/plugins/impl/code/any-language-editor.tsx +2 -2
  709. package/src/plugins/impl/common/error-banner.tsx +5 -3
  710. package/src/plugins/impl/data-editor/__tests__/column-types.test.ts +42 -0
  711. package/src/plugins/impl/data-editor/__tests__/editor-state.test.ts +52 -1
  712. package/src/plugins/impl/data-editor/__tests__/glide-data-editor.test.tsx +120 -4
  713. package/src/plugins/impl/data-editor/__tests__/glide-utils.test.ts +116 -0
  714. package/src/plugins/impl/data-editor/column-types.ts +55 -0
  715. package/src/plugins/impl/data-editor/editor-state.ts +18 -2
  716. package/src/plugins/impl/data-editor/glide-data-editor.tsx +74 -12
  717. package/src/plugins/impl/data-editor/glide-utils.ts +39 -38
  718. package/src/plugins/impl/data-editor/types.ts +5 -0
  719. package/src/plugins/impl/data-explorer/ConnectedDataExplorerComponent.tsx +1 -1
  720. package/src/plugins/impl/data-explorer/components/column-summary.tsx +4 -2
  721. package/src/plugins/impl/data-explorer/state/reducer.ts +1 -1
  722. package/src/plugins/impl/data-frames/DataFramePlugin.tsx +1 -2
  723. package/src/plugins/impl/data-frames/__tests__/sidebar.test.tsx +160 -0
  724. package/src/plugins/impl/data-frames/forms/__tests__/__snapshots__/form.test.tsx.snap +66 -66
  725. package/src/plugins/impl/data-frames/panel.tsx +44 -16
  726. package/src/plugins/impl/mpl-interactive/MplInteractivePlugin.tsx +5 -3
  727. package/src/plugins/impl/panel/PanelPlugin.tsx +16 -17
  728. package/src/plugins/impl/panel/__tests__/utils.test.ts +39 -1
  729. package/src/plugins/impl/panel/utils.ts +17 -0
  730. package/src/plugins/impl/plotly/PlotlyPlugin.tsx +2 -5
  731. package/src/plugins/impl/plotly/selection.ts +25 -19
  732. package/src/plugins/impl/vega/VegaPlugin.tsx +2 -3
  733. package/src/plugins/impl/vega/make-selectable.ts +4 -7
  734. package/src/plugins/layout/DownloadPlugin.tsx +7 -11
  735. package/src/plugins/layout/RoutesPlugin.tsx +1 -1
  736. package/src/plugins/layout/__test__/DownloadPlugin.test.tsx +205 -0
  737. package/src/stories/__tests__/editor-story.test.tsx +33 -0
  738. package/src/stories/button.stories.tsx +1 -0
  739. package/src/stories/cell-status.stories.tsx +29 -24
  740. package/src/stories/cell.stories.tsx +46 -46
  741. package/src/stories/data-table.stories.tsx +31 -0
  742. package/src/stories/editor.stories.tsx +24 -17
  743. package/src/stories/form-wrapper.stories.tsx +2 -2
  744. package/src/stories/layout/vertical/one-column.stories.tsx +28 -42
  745. package/src/stories/runtime-story.tsx +23 -17
  746. package/src/stories/select.stories.tsx +2 -2
  747. package/src/stories/switchable-multi-select.stories.tsx +1 -1
  748. package/src/theme/__tests__/islands-theme.test.tsx +276 -0
  749. package/src/theme/namespace.tsx +4 -3
  750. package/src/theme/useTheme.ts +71 -41
  751. package/src/utils/__tests__/arrays.test.ts +35 -0
  752. package/src/utils/__tests__/batch-requests.test.ts +3 -3
  753. package/src/utils/__tests__/{createReducer.test.ts → createReducer.test.tsx} +127 -1
  754. package/src/utils/__tests__/download.test.tsx +183 -23
  755. package/src/utils/__tests__/numbers.test.ts +105 -1
  756. package/src/utils/__tests__/objects.test.ts +21 -0
  757. package/src/utils/arrays.ts +11 -2
  758. package/src/utils/blob.ts +1 -1
  759. package/src/utils/createReducer.ts +115 -79
  760. package/src/utils/download.ts +67 -6
  761. package/src/utils/maps.ts +0 -3
  762. package/src/utils/numbers.ts +79 -18
  763. package/src/utils/objects.ts +4 -9
  764. package/src/utils/time.ts +10 -0
  765. package/src/utils/tracer.ts +9 -5
  766. package/src/utils/zod-utils.ts +1 -3
  767. package/dist/_baseMerge-BiGRwuqv.js +0 -165
  768. package/dist/any-language-editor-D4q-IFcM.js +0 -76
  769. package/dist/assets/__vite-browser-external-BXYkiFsk.js +0 -1
  770. package/dist/assets/worker-HPY9fbhz.js +0 -114
  771. package/dist/feedback-button-g9eH5l7Q.js +0 -379
  772. package/dist/hasIn-o2Us0uVx.js +0 -132
  773. package/dist/html-to-image-B5H-xKRH.js +0 -3251
  774. package/dist/isArrayLikeObject-BZl-15ir.js +0 -450
  775. package/dist/isEmpty-BSZ1LaUo.js +0 -35
  776. package/dist/isSymbol-kQcfYbNX.js +0 -8
  777. package/dist/label-DoysmLMW.js +0 -281
  778. package/dist/pick-CJeoxYOS.js +0 -51
  779. package/dist/select-DemoKT4G.js +0 -1344
  780. package/dist/toDate-BvdkR0aH.js +0 -1185
  781. package/dist/toast-PkdZraM8.js +0 -1830
  782. package/dist/use-restore-focus-CKjfFjLM.js +0 -6369
  783. package/dist/useLifecycle-Dfq8UD-b.js +0 -169
  784. package/dist/useTheme-Bu5bBgrh.js +0 -904
  785. package/src/components/chat/reasoning-accordion.tsx +0 -61
  786. package/src/components/chat/tool-call/tool-error-card.tsx +0 -81
  787. package/src/components/chat/tool-call/tool-history-row.tsx +0 -174
  788. package/src/components/editor/ai/__tests__/staged-cell-submission.test.ts +0 -106
  789. package/src/components/editor/ai/add-cell-with-ai.tsx +0 -506
  790. package/src/components/editor/ai/staged-cell-submission.ts +0 -46
  791. package/src/components/editor/cell/__tests__/StagedAICell.test.tsx +0 -64
  792. package/src/components/editor/cell/code/__tests__/rtc-editor-config.test.ts +0 -50
  793. package/src/components/editor/chrome/wrapper/footer-items/rtc-status.tsx +0 -65
  794. package/src/components/editor/navigation/__tests__/state.test.ts +0 -81
  795. package/src/components/editor/navigation/state.ts +0 -65
  796. package/src/components/icons/loading-ellipsis.tsx +0 -46
  797. package/src/core/ai/tools/__tests__/run-cells-tool.test.ts +0 -656
  798. package/src/core/ai/tools/run-cells-tool.ts +0 -303
  799. package/src/core/attachments/state.ts +0 -18
  800. package/src/core/cells/__tests__/apply-transaction.test.ts +0 -991
  801. package/src/core/cells/__tests__/document-changes.test.ts +0 -1140
  802. package/src/core/cells/__tests__/document-roundtrip.test.ts +0 -392
  803. package/src/core/cells/document-changes.ts +0 -944
  804. package/src/core/codemirror/rtc/extension.ts +0 -453
  805. package/src/core/codemirror/rtc/loro/__tests__/sync.test.ts +0 -52
  806. package/src/core/codemirror/rtc/loro/awareness.ts +0 -531
  807. package/src/core/codemirror/rtc/loro/colors.ts +0 -38
  808. package/src/core/codemirror/rtc/loro/sync.ts +0 -168
  809. package/src/core/host/AGENTS.md +0 -11
  810. package/src/core/host/__tests__/events.test.ts +0 -46
  811. package/src/core/host/__tests__/fixtures.ts +0 -39
  812. package/src/core/host/__tests__/notebook-client.test.ts +0 -433
  813. package/src/core/host/__tests__/protocol.test.ts +0 -214
  814. package/src/core/host/__tests__/stream.test.ts +0 -209
  815. package/src/core/host/connection.ts +0 -81
  816. package/src/core/host/events.ts +0 -61
  817. package/src/core/host/notebook-client.ts +0 -290
  818. package/src/core/host/protocol.ts +0 -1945
  819. package/src/core/host/resources/resource.ts +0 -47
  820. package/src/core/host/stream.ts +0 -211
  821. package/src/core/rtc/state.ts +0 -34
  822. package/src/core/state/__tests__/jotai.test.ts +0 -25
  823. package/src/core/wasm/worker/message-buffer.ts +0 -33
  824. package/src/core/websocket/__tests__/createConnectionTransport.test.ts +0 -49
  825. package/src/core/websocket/__tests__/useNotebookClient.hook.test.tsx +0 -170
  826. package/src/core/websocket/state.ts +0 -7
  827. package/src/core/websocket/transports/__tests__/basic.test.ts +0 -275
  828. package/src/core/websocket/transports/__tests__/sse.test.ts +0 -335
  829. package/src/core/websocket/transports/__tests__/transport.test.ts +0 -308
  830. package/src/core/websocket/transports/__tests__/ws.test.ts +0 -125
  831. package/src/core/websocket/transports/basic.ts +0 -102
  832. package/src/core/websocket/transports/create.ts +0 -31
  833. package/src/core/websocket/transports/sse.ts +0 -308
  834. package/src/core/websocket/transports/transport.ts +0 -50
  835. package/src/core/websocket/transports/ws.ts +0 -98
  836. package/src/core/websocket/useNotebookClient.ts +0 -88
  837. package/src/utils/__tests__/id-tree.test.ts +0 -2145
  838. package/src/utils/id-tree.tsx +0 -1134
  839. /package/src/{core/attachments/toast.ts → components/editor/agent-toast.ts} +0 -0
  840. /package/src/core/{websocket → session}/connection-utils.ts +0 -0
@@ -1,1134 +0,0 @@
1
- /* Copyright 2026 Marimo. All rights reserved. */
2
-
3
- import { Memoize } from "typescript-memoize";
4
- import { reorderColumnSizes } from "@/components/editor/columns/storage";
5
- import { SETUP_CELL_ID } from "@/core/cells/ids";
6
- import { arrayDelete, arrayInsert, arrayInsertMany, arrayMove } from "./arrays";
7
- import { Logger } from "./Logger";
8
-
9
- /**
10
- * Branded number to help with type safety
11
- */
12
- export type CellColumnIndex = number & { __brand: "CellColumnIndex" };
13
-
14
- /**
15
- * Branded string to help with type safety
16
- */
17
- export type CellColumnId = string & { __brand: "CellColumnId" };
18
- /**
19
- * Weakly-branded number, since making `__brand` required causes type errors
20
- */
21
- export type CellIndex = number & { __brand?: "CellIndex" };
22
-
23
- /**
24
- * Tree data structure for handling ids with nested children
25
- */
26
- export class TreeNode<T> {
27
- public value: T;
28
- public isCollapsed: boolean;
29
- public children: TreeNode<T>[];
30
-
31
- public constructor(value: T, isCollapsed: boolean, children: TreeNode<T>[]) {
32
- this.value = value;
33
- this.isCollapsed = isCollapsed;
34
- this.children = children;
35
- }
36
-
37
- /**
38
- * Recursively count the number of nodes in the tree
39
- */
40
- @Memoize()
41
- public geDescendantCount(): number {
42
- let count = 0;
43
- const stack = [...this.children];
44
-
45
- while (stack.length > 0) {
46
- // oxlint-disable-next-line typescript/no-non-null-assertion
47
- const node = stack.pop()!;
48
- count++;
49
-
50
- // Add children to stack
51
- for (let i = node.children.length - 1; i >= 0; i--) {
52
- stack.push(node.children[i]);
53
- }
54
- }
55
-
56
- return count;
57
- }
58
-
59
- @Memoize()
60
- public getDescendants(): T[] {
61
- const result: T[] = [];
62
- const stack = [...this.children];
63
-
64
- while (stack.length > 0) {
65
- // oxlint-disable-next-line typescript/no-non-null-assertion
66
- const node = stack.pop()!;
67
- result.push(node.value);
68
-
69
- // Add children to stack in reverse order to maintain correct traversal order
70
- for (let i = node.children.length - 1; i >= 0; i--) {
71
- stack.push(node.children[i]);
72
- }
73
- }
74
-
75
- return result;
76
- }
77
-
78
- @Memoize()
79
- public get inOrderIds(): T[] {
80
- const result: T[] = [];
81
-
82
- // Use depth-first traversal to preserve logical document order
83
- const traverse = (node: TreeNode<T>) => {
84
- result.push(node.value);
85
- for (const child of node.children) {
86
- traverse(child);
87
- }
88
- };
89
-
90
- for (const child of this.children) {
91
- traverse(child);
92
- }
93
-
94
- return result;
95
- }
96
-
97
- public toString(): string {
98
- if (this.isCollapsed) {
99
- return `${this.value} (collapsed)`;
100
- }
101
- return String(this.value);
102
- }
103
-
104
- public equals(other: TreeNode<T>): boolean {
105
- return this.value === other.value;
106
- }
107
- }
108
-
109
- let uniqueId = 0;
110
-
111
- export class CollapsibleTree<T> {
112
- public readonly nodes: TreeNode<T>[];
113
- public readonly id: CellColumnId;
114
-
115
- private constructor(nodes: TreeNode<T>[], id: CellColumnId) {
116
- this.nodes = nodes;
117
- this.id = id;
118
- }
119
-
120
- public static from<T>(ids: T[]): CollapsibleTree<T> {
121
- const id = `tree_${uniqueId++}` as CellColumnId;
122
- return new CollapsibleTree(
123
- ids.map((id) => new TreeNode(id, false, [])),
124
- id,
125
- );
126
- }
127
-
128
- /**
129
- * Create a new tree from ids, preserving structure from previous tree if possible
130
- */
131
- public static fromWithPreviousShape<T>(
132
- ids: T[],
133
- previousTree?: CollapsibleTree<T>,
134
- ): CollapsibleTree<T> {
135
- if (!previousTree) {
136
- return CollapsibleTree.from(ids);
137
- }
138
-
139
- // Reuse the previous tree's id if possible
140
- const id = previousTree.id;
141
-
142
- // Create new tree with nothing collapsed
143
- let newTree = new CollapsibleTree(
144
- ids.map((id) => new TreeNode(id, false, [])),
145
- id,
146
- );
147
-
148
- // Collapse nodes that were collapsed in the previous tree
149
- for (const id of ids) {
150
- if (previousTree.isCollapsed(id)) {
151
- const children = previousTree._nodeMap.get(id)?.children ?? [];
152
- // Find the first child that is also in the new tree, going backwards
153
- for (let i = children.length - 1; i >= 0; i--) {
154
- const child = children[i];
155
- if (newTree._nodeMap.has(child.value)) {
156
- newTree = newTree.collapse(id, child.value);
157
- break;
158
- }
159
- }
160
- }
161
- }
162
-
163
- return newTree;
164
- }
165
-
166
- public withNodes(nodes: TreeNode<T>[]): CollapsibleTree<T> {
167
- return new CollapsibleTree(nodes, this.id);
168
- }
169
-
170
- @Memoize()
171
- public get topLevelIds(): T[] {
172
- return this.nodes.map((n) => n.value);
173
- }
174
-
175
- @Memoize()
176
- public get inOrderIds(): T[] {
177
- return this.nodes.flatMap((n) => [n.value, ...n.inOrderIds]);
178
- }
179
-
180
- @Memoize()
181
- public get idSet(): Set<T> {
182
- return new Set(this.inOrderIds);
183
- }
184
-
185
- public get length(): number {
186
- return this.nodes.length;
187
- }
188
-
189
- @Memoize()
190
- public get _nodeMap(): Map<T, TreeNode<T>> {
191
- const result = new Map<T, TreeNode<T>>();
192
- for (const node of this.nodes) {
193
- result.set(node.value, node);
194
- }
195
- return result;
196
- }
197
-
198
- /**
199
- * Get the descendants of the given node
200
- *
201
- * Only works for the top-level nodes
202
- */
203
- public getDescendants(id: T): T[] {
204
- const node = this._nodeMap.get(id);
205
- if (!node) {
206
- Logger.warn(
207
- `Node ${id} not found in tree. Valid ids: ${this.topLevelIds}`,
208
- );
209
- return [];
210
- }
211
- return node.getDescendants();
212
- }
213
-
214
- /**
215
- * Check if the given node is collapsed
216
- *
217
- * Only works for the top-level nodes
218
- */
219
- public isCollapsed(id: T): boolean {
220
- const node = this._nodeMap.get(id);
221
- if (!node) {
222
- Logger.warn(
223
- `Node ${id} not found in tree. Valid ids: ${this.topLevelIds}`,
224
- );
225
- return false;
226
- }
227
- return node.isCollapsed;
228
- }
229
-
230
- /**
231
- * Get the index of the given node, or throw
232
- */
233
- public indexOfOrThrow(id: T): CellIndex {
234
- const index = this.nodes.findIndex((n) => n.value === id);
235
- if (index === -1) {
236
- throw new Error(
237
- `Node ${id} not found in tree. Valid ids: ${this.topLevelIds}`,
238
- );
239
- }
240
- return index as CellIndex;
241
- }
242
-
243
- /**
244
- * Get the top level nodes in the given range.
245
- * This does not include descendants.
246
- */
247
- public slice(start: number, end: number): T[] {
248
- return this.nodes.slice(start, end).map((n) => n.value);
249
- }
250
-
251
- /**
252
- * Move the given node to the front
253
- */
254
- public moveToFront(id: T): CollapsibleTree<T> {
255
- const index = this.indexOfOrThrow(id);
256
- return this.withNodes(arrayMove(this.nodes, index, 0));
257
- }
258
-
259
- /**
260
- * Move the given node to the back
261
- */
262
- public moveToBack(id: T): CollapsibleTree<T> {
263
- const index = this.indexOfOrThrow(id);
264
- return this.withNodes(arrayMove(this.nodes, index, this.nodes.length - 1));
265
- }
266
-
267
- /**
268
- * Collapse everything past the given node @param id
269
- * until @param until or the end of the tree
270
- */
271
- public collapse(id: T, until: T | undefined): CollapsibleTree<T> {
272
- const nodeIndex = this.nodes.findIndex((n) => n.value === id);
273
- if (nodeIndex === -1) {
274
- throw new Error(
275
- `Node ${id} not found in tree. Valid ids: ${this.topLevelIds}`,
276
- );
277
- }
278
-
279
- const untilIndex =
280
- until === undefined
281
- ? this.nodes.length
282
- : this.nodes.findIndex((n) => n.value === until);
283
-
284
- if (untilIndex === -1) {
285
- throw new Error(`Node ${until} not found in tree`);
286
- }
287
- if (untilIndex < nodeIndex) {
288
- throw new Error(`Node ${until} is before node ${id}`);
289
- }
290
-
291
- const nodes = [...this.nodes];
292
- const node = nodes[nodeIndex];
293
- if (node.isCollapsed) {
294
- throw new Error(`Node ${id} is already collapsed`);
295
- }
296
-
297
- // Fold the next nodes into the current node
298
- const children = nodes.splice(nodeIndex + 1, untilIndex - nodeIndex);
299
- nodes[nodeIndex] = new TreeNode(node.value, true, children);
300
-
301
- return this.withNodes(nodes);
302
- }
303
-
304
- /**
305
- * Collapse all nodes in the tree, including nested ones
306
- *
307
- * Only works for the top-level nodes
308
- * Does not collapse the children of already collapsed nodes
309
- */
310
- public collapseAll(
311
- collapseRanges: ({ id: T; until: T | undefined } | null)[],
312
- ): CollapsibleTree<T> {
313
- const nodes = [...this.nodes];
314
- if (collapseRanges.length === 0) {
315
- throw new Error("No collapse ranges provided");
316
- }
317
-
318
- if (collapseRanges.length !== nodes.length) {
319
- throw new Error(
320
- `Collapse ranges length ${collapseRanges.length} does not match tree length ${nodes.length}`,
321
- );
322
- }
323
-
324
- // Start from the end of the list and collapse nodes children first
325
- let nodeIndex = nodes.length - 1;
326
- while (nodeIndex >= 0) {
327
- const node = nodes[nodeIndex];
328
- const range = collapseRanges[nodeIndex];
329
-
330
- if (!node.isCollapsed && range) {
331
- const { id, until } = range;
332
- if (id !== node.value) {
333
- throw new Error(
334
- `Node ${node.value} does not match collapse range id ${id}`,
335
- );
336
- }
337
- const untilIndex =
338
- until === undefined
339
- ? nodes.length
340
- : nodes.findIndex((n) => n.value === until);
341
-
342
- if (untilIndex === -1) {
343
- throw new Error(`Node ${until} not found in tree`);
344
- }
345
- if (untilIndex < nodeIndex) {
346
- throw new Error(`Node ${until} is before node ${id}`);
347
- }
348
-
349
- // Fold the next nodes into the current node
350
- const children = nodes.splice(nodeIndex + 1, untilIndex - nodeIndex);
351
- nodes[nodeIndex] = new TreeNode(node.value, true, children);
352
- nodeIndex--;
353
- } else {
354
- // Move to the next node
355
- nodeIndex--;
356
- }
357
- }
358
-
359
- return this.withNodes(nodes);
360
- }
361
-
362
- /**
363
- * Expand a node and all of its children.
364
- * If the node is already expanded, returns the same tree (no-op).
365
- */
366
- public expand(id: T): CollapsibleTree<T> {
367
- const nodeIndex = this.nodes.findIndex((n) => n.value === id);
368
- if (nodeIndex === -1) {
369
- throw new Error(
370
- `Node ${id} not found in tree. Valid ids: ${this.topLevelIds}`,
371
- );
372
- }
373
-
374
- let nodes = [...this.nodes];
375
- const node = nodes[nodeIndex];
376
- if (!node.isCollapsed) {
377
- // Already expanded, no-op
378
- return this;
379
- }
380
-
381
- nodes[nodeIndex] = new TreeNode(node.value, false, []);
382
- nodes = arrayInsertMany(nodes, nodeIndex + 1, node.children);
383
-
384
- return this.withNodes(nodes);
385
- }
386
-
387
- /**
388
- * Expand all collapsed nodes in the tree, including nested ones
389
- */
390
- public expandAll(): CollapsibleTree<T> {
391
- let nodes = [...this.nodes];
392
- let nodeIndex = 0;
393
-
394
- while (nodeIndex < nodes.length) {
395
- const node = nodes[nodeIndex];
396
- if (node.isCollapsed) {
397
- // Replace the collapsed node with an expanded one
398
- nodes[nodeIndex] = new TreeNode(node.value, false, []);
399
- // Add the children of the collapsed node to the list
400
- nodes = arrayInsertMany(nodes, nodeIndex + 1, node.children);
401
- nodeIndex++;
402
- } else {
403
- // Move to the next node
404
- nodeIndex++;
405
- }
406
- }
407
-
408
- return this.withNodes(nodes);
409
- }
410
-
411
- /**
412
- * Move a node from one index to another
413
- */
414
- public move(fromIdx: number, toIdx: number): CollapsibleTree<T> {
415
- return this.withNodes(arrayMove(this.nodes, fromIdx, toIdx));
416
- }
417
-
418
- /**
419
- * Get the node at the given index
420
- */
421
- public at(index: number): T | undefined {
422
- return this.nodes.at(index)?.value;
423
- }
424
-
425
- /**
426
- * Get the node at the given index
427
- */
428
- public atOrThrow(index: number): T {
429
- const node = this.nodes.at(index);
430
- if (node === undefined) {
431
- throw new Error(`Node at index ${index} not found in tree`);
432
- }
433
- return node.value;
434
- }
435
-
436
- /**
437
- * Get the first node, or throw
438
- */
439
- public first(): T {
440
- return this.atOrThrow(0);
441
- }
442
-
443
- /**
444
- * Get the last node, or throw
445
- */
446
- public last(): T {
447
- return this.atOrThrow(this.nodes.length - 1);
448
- }
449
-
450
- /**
451
- * Get the next node after the given node, does not wrap.
452
- */
453
- public after(id: T): T | undefined {
454
- const index = this.indexOfOrThrow(id);
455
- if (index === this.nodes.length - 1) {
456
- return undefined;
457
- }
458
- return this.at(index + 1);
459
- }
460
-
461
- /**
462
- * Get the previous node before the given node, does not wrap.
463
- */
464
- public before(id: T): T | undefined {
465
- const index = this.indexOfOrThrow(id);
466
- if (index === 0) {
467
- return undefined;
468
- }
469
- return this.at(index - 1);
470
- }
471
-
472
- /**
473
- * Insert a node at the given index
474
- */
475
- public insert(id: T, index: number): CollapsibleTree<T> {
476
- return this.withNodes(
477
- arrayInsert(this.nodes, index, new TreeNode(id, false, [])),
478
- );
479
- }
480
-
481
- /**
482
- * Insert a node at the end
483
- */
484
- public insertAtEnd(id: T): CollapsibleTree<T> {
485
- return this.insert(id, this.nodes.length);
486
- }
487
-
488
- /**
489
- * Insert a node at the start
490
- */
491
- public insertAtStart(id: T): CollapsibleTree<T> {
492
- return this.insert(id, 0);
493
- }
494
-
495
- /**
496
- * Delete a node, expand if it was collapsed
497
- */
498
- public deleteAtIndex(idx: number): CollapsibleTree<T> {
499
- const id = this.atOrThrow(idx);
500
- // Expand the node first (if collapsed) to bring children back to top level
501
- const tree = this.expand(id);
502
- return tree.withNodes(arrayDelete(tree.nodes, idx));
503
- }
504
-
505
- public delete(id: T): CollapsibleTree<T> {
506
- const index = this.indexOfOrThrow(id);
507
- return this.deleteAtIndex(index);
508
- }
509
-
510
- /**
511
- * Get the number of nodes in the tree, not-including the given node
512
- */
513
- public getCount(id: T): number {
514
- return this._nodeMap.get(id)?.geDescendantCount() ?? 0;
515
- }
516
-
517
- /**
518
- * Find and expand the node and all of its children
519
- */
520
- public findAndExpandDeep(id: T): CollapsibleTree<T> {
521
- const found = this.find(id);
522
- if (found.length === 0) {
523
- return this;
524
- }
525
- return found.reduce<CollapsibleTree<T>>(
526
- (acc, node) => acc.expand(node),
527
- this,
528
- );
529
- }
530
-
531
- /**
532
- * Find a node, returning the path to it
533
- * With the last element being the node itself
534
- */
535
- public find(id: T): T[] {
536
- // We need to recursively find the node
537
- function findNode(nodes: TreeNode<T>[], path: T[]): T[] {
538
- for (const node of nodes) {
539
- if (node.value === id) {
540
- return [...path, id];
541
- }
542
- const result = findNode(node.children, [...path, node.value]);
543
- if (result.length > 0) {
544
- return result;
545
- }
546
- }
547
- return [];
548
- }
549
-
550
- return findNode(this.nodes, []);
551
- }
552
-
553
- /**
554
- * Split the tree into two trees
555
- * @param id the id of the node to split at
556
- * @returns a tuple of the left and right trees
557
- */
558
- public split(id: T): [CollapsibleTree<T>, CollapsibleTree<T> | undefined] {
559
- const index = this.nodes.findIndex((n) => n.value === id);
560
- if (index === -1) {
561
- throw new Error(`Node ${id} not found in tree`);
562
- }
563
- const leftNodes = this.nodes.slice(0, index);
564
- const rightNodes = this.nodes.slice(index);
565
- if (leftNodes.length === 0) {
566
- return [CollapsibleTree.from<T>([]), this.withNodes(rightNodes)];
567
- }
568
- const left = this.withNodes(leftNodes);
569
- const right = CollapsibleTree.from<T>([]).withNodes(rightNodes);
570
- return [left, right];
571
- }
572
-
573
- public equals(other: CollapsibleTree<T>): boolean {
574
- return (
575
- this.nodes.length === other.nodes.length &&
576
- this.nodes.every((n, i) => n.value === other.nodes[i].value)
577
- );
578
- }
579
-
580
- public toString(): string {
581
- let depth = 0;
582
- let result = "";
583
- const asString = (nodes: TreeNode<T>[]) => {
584
- for (const node of nodes) {
585
- result += `${" ".repeat(depth * 2)}${node.toString()}\n`;
586
- depth += 1;
587
- asString(node.children);
588
- depth -= 1;
589
- }
590
- };
591
- asString(this.nodes);
592
- return result;
593
- }
594
- }
595
-
596
- export class MultiColumn<T> {
597
- private readonly columns: readonly CollapsibleTree<T>[];
598
-
599
- public constructor(columns: readonly CollapsibleTree<T>[]) {
600
- this.columns = columns;
601
-
602
- // Ensure there is always at least one column
603
- if (columns.length === 0) {
604
- this.columns = [CollapsibleTree.from([])];
605
- }
606
- }
607
-
608
- public static from<T>(idsList: T[][]): MultiColumn<T> {
609
- return new MultiColumn(idsList.map((ids) => CollapsibleTree.from(ids)));
610
- }
611
-
612
- /**
613
- * Create a new MultiColumn from idsList,
614
- * attempting to preserve structure from previous MultiColumn if possible.
615
- */
616
- public static fromWithPreviousShape<T>(
617
- idsList: T[],
618
- previousShape: MultiColumn<T>,
619
- ): MultiColumn<T> {
620
- if (!previousShape) {
621
- return MultiColumn.from([idsList]);
622
- }
623
-
624
- // Get previous columns for reference
625
- const previousColumns = previousShape.getColumns();
626
-
627
- // Split the ids into their respective columns
628
- const splitIds: T[][] = Array.from(
629
- { length: previousColumns.length },
630
- () => [],
631
- );
632
- let lastUsedColumnIdx = 0;
633
- for (const id of idsList) {
634
- const column = previousColumns.findIndex((c) => c.idSet.has(id));
635
- if (column === -1) {
636
- // No column found, use the last used column
637
- splitIds[lastUsedColumnIdx].push(id);
638
- } else {
639
- lastUsedColumnIdx = column;
640
- splitIds[column].push(id);
641
- }
642
- }
643
-
644
- const newColumns = splitIds.map((ids, idx) =>
645
- CollapsibleTree.fromWithPreviousShape(ids, previousColumns[idx]),
646
- );
647
-
648
- return new MultiColumn(newColumns);
649
- }
650
-
651
- @Memoize()
652
- public isEmpty(): boolean {
653
- if (this.columns.length === 0) {
654
- return true;
655
- }
656
- return this.columns.every((c) => c.nodes.length === 0);
657
- }
658
-
659
- public static fromIdsAndColumns<T>(
660
- idAndColumns: [T, number | undefined | null][],
661
- ): MultiColumn<T> {
662
- // If column is undefined, use the previous column
663
- // Ensure there is always at least one column
664
- const numColumns = Math.max(
665
- 1,
666
- ...idAndColumns.map(([, column]) => (column ?? 0) + 1),
667
- );
668
- const idsList: T[][] = Array.from({ length: numColumns }, () => []);
669
-
670
- let prevColumn = 0;
671
- for (const [id, column] of idAndColumns) {
672
- // Avoid negative column indices
673
- if (column === undefined || column === null || column < 0) {
674
- idsList[prevColumn].push(id);
675
- } else {
676
- idsList[column].push(id);
677
- prevColumn = column;
678
- }
679
- }
680
-
681
- return MultiColumn.from(idsList);
682
- }
683
-
684
- @Memoize()
685
- public get topLevelIds(): T[][] {
686
- return this.columns.map((c) => c.topLevelIds);
687
- }
688
-
689
- public get iterateTopLevelIds(): Iterable<T> {
690
- const columns = this.columns;
691
-
692
- function* iter() {
693
- for (const column of columns) {
694
- for (const id of column.topLevelIds) {
695
- yield id;
696
- }
697
- }
698
- }
699
-
700
- return iter();
701
- }
702
-
703
- @Memoize()
704
- public get inOrderIds(): T[] {
705
- return this.columns.flatMap((c) => c.inOrderIds);
706
- }
707
-
708
- public get colLength(): number {
709
- return this.columns.length;
710
- }
711
-
712
- @Memoize()
713
- public get idLength(): number {
714
- return this.columns.reduce((acc, c) => acc + c.nodes.length, 0);
715
- }
716
-
717
- @Memoize()
718
- public get _columnMap(): Map<CellColumnId, CollapsibleTree<T>> {
719
- return new Map(this.columns.map((c) => [c.id, c]));
720
- }
721
-
722
- public at(idx: number): CollapsibleTree<T> | undefined {
723
- return this.columns[idx];
724
- }
725
-
726
- public get(columnId: CellColumnId): CollapsibleTree<T> | undefined {
727
- return this._columnMap.get(columnId);
728
- }
729
-
730
- public atOrThrow(idx: number): CollapsibleTree<T> {
731
- const column = this.columns[idx];
732
- if (!column) {
733
- throw new Error(`Column ${idx} not found`);
734
- }
735
- return column;
736
- }
737
-
738
- public hasOnlyOneColumn(): boolean {
739
- return this.columns.length === 1;
740
- }
741
-
742
- public getColumns(): readonly CollapsibleTree<T>[] {
743
- return this.columns;
744
- }
745
-
746
- public hasOnlyOneId(): boolean {
747
- return this.idLength === 1;
748
- }
749
-
750
- @Memoize()
751
- public getColumnIds(): CellColumnId[] {
752
- return this.columns.map((c) => c.id);
753
- }
754
-
755
- public indexOf(column: CollapsibleTree<T>): number {
756
- return this.columns.indexOf(column);
757
- }
758
-
759
- public addColumn(
760
- columnId: CellColumnId,
761
- initialIds: T[] = [],
762
- ): MultiColumn<T> {
763
- return new MultiColumn(
764
- this.columns.flatMap((c) => {
765
- if (c.id === columnId) {
766
- return [c, CollapsibleTree.from(initialIds)];
767
- }
768
- return [c];
769
- }),
770
- );
771
- }
772
-
773
- public insertBreakpoint(cellId: T): MultiColumn<T> {
774
- const column = this.findWithId(cellId);
775
- const [left, right] = column.split(cellId);
776
- const newColumns = this.columns.flatMap((c) => {
777
- if (c === column) {
778
- return [left, right].filter(Boolean);
779
- }
780
- return [c];
781
- });
782
- return new MultiColumn(newColumns);
783
- }
784
-
785
- public delete(columnId: CellColumnId): MultiColumn<T> {
786
- // Move cells to preceding column
787
- // If its the first column, move the cells to the next column
788
-
789
- // Noop if there is only one column
790
- if (this.columns.length <= 1) {
791
- return this;
792
- }
793
-
794
- const columnIndex = this.indexOfOrThrow(columnId);
795
- const targetColumnIndex = columnIndex === 0 ? 1 : columnIndex - 1;
796
-
797
- const columns = [...this.columns];
798
- const column = columns[columnIndex];
799
- columns[targetColumnIndex] = column.withNodes([
800
- ...columns[targetColumnIndex].nodes,
801
- ...column.nodes,
802
- ]);
803
- columns.splice(columnIndex, 1);
804
- return new MultiColumn(columns);
805
- }
806
-
807
- public mergeAllColumns(): MultiColumn<T> {
808
- if (this.columns.length <= 1) {
809
- return this;
810
- }
811
-
812
- const nodes = this.columns.flatMap((c) => c.nodes);
813
- const firstColumn = this.columns[0];
814
- return new MultiColumn([firstColumn.withNodes(nodes)]);
815
- }
816
-
817
- public moveWithinColumn(
818
- col: CellColumnId,
819
- fromIdx: CellIndex,
820
- toIdx: CellIndex,
821
- ): MultiColumn<T> {
822
- return this.transform(col, (c) => {
823
- return c.move(fromIdx, toIdx);
824
- });
825
- }
826
-
827
- public moveAcrossColumns(
828
- fromCol: CellColumnId,
829
- fromId: T,
830
- toCol: CellColumnId,
831
- toId: T | undefined,
832
- ): MultiColumn<T> {
833
- // Find indices once to avoid repeated lookups
834
- const fromColumnIndex = this.indexOfOrThrow(fromCol);
835
- const toColumnIndex = this.indexOfOrThrow(toCol);
836
-
837
- // Only copy the columns we're modifying
838
- const newColumns = [...this.columns];
839
- const fromColumn = newColumns[fromColumnIndex];
840
-
841
- // Find the node once
842
- const nodeIndex = fromColumn.nodes.findIndex((n) => n.value === fromId);
843
- if (nodeIndex === -1) {
844
- throw new Error(`Node ${fromId} not found in column ${fromCol}`);
845
- }
846
-
847
- const node = fromColumn.nodes[nodeIndex];
848
-
849
- // Create new columns with the changes
850
- newColumns[fromColumnIndex] = fromColumn.withNodes(
851
- fromColumn.nodes.filter((_, i) => i !== nodeIndex),
852
- );
853
-
854
- const toColumn = newColumns[toColumnIndex];
855
- if (toId) {
856
- const toIndex = toColumn.indexOfOrThrow(toId);
857
- newColumns[toColumnIndex] = toColumn.withNodes(
858
- arrayInsert(toColumn.nodes, toIndex, node),
859
- );
860
- } else {
861
- newColumns[toColumnIndex] = toColumn.withNodes([node, ...toColumn.nodes]);
862
- }
863
-
864
- return new MultiColumn(newColumns);
865
- }
866
-
867
- /**
868
- * Move multiple cells to be immediately before (or after) a target cell.
869
- * Cells are inserted in their original order.
870
- *
871
- * @throws Error if any cellId is not found in any column.
872
- * If targetId is among the moved cells, cells are inserted at the end of the target column.
873
- */
874
- public moveCellsRelativeTo(
875
- cellIds: T[],
876
- targetId: T,
877
- position: "before" | "after",
878
- ): MultiColumn<T> {
879
- if (cellIds.length === 0) {
880
- return this;
881
- }
882
-
883
- const cellIdSet = new Set(cellIds);
884
- const targetColumn = this.findWithId(targetId);
885
- const targetColIndex = this.indexOfOrThrow(targetColumn.id);
886
-
887
- // Collect nodes to move
888
- const nodesToMove: TreeNode<T>[] = [];
889
- for (const id of cellIds) {
890
- const col = this.findWithId(id);
891
- const node = col.nodes.find((n) => n.value === id);
892
- if (!node) {
893
- throw new Error(`Node ${id} not found in column ${col.id}`);
894
- }
895
- nodesToMove.push(node);
896
- }
897
-
898
- // Remove moved cells from all columns
899
- const columnsWithRemovals = this.columns.map((col) =>
900
- col.withNodes(col.nodes.filter((n) => !cellIdSet.has(n.value))),
901
- );
902
-
903
- // Find target index in the cleaned column
904
- const cleanedTargetCol = columnsWithRemovals[targetColIndex];
905
- let insertIndex = cleanedTargetCol.nodes.findIndex(
906
- (n) => n.value === targetId,
907
- );
908
-
909
- // If target was one of the moved cells, insert at end
910
- if (insertIndex === -1) {
911
- insertIndex = cleanedTargetCol.nodes.length;
912
- } else if (position === "after") {
913
- insertIndex += 1;
914
- }
915
-
916
- // Insert all moved nodes at target position
917
- const newTargetNodes = arrayInsertMany(
918
- cleanedTargetCol.nodes,
919
- insertIndex,
920
- nodesToMove,
921
- );
922
- columnsWithRemovals[targetColIndex] =
923
- cleanedTargetCol.withNodes(newTargetNodes);
924
-
925
- return new MultiColumn(columnsWithRemovals);
926
- }
927
-
928
- public indexOfOrThrow(id: CellColumnId): number {
929
- const index = this.columns.findIndex((c) => c.id === id);
930
- if (index === -1) {
931
- throw new Error(
932
- `Column ${id} not found. Possible values: ${this.getColumnIds().join(", ")}`,
933
- );
934
- }
935
- return index;
936
- }
937
-
938
- public moveColumn(
939
- fromCol: CellColumnId,
940
- toCol: CellColumnId | "_left_" | "_right_",
941
- ): MultiColumn<T> {
942
- if (fromCol === toCol) {
943
- return this;
944
- }
945
- const fromIdx = this.indexOfOrThrow(fromCol);
946
- const toIdx =
947
- toCol === "_left_"
948
- ? fromIdx - 1
949
- : toCol === "_right_"
950
- ? fromIdx + 1
951
- : this.indexOfOrThrow(toCol);
952
-
953
- reorderColumnSizes(fromIdx, toIdx);
954
- return new MultiColumn(arrayMove([...this.columns], fromIdx, toIdx));
955
- }
956
-
957
- public moveToNewColumn(cellId: T): MultiColumn<T> {
958
- const fromColumn = this.findWithId(cellId);
959
-
960
- // Create new columns array with the cell removed from its original column
961
- const columns = this.columns.map((c) => {
962
- if (c.id === fromColumn.id) {
963
- return c.delete(cellId);
964
- }
965
- return c;
966
- });
967
-
968
- // Insert into new column
969
- const newColumn = CollapsibleTree.from([cellId]);
970
- return new MultiColumn([...columns, newColumn]);
971
- }
972
-
973
- public findWithId(id: T): CollapsibleTree<T> {
974
- const found = this.columns.find((c) => {
975
- return c.inOrderIds.includes(id);
976
- });
977
- if (!found) {
978
- Logger.log(
979
- `Possible values: ${this.columns.map((c) => c.inOrderIds).join(", ")}`,
980
- );
981
- throw new Error(`Cell ${id} not found in any column`);
982
- }
983
- return found;
984
- }
985
-
986
- /**
987
- * Transform the column containing the given cell id
988
- * @param id the id of the cell to transform
989
- * @param fn the function to transform the column
990
- * @returns new MultiColumn with the transformed column
991
- * If the column was not updated, we return the object.
992
- */
993
- public transformWithCellId(
994
- id: T,
995
- fn: (tree: CollapsibleTree<T>) => CollapsibleTree<T>,
996
- ): MultiColumn<T> {
997
- let didChange = false;
998
-
999
- const columns = this.columns.map((c) => {
1000
- if (c.inOrderIds.includes(id)) {
1001
- const newColumn = fn(c);
1002
- if (c !== newColumn) {
1003
- didChange = true;
1004
- }
1005
- return newColumn;
1006
- }
1007
- return c;
1008
- });
1009
-
1010
- // Avoid unnecessary re-renders
1011
- if (!didChange) {
1012
- return this;
1013
- }
1014
-
1015
- return new MultiColumn(columns);
1016
- }
1017
-
1018
- public setupCellExists(): boolean {
1019
- return this.columns.some((c) => c.topLevelIds.includes(SETUP_CELL_ID as T));
1020
- }
1021
-
1022
- public insertId(id: T, col: CellColumnId, index: CellIndex): MultiColumn<T> {
1023
- return this.transform(col, (c) => c.insert(id, index));
1024
- }
1025
-
1026
- public deleteById(cellId: T): MultiColumn<T> {
1027
- return this.transformWithCellId(cellId, (c) => c.delete(cellId));
1028
- }
1029
-
1030
- /**
1031
- * Remove the given cells from the tree, then re-insert each at its
1032
- * (columnId, index). Used to undo a move (e.g. cut-paste) by restoring
1033
- * cells to their previous positions. Placements are sorted by
1034
- * (columnId, index) so insert order keeps indices valid.
1035
- */
1036
- public placeCells(
1037
- placements: Array<{ id: T; columnId: CellColumnId; index: CellIndex }>,
1038
- ): MultiColumn<T> {
1039
- if (placements.length === 0) {
1040
- return this;
1041
- }
1042
- let result = this.deleteById(placements[0].id);
1043
- for (const { id } of placements.slice(1)) {
1044
- result = result.deleteById(id);
1045
- }
1046
- const sorted = [...placements].toSorted((a, b) => {
1047
- if (a.columnId !== b.columnId) {
1048
- return a.columnId.localeCompare(b.columnId);
1049
- }
1050
- return (a.index as number) - (b.index as number);
1051
- });
1052
- for (const { id, columnId, index } of sorted) {
1053
- result = result.insertId(id, columnId, index);
1054
- }
1055
- return result;
1056
- }
1057
-
1058
- public compact(): MultiColumn<T> {
1059
- // Don't compact if there's only one column
1060
- if (this.columns.length === 1) {
1061
- return this;
1062
- }
1063
- // If no need to compact, return the same tree
1064
- // to avoid unnecessary re-renders
1065
- const someEmpty = this.columns.some((c) => c.nodes.length === 0);
1066
- if (!someEmpty) {
1067
- return this;
1068
- }
1069
-
1070
- return new MultiColumn(this.columns.filter((c) => c.nodes.length > 0));
1071
- }
1072
-
1073
- /**
1074
- * Transform the column with the given column id
1075
- */
1076
- public transform(
1077
- columnId: CellColumnId,
1078
- fn: (tree: CollapsibleTree<T>) => CollapsibleTree<T>,
1079
- ): MultiColumn<T> {
1080
- // Use columnMap for faster lookup
1081
- const column = this._columnMap.get(columnId);
1082
- if (!column) {
1083
- Logger.warn(`Column ${columnId} not found`);
1084
- return this;
1085
- }
1086
-
1087
- const newColumn = fn(column);
1088
- if (column === newColumn) {
1089
- return this;
1090
- }
1091
-
1092
- const newColumns = this.columns.map((c) => {
1093
- if (c.id === columnId) {
1094
- return newColumn;
1095
- }
1096
- return c;
1097
- });
1098
-
1099
- return new MultiColumn(newColumns);
1100
- }
1101
-
1102
- /**
1103
- * Apply a transformation function to all columns
1104
- * @param fn The function to transform each column
1105
- * @returns A new MultiColumn if any changes were made, otherwise this
1106
- */
1107
- public transformAll(
1108
- fn: (tree: CollapsibleTree<T>) => CollapsibleTree<T>,
1109
- ): MultiColumn<T> {
1110
- let didChange = false;
1111
-
1112
- // Apply the transformation to all columns
1113
- const newColumns = this.columns.map((column) => {
1114
- const newColumn = fn(column);
1115
- if (!column.equals(newColumn)) {
1116
- didChange = true;
1117
- }
1118
- return newColumn;
1119
- });
1120
-
1121
- // Avoid unnecessary re-renders if nothing changed
1122
- if (!didChange) {
1123
- return this;
1124
- }
1125
-
1126
- return new MultiColumn(newColumns);
1127
- }
1128
- }
1129
-
1130
- export const visibleForTesting = {
1131
- reset: () => {
1132
- uniqueId = 0;
1133
- },
1134
- };