@marimo-team/islands 0.24.3-dev9 → 0.25.0

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 (440) hide show
  1. package/dist/{ConnectedDataExplorerComponent-C9OF_75w.js → ConnectedDataExplorerComponent-KVhjDMSe.js} +1066 -1066
  2. package/dist/ErrorBoundary-DnNkbB_U.js +200 -0
  3. package/dist/{ImageComparisonComponent-2a9TMMm2.js → ImageComparisonComponent-Dlm5aWnH.js} +4 -4
  4. package/dist/{Plot-C-9MQeGP.js → Plot-CTyjbQDT.js} +21032 -20666
  5. package/dist/_baseMerge-BiGRwuqv.js +165 -0
  6. package/dist/{abnfDiagram-N423BO3Z-CQKwzX8t.js → abnfDiagram-VCTEODGH-CpN0FRda.js} +17 -18
  7. package/dist/{any-language-editor-DmQ7dyCx.js → any-language-editor-CycIVIeP.js} +17 -17
  8. package/dist/arc-7ra3iNdN.js +81 -0
  9. package/dist/architecture-7GRP2DOG-BWLylgiA.js +3 -0
  10. package/dist/{architectureDiagram-T3A2C74G-CncrDpfa.js → architectureDiagram-5GKGNRK7-DDyj5SRB.js} +25 -25
  11. package/dist/assets/__vite-browser-external-C9iR87Zl.js +1 -0
  12. package/dist/assets/worker-D7hWi02M.js +109 -0
  13. package/dist/blockDiagram-I7D4REHJ-BbXEXJRu.js +1922 -0
  14. package/dist/{button-CKBkqR9J.js → button-DdXAm8iz.js} +5 -5
  15. package/dist/{c4Diagram-5PPSVZJV-DarUk3Yq.js → c4Diagram-7LVT6UL2-DcLsbQmR.js} +696 -668
  16. package/dist/{capabilities-CMBBJTcc.js → capabilities-B3ce_GNu.js} +1 -1
  17. package/dist/{html-to-image-BtFMe_Nq.js → cells-DYIkSxs6.js} +6757 -10137
  18. package/dist/{channel-CyiYUzJv.js → channel-B5XnTarr.js} +1 -1
  19. package/dist/chat-ui-BXj3uYjy.js +5786 -0
  20. package/dist/{check-CHig47QV.js → check-B7cIK6gb.js} +1 -1
  21. package/dist/{chunk-2Q5K7J3B-BMuJl2jB.js → chunk-2Q5K7J3B-BMkUkeuy.js} +2 -2
  22. package/dist/chunk-4HAMMTFA-D2qv8E0X.js +4188 -0
  23. package/dist/{chunk-5VM5RSS4-Bcq0ftdy.js → chunk-5VM5RSS4-DKsmPCL6.js} +2 -2
  24. package/dist/{chunk-NSK5VX7P-CDTMcJB0.js → chunk-75Z2AOVW-5_HsvXwr.js} +23 -23
  25. package/dist/{chunk-I66GZJ75-BqyTCAPf.js → chunk-DU6HZSFF-BUgAHvnM.js} +21 -4
  26. package/dist/{chunk-2GRJ4B5K-DgO8Qudq.js → chunk-F27PBJKO-DHmYWZXr.js} +4 -4
  27. package/dist/{chunk-KEIR6QF5-C4KX3XYh.js → chunk-FOHPRMQF-BpYR8RqP.js} +4 -4
  28. package/dist/{chunk-WRU74C26-BpWsbiDK.js → chunk-GMAD6QVW-Czynz8aA.js} +486 -258
  29. package/dist/chunk-GVQU2GXP-yQEdulRS.js +37 -0
  30. package/dist/{chunk-5RXB4S5H-tLNUVDdO.js → chunk-IMKFNOWR-BfwTebD0.js} +11 -11
  31. package/dist/{chunk-JWPE2WC7-BJwjGUnF.js → chunk-JWPE2WC7-DJvv1t8U.js} +2 -2
  32. package/dist/chunk-L3NEJ4N5-DwRWnDDK.js +245 -0
  33. package/dist/{chunk-7Z6QIM7H-Dc18hFxH.js → chunk-OSK3NFVY-BBKU_Ign.js} +222 -144
  34. package/dist/{chunk-W5SLKNZC-DLnvpEtV.js → chunk-P2QGCYS3-C0iGU29N.js} +20 -20
  35. package/dist/{chunk-KBJHAD2P-BuqWqkcW.js → chunk-POPQ4Y6H-BCbS3Ozc.js} +4 -4
  36. package/dist/{chunk-4I5QYGJK-DpytHuZQ.js → chunk-PWAF6VOD-CTFCL0jI.js} +4 -4
  37. package/dist/{chunk-JQJVKLGR-CgqCwe8E.js → chunk-SHT3W25Y-BspJEJ5H.js} +109 -63
  38. package/dist/{chunk-6Q2QTUOP-DmTcEBMn.js → chunk-SVP7TREG-DX3rFNTe.js} +5 -5
  39. package/dist/{chunk-GF5L2VYU-B0wgCQgS.js → chunk-TICWLB2K-fVF7Uujg.js} +13 -13
  40. package/dist/{chunk-XXDRQBXY-D73H4IN0.js → chunk-XXDRQBXY-Dnl5VBqG.js} +3 -3
  41. package/dist/{chunk-Y2CYZVJY-DoegUj_e.js → chunk-Y2CYZVJY-DKKS1VyV.js} +1 -1
  42. package/dist/{chunk-5FQGJX7Z-B85XCPv6.js → chunk-YOKDWASO-DrWbKnxA.js} +6925 -5460
  43. package/dist/classDiagram-ZZMXUADV-Fe-V14Sc.js +30 -0
  44. package/dist/classDiagram-v2-VYDZK3BY-xTDg7lOs.js +30 -0
  45. package/dist/code-visibility-DElzk_hh.js +138 -0
  46. package/dist/{common-Cv-4hMa0.js → common-B4-ih9IA.js} +8838 -12645
  47. package/dist/{compiler-runtime-CAH9RLw2.js → compiler-runtime-Cj8ZWiNS.js} +2 -2
  48. package/dist/copy-icon-CLdENY__.js +190 -0
  49. package/dist/{cose-bilkent-JH36ORCC-FUWHkXFX.js → cose-bilkent-JH36ORCC-_LyRKVqm.js} +2 -2
  50. package/dist/cubic-OaEBhQPK.js +1404 -0
  51. package/dist/cynefin-OW5HDTMX-obq-i80l.js +3 -0
  52. package/dist/{cynefinDiagram-MW4NZA55-BXSFK93J.js → cynefinDiagram-5FMLGOSQ-CFQrqzSX.js} +10 -10
  53. package/dist/{dagre-CGyalH38.js → dagre-BGSfXNEb.js} +678 -537
  54. package/dist/dagre-GXQ25YYZ-xHNAUTyG.js +425 -0
  55. package/dist/{data-grid-overlay-editor-DZM4BAaI.js → data-grid-overlay-editor-CRH6JQPE.js} +8 -9
  56. package/dist/{data-grid-types-BnZwWG8z.js → data-grid-types-BucVmDDp.js} +1 -1
  57. package/dist/{defaultLocale-DKaU_opG.js → defaultLocale-JI_lnoCe.js} +1 -1
  58. package/dist/{diagram-7IWD3JNH-BjfzDNvj.js → diagram-S7CK7UJ4-Bt1rPbAx.js} +40 -39
  59. package/dist/{diagram-UB23O5K3-DDg-7wLA.js → diagram-UQ7AKVKN-D1sq5FoZ.js} +10 -10
  60. package/dist/{diagram-B4RE2ZJO-CKccR9eE.js → diagram-VSXAHHWV-BKpmG23x.js} +10 -10
  61. package/dist/{diagram-Q27KOJAE-Zhz01ss7.js → diagram-VX7I27RA-BMwGFVD6.js} +21 -21
  62. package/dist/{diagram-LBJQPF4R-CJ-bOruh.js → diagram-Z3DM3KII--KLDR9Pl.js} +10 -10
  63. package/dist/dialog-CgNq6y9-.js +94 -0
  64. package/dist/{dist-dAqZAPcF.js → dist-1HDa70oE.js} +3 -3
  65. package/dist/{dist-Re9sOPOx.js → dist-9x1ZRe-e.js} +2 -2
  66. package/dist/{dist-DEeLqRlU.js → dist-B1vYLK28.js} +1 -1
  67. package/dist/{dist-C5Bn52W4.js → dist-B8D7McG3.js} +3 -3
  68. package/dist/{dist-_XvgytiS.js → dist-BHCHt1NI.js} +1 -1
  69. package/dist/{dist-CRjAdnqF.js → dist-BRxfaJgs.js} +3 -3
  70. package/dist/{dist-Byj2bV8o.js → dist-BVGtK7Ht.js} +1 -1
  71. package/dist/{dist-BIN5LKyE.js → dist-BaHjhkpZ.js} +2 -2
  72. package/dist/{dist-DVFbIwc5.js → dist-BtKIs9N-.js} +1 -1
  73. package/dist/{dist-BrQGcfQ9.js → dist-C2KzV-vf.js} +2 -2
  74. package/dist/{dist-DJFiGP2k.js → dist-C2wDlYdD.js} +2 -2
  75. package/dist/{dist-BVRM2y1P.js → dist-C8xMLVYi.js} +2 -2
  76. package/dist/dist-CMh_W4y4.js +538 -0
  77. package/dist/{extends-BPB6_lTK.js → dist-CO1AwwG_.js} +516 -561
  78. package/dist/{dist-BzN60Z2s.js → dist-CPGxfVGX.js} +1 -1
  79. package/dist/{dist-C7v-9nUK.js → dist-Cm3iAFMD.js} +3 -3
  80. package/dist/{dist-CGAxEiaM.js → dist-Cs2FijYk.js} +2 -2
  81. package/dist/{dist-hXd65f0_.js → dist-D1PpnuZB.js} +1 -1
  82. package/dist/{dist-VdvbxG72.js → dist-DHOTQar0.js} +1 -1
  83. package/dist/{dist-DcgzXCfy.js → dist-DPcEtqmG.js} +2 -2
  84. package/dist/{dist-D4Z_qdP4.js → dist-Df0wKI0F.js} +1 -1
  85. package/dist/{dist-qhLI-SHd.js → dist-DszxuxS1.js} +2 -2
  86. package/dist/{dist-BEmkrGoQ.js → dist-Kxgjxakw.js} +1 -1
  87. package/dist/{dist-BbSMhhD2.js → dist-KzZ7WELx.js} +2 -2
  88. package/dist/{dist-jWUab2d1.js → dist-lA1Cttkb.js} +1 -1
  89. package/dist/dropdown-menu-CZgjYSAh.js +4502 -0
  90. package/dist/{ebnfDiagram-BXEA7PRR-Dm75pCAS.js → ebnfDiagram-PWID7BFC-WnG4cvSQ.js} +17 -18
  91. package/dist/{erDiagram-JOGREHBK-rVDG3VSQ.js → erDiagram-RLTQ6QDP-DhzKiYHc.js} +1037 -798
  92. package/dist/error-banner-B94dcDmP.js +391 -0
  93. package/dist/error-entries-C0NsUqXl.js +56 -0
  94. package/dist/{esm-CR1nhb1c.js → esm-BElI3qKH.js} +22 -22
  95. package/dist/{esm-C1d0g6Bv.js → esm-G4Fhsgng.js} +51 -37
  96. package/dist/{esm-CesmlDrs.js → esm-h8f7-1CJ.js} +423 -423
  97. package/dist/eventmodeling-NTZA5JFV-D7nP7Uyu.js +3 -0
  98. package/dist/feedback-button-cQcMqpEP.js +380 -0
  99. package/dist/flowDiagram-HODETNUW-6dMdB8pR.js +16 -0
  100. package/dist/{formats-CslNOKy0.js → formats-BR5iGb4s.js} +8 -8
  101. package/dist/{ganttDiagram-PKOTCBZU-9D-LXF6P.js → ganttDiagram-EL5Y4UJY-DbzEBLbl.js} +15 -15
  102. package/dist/gitGraph-4MIJSDKK-Dy9uQXGh.js +3 -0
  103. package/dist/{gitGraphDiagram-DS77QQ5N-BfpsXTLf.js → gitGraphDiagram-WWUBYQGX-BMf0iKi1.js} +10 -10
  104. package/dist/{glide-data-editor-sPZ8fUFn.js → glide-data-editor-DYOxfSzI.js} +2143 -1910
  105. package/dist/{glide-utils-NShAPPtn.js → glide-utils-B3rUT5PI.js} +15 -15
  106. package/dist/globals-BOoLHa7X.js +19 -0
  107. package/dist/highlighted-body-KPVGNVTW-Ad3MKZ18.js +38 -0
  108. package/dist/html-to-image-CeYYvQNb.js +3272 -0
  109. package/dist/info-A6RAGUB7-DKoayiHY.js +3 -0
  110. package/dist/{infoDiagram-6WML65LV-DqCTXHVy.js → infoDiagram-27XIBGKW-BagtCX_5.js} +7 -7
  111. package/dist/{ishikawaDiagram-WSZJBQD7-BCUYmZ1v.js → ishikawaDiagram-5VMMS53U-DByDehYy.js} +8 -8
  112. package/dist/{journeyDiagram-NVQOT4AX-BXB6M4zN.js → journeyDiagram-3NMN7TZE-D2LcKDUO.js} +8 -8
  113. package/dist/{jsx-runtime-CpoKNRgu.js → jsx-runtime-DgDPJV9S.js} +1 -1
  114. package/dist/{kanban-definition-27J2QSJJ-CGRhrDUX.js → kanban-definition-UXKFOSKX-BxwkbBI_.js} +29 -29
  115. package/dist/katex-DFBiSucW.js +21840 -0
  116. package/dist/{label-lwzzBHUW.js → label-BJ49YTvk.js} +6 -6
  117. package/dist/{linear-D5r_1YqD.js → linear-Cnaq3Tfb.js} +4 -4
  118. package/dist/{loader-VZ__bv4g.js → loader-D2W4oM-3.js} +15 -15
  119. package/dist/main.js +8113 -13475
  120. package/dist/mermaid-DPNuhemn.js +3084 -0
  121. package/dist/mermaid-HWGCJPDP-DYCzSILp.js +2 -0
  122. package/dist/mermaid-parser.core-DxuSfYwJ.js +638 -0
  123. package/dist/{mhchem-BjwrxcV-.js → mhchem-DWCF06w9.js} +1 -1
  124. package/dist/{micromark-factory-space-DruVGzeG.js → micromark-factory-space-DGxAzmw8.js} +2 -2
  125. package/dist/{mindmap-definition-FAOFIHXS-C9gRhzZq.js → mindmap-definition-YA3MSWOX-Cgvojw3y.js} +17 -17
  126. package/dist/{node-sql-parser-DesT1xNw.js → node-sql-parser-BiZOJ-FS.js} +0 -3
  127. package/dist/{number-overlay-editor-De2CabLL.js → number-overlay-editor-DZp5bEmI.js} +5 -5
  128. package/dist/objectWithoutPropertiesLoose-BRDcTsfB.js +23 -0
  129. package/dist/packet-AYTQ26CC-Yw7ajchJ.js +3 -0
  130. package/dist/{pegDiagram-VL7TDLO6-Df9IUjMD.js → pegDiagram-XKGWAZYB-DahHhYyN.js} +19 -20
  131. package/dist/{pick-SnHlmIBN.js → pick-CJeoxYOS.js} +1 -1
  132. package/dist/pie-WAS4IAKB-BKdKOAkL.js +3 -0
  133. package/dist/{pieDiagram-7S7Q4E2Y-BmRzQ8ZP.js → pieDiagram-E7YTZNPT-CCtX0oCK.js} +29 -31
  134. package/dist/{process-output-CPy0YKUe.js → process-output-BCTjlyuH.js} +7 -6
  135. package/dist/purify.es-DgKyQviY.js +805 -0
  136. package/dist/{quadrantDiagram-CIZ2JOQS-wFBvWcxS.js → quadrantDiagram-AXDQQJYC-DftINo6g.js} +5 -5
  137. package/dist/radar-RG4KPBEZ-ScR_D_Ts.js +3 -0
  138. package/dist/railroad-74A4TZTK-DQvPSdo5.js +3 -0
  139. package/dist/railroad-abnf-HS5TGJTU-CsJQG2O8.js +3 -0
  140. package/dist/railroad-ebnf-LZEXJU2U-BgEobkSn.js +3 -0
  141. package/dist/railroad-peg-WCYAUIDC-DjLAjofI.js +3 -0
  142. package/dist/{railroadDiagram-AXF67PYL-DxbIatiN.js → railroadDiagram-O6MQD6OU-Du5NsPUb.js} +17 -18
  143. package/dist/{react-dom-C94wmq5w.js → react-dom-BUgJ-ab_.js} +3 -3
  144. package/dist/{react-DMWcHin-.js → react-ofJbxM4x.js} +2 -2
  145. package/dist/{react-vega-DSD5aT7_.js → react-vega-5AcMW8gG.js} +10012 -9369
  146. package/dist/{requirementDiagram-LRYGKXZP-X_x-Y713.js → requirementDiagram-BXWQKSXE-0pmmxL6_.js} +20 -19
  147. package/dist/{reveal-component-CVsYlb9J.js → reveal-component-C9h2Lubu.js} +1303 -1237
  148. package/dist/{sankeyDiagram-W5VNT64P-BYJALbbm.js → sankeyDiagram-P5KCCOFB-CDKR5TJH.js} +4 -4
  149. package/dist/{select-3qHpFKF9.js → select-C6plhmZr.js} +317 -562
  150. package/dist/{sequenceDiagram-SI44F4Z6-BiPBe3Sv.js → sequenceDiagram-WJ2MYXX4-DB-ChWwU.js} +11 -11
  151. package/dist/{sizeCapture-X5ZJPWSS-BKLDeh5H.js → sizeCapture-INFHLROL-Dx5SpkQF.js} +2 -2
  152. package/dist/{spec-CutWdqo3.js → spec-CAYwFeV6.js} +4 -4
  153. package/dist/{src-C31ngt98.js → src-CA_m4ONl.js} +298 -303
  154. package/dist/{stateDiagram-OKZ733FA-B7QyNBxH.js → stateDiagram-D77RDMKH-orN6AwMx.js} +19 -20
  155. package/dist/stateDiagram-v2-MP3YSRHH-o05_rJN8.js +30 -0
  156. package/dist/style.css +2 -2
  157. package/dist/{swimlanes-SLNWSIFB-B4f8VP3b.js → swimlanes-42K2YHIH-BkSDcqDT.js} +1501 -1591
  158. package/dist/swimlanesDiagram-VR7AAH4N-D_nFQfRc.js +30 -0
  159. package/dist/{swiper-component-C90YjhaV.js → swiper-component-IOUowglM.js} +39 -26
  160. package/dist/{time-aWGfjN8x.js → time-BieKwdYS.js} +42 -42
  161. package/dist/{timeline-definition-Z64GVDOM-Dacq_5lr.js → timeline-definition-24CTP7MA-BuqJUIRZ.js} +7 -7
  162. package/dist/{toDate-CpXBeDq0.js → toDate-WXg1yLcI.js} +7 -7
  163. package/dist/toast-DvY70eFX.js +1834 -0
  164. package/dist/tooltip-qB8NlSqV.js +1742 -0
  165. package/dist/treeView-Q6P3EWNA-DuRV97YF.js +3 -0
  166. package/dist/treemap-WGGIJYW6-AsLq-uwC.js +3 -0
  167. package/dist/use-restore-focus-D5D9xEjZ.js +5946 -0
  168. package/dist/{use-vega-container-remeasure-DUW4tRxq.js → use-vega-container-remeasure-4DwJbPWu.js} +2 -2
  169. package/dist/{useAsyncData-CH6-CgJF.js → useAsyncData-BD6AStMt.js} +3 -3
  170. package/dist/{useDateFormatter-Cp9Jdxls.js → useDateFormatter-BRTPsUK7.js} +8 -8
  171. package/dist/{useDeepCompareMemoize-JC87C_jO.js → useDeepCompareMemoize-D_HNdyvI.js} +2 -2
  172. package/dist/{useIframeCapabilities-De3C-9b4.js → useIframeCapabilities-CVtNkI3Y.js} +2 -2
  173. package/dist/{useLifecycle-B4RGlyf0.js → useLifecycle-DPgiiwwU.js} +6 -6
  174. package/dist/useNumberFormatter-BfDpa21j.js +251 -0
  175. package/dist/useTheme-DzXmYZ5V.js +904 -0
  176. package/dist/{vega-component-ovBXgp91.js → vega-component-D0QXopU8.js} +34 -34
  177. package/dist/{vega-embed-container-TJ5z5dZw.js → vega-embed-container-CbnTccZi.js} +6 -6
  178. package/dist/vega-loader.browser-D95WfUcj.js +1139 -0
  179. package/dist/{vennDiagram-T6HMQDX7-D-Rcq3Iu.js → vennDiagram-4TSXK5OY-CTUlJ2PK.js} +9 -9
  180. package/dist/wardley-WFR3VGLG-Na-tFhQJ.js +3 -0
  181. package/dist/{wardleyDiagram-T6FBY63Y-Z-Og7_Wd.js → wardleyDiagram-VM6X3IG4-3evLUb0M.js} +10 -10
  182. package/dist/{xychartDiagram-ELKLHX3M-BDJ2dITA.js → xychartDiagram-S5SC5T6Z-DL2E3K8-.js} +248 -139
  183. package/package.json +54 -57
  184. package/src/__mocks__/notebook.ts +1 -0
  185. package/src/__mocks__/requests.ts +7 -0
  186. package/src/__tests__/__snapshots__/CellStatus.test.tsx.snap +12 -12
  187. package/src/__tests__/fixtures/pair-preview.ts +19 -0
  188. package/src/__tests__/mount.test.ts +18 -0
  189. package/src/components/app-config/optional-features.tsx +6 -0
  190. package/src/components/chat/acp/__tests__/agent-panel-initialization.test.tsx +394 -0
  191. package/src/components/chat/acp/__tests__/agent-panel.test.tsx +272 -0
  192. package/src/components/chat/acp/__tests__/state.test.ts +2 -2
  193. package/src/components/chat/acp/agent-panel.tsx +115 -74
  194. package/src/components/chat/acp/state.ts +1 -1
  195. package/src/components/data-table/__tests__/filters.test.ts +21 -21
  196. package/src/components/data-table/charts/__tests__/spec.test.ts +5 -10
  197. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +2 -6
  198. package/src/components/data-table/column-summary/chart-spec-model.tsx +1 -1
  199. package/src/components/data-table/columns.tsx +64 -67
  200. package/src/components/editor/RecoveryButton.tsx +1 -0
  201. package/src/components/editor/__tests__/dynamic-favicon.test.tsx +36 -2
  202. package/src/components/editor/actions/__tests__/pair-with-agent-commands.test.ts +115 -0
  203. package/src/components/editor/actions/__tests__/pair-with-agent-modal.test.tsx +218 -0
  204. package/src/components/editor/actions/pair-with-agent-commands.ts +46 -9
  205. package/src/components/editor/actions/pair-with-agent-modal.tsx +49 -23
  206. package/src/components/editor/ai/add-cell-with-ai.tsx +1 -0
  207. package/src/components/editor/ai/ai-completion-editor.tsx +3 -1
  208. package/src/components/editor/alerts/__tests__/connection-notice.test.tsx +186 -0
  209. package/src/components/editor/alerts/__tests__/startup-progress.test.tsx +185 -0
  210. package/src/components/editor/alerts/connecting-alert.tsx +1 -66
  211. package/src/components/editor/alerts/connection-notice.tsx +186 -0
  212. package/src/components/editor/alerts/startup-output.tsx +173 -0
  213. package/src/components/editor/alerts/startup-progress.tsx +204 -0
  214. package/src/components/editor/app-container.tsx +9 -3
  215. package/src/components/editor/boundary/ErrorBoundary.tsx +38 -16
  216. package/src/components/editor/boundary/__tests__/ErrorBoundary.test.tsx +311 -0
  217. package/src/components/editor/cell/__tests__/toolbar.test.tsx +73 -0
  218. package/src/components/editor/cell/code/__tests__/rtc-editor-config.test.ts +50 -0
  219. package/src/components/editor/cell/code/cell-editor.tsx +41 -42
  220. package/src/components/editor/cell/toolbar.tsx +11 -0
  221. package/src/components/editor/chrome/components/__tests__/feedback-button.test.tsx +94 -0
  222. package/src/components/editor/chrome/components/feedback-button.tsx +63 -42
  223. package/src/components/editor/chrome/panels/__tests__/packages-panel.test.tsx +164 -8
  224. package/src/components/editor/chrome/panels/__tests__/sandbox-details.test.tsx +358 -0
  225. package/src/components/editor/chrome/panels/__tests__/sandbox-recovery.test.tsx +168 -0
  226. package/src/components/editor/chrome/panels/packages-panel.tsx +113 -175
  227. package/src/components/editor/chrome/panels/sandbox-controller.tsx +106 -0
  228. package/src/components/editor/chrome/panels/sandbox-details-state.ts +38 -0
  229. package/src/components/editor/chrome/panels/sandbox-panel.tsx +230 -0
  230. package/src/components/editor/chrome/panels/sandbox-toggle.tsx +52 -0
  231. package/src/components/editor/chrome/wrapper/app-chrome.tsx +7 -0
  232. package/src/components/editor/chrome/wrapper/footer-items/backend-status.tsx +3 -1
  233. package/src/components/editor/code/__tests__/readonly-diff.test.tsx +65 -0
  234. package/src/components/editor/code/readonly-diff.tsx +1 -1
  235. package/src/components/editor/connections/database/__tests__/__snapshots__/as-code.test.ts.snap +98 -98
  236. package/src/components/editor/connections/database/__tests__/as-code.test.ts +11 -5
  237. package/src/components/editor/dynamic-favicon.tsx +17 -10
  238. package/src/components/editor/file-tree/__tests__/file-explorer-navigation.test.tsx +13 -11
  239. package/src/components/editor/file-tree/__tests__/tree-actions.test.tsx +54 -0
  240. package/src/components/editor/file-tree/tree-actions.tsx +11 -14
  241. package/src/components/editor/header/__tests__/status.test.tsx +8 -20
  242. package/src/components/editor/header/filename-input.tsx +2 -0
  243. package/src/components/editor/header/status.tsx +5 -3
  244. package/src/components/editor/navigation/clipboard.ts +1 -0
  245. package/src/components/editor/notebook-cell.tsx +4 -2
  246. package/src/components/editor/output/JsonOutput.tsx +182 -632
  247. package/src/components/editor/output/Outputs.css +49 -17
  248. package/src/components/editor/output/__tests__/JsonOutput-interactions.test.tsx +254 -0
  249. package/src/components/editor/output/__tests__/JsonOutput-mimetype.test.tsx +41 -46
  250. package/src/components/editor/output/__tests__/{json-output.test.ts → json-output-formatting.test.ts} +113 -75
  251. package/src/components/editor/output/__tests__/json-output-pagination.test.ts +252 -0
  252. package/src/components/editor/output/json-output/formatting.ts +167 -0
  253. package/src/components/editor/output/json-output/pagination.ts +155 -0
  254. package/src/components/editor/output/json-output/renderers.tsx +196 -0
  255. package/src/components/editor/output/json-output/themes.ts +52 -0
  256. package/src/components/editor/package-alert.tsx +112 -66
  257. package/src/components/editor/renderers/cell-array.tsx +1 -5
  258. package/src/components/editor/renderers/slides-layout/__tests__/plugin.test.ts +3 -7
  259. package/src/components/slides/slide-form.tsx +1 -0
  260. package/src/components/slides/slide-notes-editor.tsx +1 -0
  261. package/src/components/tracing/tracing-spec.ts +1 -1
  262. package/src/components/ui/__tests__/badge.test.ts +6 -4
  263. package/src/components/ui/use-toast.ts +8 -0
  264. package/src/core/MarimoApp.tsx +0 -2
  265. package/src/core/ai/context/providers/__tests__/error.test.ts +16 -22
  266. package/src/core/alerts/__tests__/environment.test.ts +183 -0
  267. package/src/core/alerts/__tests__/state.test.tsx +240 -0
  268. package/src/core/alerts/environment.ts +57 -0
  269. package/src/core/alerts/state.ts +155 -99
  270. package/src/core/cells/__tests__/__snapshots__/cells.test.ts.snap +296 -259
  271. package/src/core/cells/__tests__/apply-transaction.test.ts +34 -0
  272. package/src/core/cells/__tests__/cell.test.ts +61 -0
  273. package/src/core/cells/__tests__/cells.test.ts +182 -37
  274. package/src/core/cells/__tests__/document-changes.test.ts +39 -1
  275. package/src/core/cells/__tests__/outputs.test.tsx +117 -0
  276. package/src/core/cells/__tests__/pending-delete-service.test.tsx +4 -3
  277. package/src/core/cells/__tests__/session.test.ts +7 -0
  278. package/src/core/cells/cell.ts +9 -1
  279. package/src/core/cells/cells.ts +13 -18
  280. package/src/core/cells/document-changes.ts +11 -1
  281. package/src/core/cells/outputs.ts +66 -9
  282. package/src/core/cells/pending-delete-service.ts +12 -16
  283. package/src/core/cells/session.ts +2 -0
  284. package/src/core/cells/types.ts +2 -0
  285. package/src/core/codemirror/find-replace/__tests__/navigate.test.ts +8 -16
  286. package/src/core/codemirror/language/__tests__/sql.test.ts +70 -2
  287. package/src/core/codemirror/language/embedded/__tests__/embedded-python.test.ts +4 -8
  288. package/src/core/codemirror/language/languages/sql/sql.ts +16 -1
  289. package/src/core/codemirror/rtc/extension.ts +5 -2
  290. package/src/core/config/pair.ts +19 -0
  291. package/src/core/datasets/__tests__/data-source.test.ts +2 -0
  292. package/src/core/datasets/data-source-connections.ts +15 -10
  293. package/src/core/edit-app.tsx +8 -5
  294. package/src/core/errors/state.ts +1 -2
  295. package/src/core/export/__tests__/hooks.test.ts +1 -6
  296. package/src/core/islands/bootstrap.ts +3 -1
  297. package/src/core/islands/bridge.ts +3 -0
  298. package/src/core/islands/worker-factory.ts +2 -12
  299. package/src/core/kernel/messages.ts +2 -2
  300. package/src/core/network/__tests__/requests-network.test.ts +4 -3
  301. package/src/core/network/connection-notice.ts +117 -0
  302. package/src/core/network/connection.ts +19 -0
  303. package/src/core/network/requests-lazy.ts +3 -0
  304. package/src/core/network/requests-network.ts +12 -0
  305. package/src/core/network/requests-static.ts +3 -0
  306. package/src/core/network/requests-toasting.tsx +3 -0
  307. package/src/core/network/resolve.ts +2 -1
  308. package/src/core/network/types.ts +7 -0
  309. package/src/core/network/useConnectionNotice.ts +53 -0
  310. package/src/core/packages/__tests__/usePackageAction.test.tsx +129 -0
  311. package/src/core/packages/__tests__/useSandboxController.test.tsx +246 -0
  312. package/src/core/packages/package-data.ts +35 -0
  313. package/src/core/packages/sandbox-state.ts +67 -0
  314. package/src/core/packages/toast-components.tsx +11 -0
  315. package/src/core/packages/useInstallPackage.ts +1 -1
  316. package/src/core/packages/usePackageAction.ts +51 -0
  317. package/src/core/packages/usePackageDependencies.ts +22 -0
  318. package/src/core/packages/useSandboxController.ts +208 -0
  319. package/src/core/run-app.tsx +2 -0
  320. package/src/core/static/__tests__/files.test.ts +12 -30
  321. package/src/core/wasm/__tests__/bootstrap.test.ts +63 -0
  322. package/src/core/wasm/__tests__/bridge.test.ts +13 -4
  323. package/src/core/wasm/__tests__/fs.test.ts +22 -0
  324. package/src/core/wasm/__tests__/runtime-config.test.ts +65 -0
  325. package/src/core/wasm/bridge.ts +35 -23
  326. package/src/core/wasm/rpc.ts +2 -0
  327. package/src/core/wasm/runtime-config.ts +31 -0
  328. package/src/core/wasm/worker/bootstrap.ts +21 -11
  329. package/src/core/wasm/worker/constants.ts +1 -0
  330. package/src/core/wasm/worker/fs.ts +4 -0
  331. package/src/core/wasm/worker/getController.ts +3 -1
  332. package/src/core/wasm/worker/save-worker.ts +10 -9
  333. package/src/core/wasm/worker/types.ts +6 -4
  334. package/src/core/wasm/worker/worker.ts +9 -9
  335. package/src/core/websocket/__tests__/useMarimoKernelConnection.hook.test.tsx +404 -3
  336. package/src/core/websocket/__tests__/useMarimoKernelConnection.test.ts +8 -6
  337. package/src/core/websocket/transports/transport.ts +1 -1
  338. package/src/core/websocket/transports/ws.ts +1 -1
  339. package/src/core/websocket/types.ts +11 -1
  340. package/src/core/websocket/useMarimoKernelConnection.tsx +63 -16
  341. package/src/hooks/useDebounce.ts +2 -0
  342. package/src/mount.tsx +3 -0
  343. package/src/plugins/core/BadPlugin.tsx +3 -14
  344. package/src/plugins/core/RenderHTML.tsx +22 -2
  345. package/src/plugins/core/__test__/RenderHTML.test.ts +187 -0
  346. package/src/plugins/core/registerReactComponent.tsx +0 -1
  347. package/src/plugins/impl/FileBrowserPlugin.tsx +10 -4
  348. package/src/plugins/impl/FormPlugin.tsx +2 -0
  349. package/src/plugins/impl/MatrixPlugin.tsx +2 -0
  350. package/src/plugins/impl/RangeSliderPlugin.tsx +2 -0
  351. package/src/plugins/impl/SliderPlugin.tsx +2 -0
  352. package/src/plugins/impl/__tests__/FileBrowserPlugin.test.tsx +50 -1
  353. package/src/plugins/impl/data-editor/__tests__/glide-data-editor.test.tsx +23 -18
  354. package/src/plugins/impl/data-frames/panel.tsx +1 -0
  355. package/src/plugins/impl/image-comparison/ImageComparisonComponent.tsx +1 -1
  356. package/src/plugins/impl/image-comparison/__tests__/ImageComparisonComponent.test.tsx +15 -0
  357. package/src/plugins/impl/vega/__tests__/make-selectable.test.ts +42 -48
  358. package/src/plugins/layout/AccordionPlugin.tsx +7 -2
  359. package/src/plugins/layout/JsonOutputPlugin.tsx +7 -10
  360. package/src/plugins/layout/__test__/AccordionPlugin.test.tsx +66 -0
  361. package/src/stories/sandbox.stories.tsx +488 -0
  362. package/src/utils/__tests__/path.test.ts +6 -5
  363. package/src/utils/__tests__/worker.test.ts +81 -0
  364. package/src/utils/worker.ts +22 -0
  365. package/dist/ErrorBoundary-CR-ZQN_c.js +0 -125
  366. package/dist/_baseMerge-Dv8bBloN.js +0 -73
  367. package/dist/_initCloneObject---vediN2.js +0 -95
  368. package/dist/arc-DOVLrCPd.js +0 -82
  369. package/dist/architecture-TIHT7OUA-MiJpPpQW.js +0 -3
  370. package/dist/array-CApNbSU9.js +0 -6
  371. package/dist/assets/__vite-browser-external-BdKGjRZ4.js +0 -1
  372. package/dist/assets/worker-DlIBfp9S.js +0 -98
  373. package/dist/blockDiagram-VBNYF7ZC-Bc--I65C.js +0 -3158
  374. package/dist/chat-ui-BSwr409J.js +0 -8455
  375. package/dist/chunk-3NCLNEKW-BIp_lB_4.js +0 -14
  376. package/dist/chunk-5FCAYU7R-C_HO9A1J.js +0 -23
  377. package/dist/chunk-5HE753X5-Bixm_MV-.js +0 -38
  378. package/dist/chunk-5JV3BV7I-CH5J3iZY.js +0 -54
  379. package/dist/chunk-5TONJI2A-DG6gDiSS.js +0 -62
  380. package/dist/chunk-7BUUIJ7U-5afmIPeo.js +0 -82
  381. package/dist/chunk-BIQX33UG-7TMBUf89.js +0 -23
  382. package/dist/chunk-CQNSW5MT-Cnqqsxt-.js +0 -38
  383. package/dist/chunk-CYSBUYHQ-BAbymFHR.js +0 -23
  384. package/dist/chunk-EMLP6XTP-Bsz-QL77.js +0 -23
  385. package/dist/chunk-J7OUQ5F2-CM_meqZH.js +0 -57
  386. package/dist/chunk-JG7HCLWE-DUnCDgPk.js +0 -62
  387. package/dist/chunk-MOZMSUNE-BG6IHvzT.js +0 -35
  388. package/dist/chunk-OSBZ3O6U-CYwj_bvR.js +0 -23
  389. package/dist/chunk-QBLGF6JB-B4vJ4j8J.js +0 -23
  390. package/dist/chunk-QR6OTTB3-D4wH2ldi.js +0 -3738
  391. package/dist/chunk-R7FJI6CG-Blf8FcmZ.js +0 -64
  392. package/dist/chunk-RYQCIY6F-BWbIlBIH.js +0 -241
  393. package/dist/chunk-U6XO7XAA-COw445DS.js +0 -63
  394. package/dist/chunk-UBXNYLIW-BHigVU4H.js +0 -32
  395. package/dist/chunk-YOTPTUD7-Dn044Q_d.js +0 -30
  396. package/dist/chunk-ZIRB5QZD-BR4TMfOa.js +0 -1153
  397. package/dist/classDiagram-JCYQIIEL-DmXSLxe_.js +0 -30
  398. package/dist/classDiagram-v2-OCEON4UE-CooqVexA.js +0 -30
  399. package/dist/click-outside-container-D_URcm3D.js +0 -167
  400. package/dist/code-block-37QAKDTI-CQrzBOr-.js +0 -107
  401. package/dist/copy-CD7S58CY.js +0 -141
  402. package/dist/cynefin-VYW2F7L2-CeHAxOEX.js +0 -3
  403. package/dist/dagre-VZM6K2ZE-CJggWPTJ.js +0 -328
  404. package/dist/dist-3_o3T78I.js +0 -1360
  405. package/dist/dist-ABQjhuek.js +0 -64
  406. package/dist/dist-CO5R6VMi.js +0 -538
  407. package/dist/dropdown-menu-DhCfcscX.js +0 -5858
  408. package/dist/emotion-is-prop-valid.esm-M57VsT8j.js +0 -14
  409. package/dist/error-banner-CsXbEEjo.js +0 -611
  410. package/dist/eventmodeling-45OFAUF4-B_lWZ-Pd.js +0 -3
  411. package/dist/flowDiagram-UKHOOZJN-g1AmrZzM.js +0 -17
  412. package/dist/gitGraph-TEB2WS4Q-Dj-eXUph.js +0 -3
  413. package/dist/info-DKCQHKI2-Bhb-pe2e.js +0 -3
  414. package/dist/line-CuKjIQa1.js +0 -34
  415. package/dist/map-BJpOfPlL.js +0 -149
  416. package/dist/math-BXtKgYah.js +0 -10
  417. package/dist/mermaid-4DMBBIKO-Ddp9TgNp.js +0 -2
  418. package/dist/mermaid-Bi23Ibnw.js +0 -1173
  419. package/dist/mermaid-parser.core-Din9FvSi.js +0 -99
  420. package/dist/packet-7NZHBO7P-fbkIIyKE.js +0 -3
  421. package/dist/path-BNHuHZP8.js +0 -87
  422. package/dist/pie-RZYD4A2V-CLRIsxY1.js +0 -3
  423. package/dist/purify.es-CB-YO1Hn.js +0 -774
  424. package/dist/radar-I7S5WNFK-BGzCbgXu.js +0 -3
  425. package/dist/railroad-3IZDKUUU-CvQIIcuU.js +0 -3
  426. package/dist/railroad-abnf-AHOZXSZD-CMwtlNtu.js +0 -3
  427. package/dist/railroad-ebnf-EBAXGLYW-n1QUOAsh.js +0 -3
  428. package/dist/railroad-peg-LSFZ7HO6-PjnrpmCs.js +0 -3
  429. package/dist/schemas-DzK6U94N.js +0 -6057
  430. package/dist/stateDiagram-v2-UEYNNEHI-BTRUs8Il.js +0 -30
  431. package/dist/step-CKczO72Q.js +0 -670
  432. package/dist/swimlanesDiagram-ULZ7WXOC-NBmgBl9G.js +0 -31
  433. package/dist/timer-DpDyj9G0.js +0 -596
  434. package/dist/tooltip-Dt77sBeT.js +0 -390
  435. package/dist/treeView-QDETBFTQ-DU8LwHuf.js +0 -3
  436. package/dist/treemap-6X3UGDF4-DUk4-k_O.js +0 -3
  437. package/dist/useTheme-CVJ0UOf2.js +0 -841
  438. package/dist/vega-loader.browser-DEggZzni.js +0 -1083
  439. package/dist/wardley-OPB4EBWU-Db-AaGas.js +0 -3
  440. package/src/components/editor/output/EmotionCacheProvider.tsx +0 -32
@@ -0,0 +1,117 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ import { act, renderHook } from "@testing-library/react";
4
+ import { createStore, Provider } from "jotai";
5
+ import { beforeEach, describe, expect, it, vi } from "vitest";
6
+ import { MockNotebook } from "@/__mocks__/notebook";
7
+ import { notebookAtom } from "@/core/cells/cells";
8
+ import { CellId } from "@/core/cells/ids";
9
+ import { type AppMode, viewStateAtom } from "@/core/mode";
10
+ import { useExpandedConsoleOutput, useExpandedOutput } from "../outputs";
11
+
12
+ const saveCellConfig = vi.fn().mockResolvedValue(null);
13
+
14
+ vi.mock("@/core/network/requests", () => ({
15
+ getRequestClient: () => ({ saveCellConfig }),
16
+ }));
17
+
18
+ function setup(opts: { mode: AppMode; expandOutput?: boolean }) {
19
+ const cellId = CellId.create();
20
+ const store = createStore();
21
+ store.set(
22
+ notebookAtom,
23
+ MockNotebook.notebookState({
24
+ cellData: {
25
+ [cellId]: { config: { expand_output: opts.expandOutput ?? false } },
26
+ },
27
+ }),
28
+ );
29
+ store.set(viewStateAtom, { mode: opts.mode, cellAnchor: null });
30
+
31
+ const { result } = renderHook(() => useExpandedOutput(cellId), {
32
+ wrapper: ({ children }) => <Provider store={store}>{children}</Provider>,
33
+ });
34
+
35
+ return { cellId, store, result };
36
+ }
37
+
38
+ const configOf = (store: ReturnType<typeof createStore>, cellId: CellId) =>
39
+ store.get(notebookAtom).cellData[cellId].config;
40
+
41
+ describe("useExpandedOutput", () => {
42
+ beforeEach(() => {
43
+ vi.clearAllMocks();
44
+ });
45
+
46
+ it("reads the initial state from the cell's expand_output config", () => {
47
+ expect(setup({ mode: "edit" }).result.current[0]).toBe(false);
48
+ expect(setup({ mode: "edit", expandOutput: true }).result.current[0]).toBe(
49
+ true,
50
+ );
51
+ });
52
+
53
+ it("persists the toggle to the cell's config in edit mode", () => {
54
+ const { cellId, store, result } = setup({ mode: "edit" });
55
+
56
+ act(() => result.current[1](true));
57
+
58
+ expect(result.current[0]).toBe(true);
59
+ expect(configOf(store, cellId).expand_output).toBe(true);
60
+ expect(saveCellConfig).toHaveBeenCalledWith({
61
+ configs: { [cellId]: { expand_output: true } },
62
+ });
63
+ });
64
+
65
+ it("collapses by clearing the config", () => {
66
+ const { cellId, store, result } = setup({
67
+ mode: "edit",
68
+ expandOutput: true,
69
+ });
70
+
71
+ act(() => result.current[1](false));
72
+
73
+ expect(result.current[0]).toBe(false);
74
+ expect(configOf(store, cellId).expand_output).toBe(false);
75
+ expect(saveCellConfig).toHaveBeenCalledWith({
76
+ configs: { [cellId]: { expand_output: false } },
77
+ });
78
+ });
79
+
80
+ it("keeps the toggle in memory outside of edit mode", () => {
81
+ const { cellId, store, result } = setup({ mode: "read" });
82
+
83
+ act(() => result.current[1](true));
84
+
85
+ expect(result.current[0]).toBe(true);
86
+ // Cell configs are read-only outside of edit mode.
87
+ expect(configOf(store, cellId).expand_output).toBe(false);
88
+ expect(saveCellConfig).not.toHaveBeenCalled();
89
+ });
90
+
91
+ it("still honors expand_output outside of edit mode", () => {
92
+ const { result } = setup({ mode: "read", expandOutput: true });
93
+ expect(result.current[0]).toBe(true);
94
+ });
95
+
96
+ // `expand_output` covers the cell's output area only. Console output is
97
+ // clamped independently and stays an in-memory, per-session toggle.
98
+ it("does not touch the config when console output is expanded", () => {
99
+ const cellId = CellId.create();
100
+ const store = createStore();
101
+ store.set(
102
+ notebookAtom,
103
+ MockNotebook.notebookState({ cellData: { [cellId]: {} } }),
104
+ );
105
+ store.set(viewStateAtom, { mode: "edit", cellAnchor: null });
106
+
107
+ const { result } = renderHook(() => useExpandedConsoleOutput(cellId), {
108
+ wrapper: ({ children }) => <Provider store={store}>{children}</Provider>,
109
+ });
110
+
111
+ act(() => result.current[1](true));
112
+
113
+ expect(result.current[0]).toBe(true);
114
+ expect(configOf(store, cellId).expand_output).toBe(false);
115
+ expect(saveCellConfig).not.toHaveBeenCalled();
116
+ });
117
+ });
@@ -194,9 +194,10 @@ describe("pending-delete-service", () => {
194
194
  wrapper,
195
195
  });
196
196
  expect(result.current.isPending).toBe(true);
197
- if (result.current.isPending) {
198
- expect(result.current.shouldConfirmDelete).toBe(false);
199
- expect("confirm" in result.current).toBe(false);
197
+ if (!result.current.isPending) {
198
+ throw new Error("Expected cell deletion to be pending");
200
199
  }
200
+ expect(result.current.shouldConfirmDelete).toBe(false);
201
+ expect("confirm" in result.current).toBe(false);
201
202
  });
202
203
  });
@@ -59,6 +59,7 @@ describe("notebookStateFromSession", () => {
59
59
  column: config?.column ?? null,
60
60
  disabled: config?.disabled ?? null,
61
61
  hide_code: config?.hide_code ?? null,
62
+ expand_output: config?.expand_output ?? null,
62
63
  },
63
64
  });
64
65
 
@@ -298,6 +299,7 @@ describe("notebookStateFromSession", () => {
298
299
  hide_code: false,
299
300
  disabled: false,
300
301
  column: null,
302
+ expand_output: false,
301
303
  },
302
304
  serializedEditorState: null,
303
305
  });
@@ -309,6 +311,7 @@ describe("notebookStateFromSession", () => {
309
311
  hide_code: true,
310
312
  disabled: true,
311
313
  column: 1,
314
+ expand_output: true,
312
315
  }),
313
316
  ]);
314
317
  const result = notebookStateFromSession(null, notebook);
@@ -319,6 +322,7 @@ describe("notebookStateFromSession", () => {
319
322
  hide_code: true,
320
323
  disabled: true,
321
324
  column: 1,
325
+ expand_output: true,
322
326
  });
323
327
  });
324
328
 
@@ -350,6 +354,7 @@ describe("notebookStateFromSession", () => {
350
354
  hide_code: false,
351
355
  disabled: false,
352
356
  column: null,
357
+ expand_output: false,
353
358
  },
354
359
  serializedEditorState: null,
355
360
  });
@@ -386,6 +391,7 @@ describe("notebookStateFromSession", () => {
386
391
  hide_code: false,
387
392
  disabled: false,
388
393
  column: null,
394
+ expand_output: false,
389
395
  },
390
396
  serializedEditorState: null,
391
397
  });
@@ -426,6 +432,7 @@ describe("notebookStateFromSession", () => {
426
432
  hide_code: false,
427
433
  disabled: false,
428
434
  column: null,
435
+ expand_output: false,
429
436
  },
430
437
  serializedEditorState: null,
431
438
  });
@@ -126,7 +126,15 @@ export function transitionCell(
126
126
  nextCell.debuggerActive = false;
127
127
  consoleOutputs = consoleOutputs.map((output) => {
128
128
  if (output.channel === "stdin") {
129
- return { ...output, response: output.response ?? "" };
129
+ // StatefulOutputMessage exposes data through a getter, which object
130
+ // spread would omit.
131
+ return {
132
+ channel: output.channel,
133
+ mimetype: output.mimetype,
134
+ data: output.data,
135
+ timestamp: output.timestamp,
136
+ response: output.response ?? "",
137
+ };
130
138
  }
131
139
  return output;
132
140
  });
@@ -125,7 +125,12 @@ export interface NotebookState {
125
125
  }
126
126
 
127
127
  function withScratchCell(notebookState: NotebookState): NotebookState {
128
- const config = { column: 0, hide_code: false, disabled: false };
128
+ const config = {
129
+ column: 0,
130
+ hide_code: false,
131
+ disabled: false,
132
+ expand_output: false,
133
+ };
129
134
  return {
130
135
  ...notebookState,
131
136
  cellData: {
@@ -1365,10 +1370,7 @@ const {
1365
1370
 
1366
1371
  // Find the start/end of the collapsed ranges
1367
1372
  const nodes = [...column.nodes];
1368
- const rangeIndexes: {
1369
- start: CellIndex;
1370
- end: CellIndex;
1371
- }[] = [];
1373
+ const visibleEndByOriginalEnd = new Map<CellIndex, CellIndex>();
1372
1374
  const reversedCollapseRanges = [];
1373
1375
 
1374
1376
  // Iterate in reverse order (bottom-up) to process children first
@@ -1377,20 +1379,13 @@ const {
1377
1379
  const range = findCollapseRange(i, outlines);
1378
1380
  if (range) {
1379
1381
  const startIndex = i;
1380
- let endIndex = range[1];
1381
-
1382
- // Check if the parent's end point is inside any already-collapsed child range
1383
- const parentEndInChild = rangeIndexes.find(
1384
- (child) => child.start <= endIndex && child.end === endIndex,
1385
- );
1386
-
1387
- if (parentEndInChild) {
1388
- // Adjust the new endIndex to the child's start
1389
- endIndex = parentEndInChild.start;
1390
- }
1382
+ const originalEnd = range[1];
1383
+ const endIndex =
1384
+ visibleEndByOriginalEnd.get(originalEnd) ?? originalEnd;
1391
1385
 
1392
- // Store this range for future child checks
1393
- rangeIndexes.push({ start: startIndex, end: endIndex });
1386
+ // After this section collapses, its heading represents this
1387
+ // endpoint for any enclosing section that shares it.
1388
+ visibleEndByOriginalEnd.set(originalEnd, startIndex);
1394
1389
 
1395
1390
  // Add the range to the list of ranges
1396
1391
  const cellId = column.atOrThrow(startIndex);
@@ -164,6 +164,7 @@ function columnChanges(
164
164
  column: newCol,
165
165
  disabled: cell?.config.disabled ?? false,
166
166
  hideCode: cell?.config.hide_code ?? false,
167
+ expandOutput: cell?.config.expand_output ?? false,
167
168
  });
168
169
  }
169
170
  }
@@ -277,6 +278,7 @@ export function toDocumentChanges(
277
278
  column: cell.config.column ?? null,
278
279
  disabled: cell.config.disabled ?? false,
279
280
  hideCode: cell.config.hide_code ?? false,
281
+ expandOutput: cell.config.expand_output ?? false,
280
282
  },
281
283
  ];
282
284
  }
@@ -452,7 +454,11 @@ export function fromDocumentChanges(
452
454
  payload: { cellId: change.cellId, name: change.name },
453
455
  });
454
456
  }
455
- if (change.config?.disabled != null || change.config?.column != null) {
457
+ if (
458
+ change.config?.disabled != null ||
459
+ change.config?.column != null ||
460
+ change.config?.expand_output != null
461
+ ) {
456
462
  actions.push({
457
463
  type: "updateCellConfig",
458
464
  payload: {
@@ -464,6 +470,9 @@ export function fromDocumentChanges(
464
470
  ...(change.config.column != null && {
465
471
  column: change.config.column,
466
472
  }),
473
+ ...(change.config.expand_output != null && {
474
+ expand_output: change.config.expand_output,
475
+ }),
467
476
  },
468
477
  },
469
478
  });
@@ -560,6 +569,7 @@ export function fromDocumentChanges(
560
569
  column: change.column,
561
570
  disabled: change.disabled,
562
571
  hide_code: change.hideCode,
572
+ expand_output: change.expandOutput,
563
573
  },
564
574
  },
565
575
  });
@@ -1,34 +1,91 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
- import { useEffect, useState } from "react";
3
+ import { useAtomValue } from "jotai";
4
+ import { selectAtom } from "jotai/utils";
5
+ import { useEffect, useMemo, useState } from "react";
6
+ import { useEvent } from "@/hooks/useEvent";
7
+ import { Logger } from "@/utils/Logger";
4
8
  import type { OutputMessage } from "../kernel/messages";
9
+ import { viewStateAtom } from "../mode";
10
+ import { getRequestClient } from "../network/requests";
11
+ import { cellDataAtom, useCellActions } from "./cells";
5
12
  import type { CellId } from "./ids";
6
13
 
7
14
  // This does not need to be overcomplicated. We can just store the expanded
8
15
  // state in a global map instead of Jotai since state is not shared between cells.
16
+ // The output area only falls back to its map where the `expand_output` config
17
+ // cannot be edited; see `useExpandedOutput`.
9
18
  const expandedOutputs: Record<CellId, boolean> = {};
10
19
  const expandedConsoleOutputs: Record<CellId, boolean> = {};
11
20
 
21
+ /**
22
+ * Whether a cell's output is shown in full, instead of clamped to a fixed
23
+ * height. Covers the cell's output area only; console output is clamped
24
+ * independently, via `useExpandedConsoleOutput`.
25
+ *
26
+ * In edit mode, we toggle the cell's `expand_output` config, so the choice is persisted.
27
+ */
12
28
  export function useExpandedOutput(cellId: CellId) {
13
- const [state, setState] = useState(expandedOutputs[cellId] ?? false);
29
+ const { mode } = useAtomValue(viewStateAtom);
30
+ const { updateCellConfig } = useCellActions();
31
+ // Select just the flag: every output would otherwise re-render on each
32
+ // keystroke in its cell.
33
+ const isConfigExpanded = useAtomValue(
34
+ useMemo(
35
+ () =>
36
+ selectAtom(
37
+ cellDataAtom(cellId),
38
+ (data) => data?.config.expand_output ?? false,
39
+ Object.is,
40
+ ),
41
+ [cellId],
42
+ ),
43
+ );
44
+ const [isSessionExpanded, setIsSessionExpanded] = useState(
45
+ () => expandedOutputs[cellId] ?? isConfigExpanded,
46
+ );
14
47
 
15
48
  // Sync state to external storage
16
49
  useEffect(() => {
17
- expandedOutputs[cellId] = state;
18
- }, [cellId, state]);
50
+ expandedOutputs[cellId] = isSessionExpanded;
51
+ }, [cellId, isSessionExpanded]);
19
52
 
20
- return [state, setState] as const;
53
+ const isEditable = mode === "edit";
54
+ const isExpanded = isEditable ? isConfigExpanded : isSessionExpanded;
55
+
56
+ const setIsExpanded = useEvent((expanded: boolean) => {
57
+ setIsSessionExpanded(expanded);
58
+ if (!isEditable) {
59
+ return;
60
+ }
61
+ const config = { expand_output: expanded };
62
+ updateCellConfig({ cellId, config });
63
+ getRequestClient()
64
+ .saveCellConfig({ configs: { [cellId]: config } })
65
+ .catch((error) => {
66
+ Logger.error("Failed to save expand_output config", error);
67
+ });
68
+ });
69
+
70
+ return [isExpanded, setIsExpanded] as const;
21
71
  }
22
72
 
73
+ /**
74
+ * Whether a cell's console output is shown in full. Deliberately not backed by
75
+ * `expand_output`: that config covers the cell's output area only, so console
76
+ * output stays a per-session, in-memory toggle.
77
+ */
23
78
  export function useExpandedConsoleOutput(cellId: CellId) {
24
- const [state, setState] = useState(expandedConsoleOutputs[cellId] ?? false);
79
+ const [isExpanded, setIsExpanded] = useState(
80
+ expandedConsoleOutputs[cellId] ?? false,
81
+ );
25
82
 
26
83
  // Sync state to external storage
27
84
  useEffect(() => {
28
- expandedConsoleOutputs[cellId] = state;
29
- }, [cellId, state]);
85
+ expandedConsoleOutputs[cellId] = isExpanded;
86
+ }, [cellId, isExpanded]);
30
87
 
31
- return [state, setState] as const;
88
+ return [isExpanded, setIsExpanded] as const;
32
89
  }
33
90
 
34
91
  export function isOutputEmpty(
@@ -1,7 +1,6 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
3
  import { useAtomValue, useStore } from "jotai";
4
- import { useMemo } from "react";
5
4
  import {
6
5
  useDeleteCellCallback,
7
6
  useDeleteManyCellsCallback,
@@ -130,21 +129,18 @@ export function usePendingDeleteService() {
130
129
  const { entries } = useAtomValue(pendingDeleteStateAtom);
131
130
  const deleteCell = useDeleteCellCallback();
132
131
  const deleteManyCells = useDeleteManyCellsCallback();
133
- return useMemo(
134
- () => ({
135
- submit: (cellIds: CellId[]) => {
136
- submit({ cellIds, deleteCell, deleteManyCells, store });
137
- },
138
- clear,
139
- get idle() {
140
- return entries.size === 0;
141
- },
142
- get shouldConfirmDelete() {
143
- return entries.size > 1;
144
- },
145
- }),
146
- [store, submit, clear, entries, deleteCell, deleteManyCells],
147
- );
132
+ return {
133
+ submit: (cellIds: CellId[]) => {
134
+ submit({ cellIds, deleteCell, deleteManyCells, store });
135
+ },
136
+ clear,
137
+ get idle() {
138
+ return entries.size === 0;
139
+ },
140
+ get shouldConfirmDelete() {
141
+ return entries.size > 1;
142
+ },
143
+ };
148
144
  }
149
145
 
150
146
  export function usePendingDelete(cellId: CellId) {
@@ -149,6 +149,7 @@ function createEmptyNotebookCell(): NotebookCell {
149
149
  column: null,
150
150
  disabled: false,
151
151
  hide_code: false,
152
+ expand_output: false,
152
153
  },
153
154
  };
154
155
  }
@@ -177,6 +178,7 @@ function createCellDataFromNotebook(
177
178
  column: notebookCell.config?.column ?? null,
178
179
  disabled: notebookCell.config?.disabled ?? false,
179
180
  hide_code: notebookCell.config?.hide_code ?? false,
181
+ expand_output: notebookCell.config?.expand_output ?? false,
180
182
  },
181
183
  serializedEditorState: null,
182
184
  };
@@ -27,6 +27,7 @@ export function createCell({
27
27
  hide_code: false,
28
28
  disabled: false,
29
29
  column: null,
30
+ expand_output: false,
30
31
  },
31
32
  name: name,
32
33
  code: code,
@@ -42,6 +43,7 @@ export function createCellConfig(config?: Partial<CellConfig>): CellConfig {
42
43
  hide_code: false,
43
44
  disabled: false,
44
45
  column: null,
46
+ expand_output: false,
45
47
  ...config,
46
48
  };
47
49
  }
@@ -500,17 +500,15 @@ describe("navigate", () => {
500
500
  const view1Positions = result.position.get(view1);
501
501
  const view2Positions = result.position.get(view2);
502
502
 
503
- if (view1Positions) {
504
- expect(view1Positions.size).toBeGreaterThan(0);
505
- // Check that position keys are in "from:to" format
506
- for (const key of view1Positions.keys()) {
507
- expect(key).toMatch(/^\d+:\d+$/);
508
- }
503
+ invariant(view1Positions, "Expected positions for the first view");
504
+ expect(view1Positions.size).toBeGreaterThan(0);
505
+ // Check that position keys are in "from:to" format
506
+ for (const key of view1Positions.keys()) {
507
+ expect(key).toMatch(/^\d+:\d+$/);
509
508
  }
510
509
 
511
- if (view2Positions) {
512
- expect(view2Positions.size).toBeGreaterThan(0);
513
- }
510
+ invariant(view2Positions, "Expected positions for the second view");
511
+ expect(view2Positions.size).toBeGreaterThan(0);
514
512
  });
515
513
 
516
514
  it("should handle regex patterns", () => {
@@ -654,13 +652,7 @@ describe("navigate", () => {
654
652
 
655
653
  const result = findNext();
656
654
  // Should still work by starting from index 0
657
- if (result) {
658
- expect(result).toBeTruthy();
659
- invariant(result, "findNext should return a result");
660
- } else {
661
- // It's ok if no match is found since "hello" might not be in the mock views
662
- expect(result).toBe(false);
663
- }
655
+ expect(result).toMatchObject({ from: 0, to: 5 });
664
656
  });
665
657
 
666
658
  it("should handle malformed regex in replace pattern", () => {
@@ -17,6 +17,7 @@ import type {
17
17
  import type { DataSourceConnection } from "@/core/datasets/data-source-connections";
18
18
  import {
19
19
  dataSourceConnectionsAtom,
20
+ exportedForTesting as dataSourceTesting,
20
21
  setLatestEngineSelected,
21
22
  } from "@/core/datasets/data-source-connections";
22
23
  import { type ConnectionName, DUCKDB_ENGINE } from "@/core/datasets/engines";
@@ -550,8 +551,8 @@ _df = mo.sql(
550
551
  const getLatestEngine = () =>
551
552
  store.get(dataSourceConnectionsAtom).latestEngineSelected;
552
553
 
553
- it("should use default engine initially", () => {
554
- expect(getLatestEngine()).toBe(DUCKDB_ENGINE);
554
+ it("should have no selected engine initially", () => {
555
+ expect(getLatestEngine()).toBeNull();
555
556
  });
556
557
 
557
558
  it("should persist the selected engine", () => {
@@ -622,6 +623,73 @@ _df = mo.sql(
622
623
  });
623
624
 
624
625
  describe("defaultCode", () => {
626
+ it("should prefer the newest usable connection until an engine is selected", () => {
627
+ const previousState = store.get(dataSourceConnectionsAtom);
628
+ const connection: DataSourceConnection = {
629
+ name: "first_connection" as ConnectionName,
630
+ source: "sqlite",
631
+ display_name: "SQLite",
632
+ dialect: "sqlite",
633
+ databases: [],
634
+ };
635
+ const newestConnection = {
636
+ ...connection,
637
+ name: "newest_connection" as ConnectionName,
638
+ };
639
+ const icebergConnection = {
640
+ ...connection,
641
+ name: "catalog" as ConnectionName,
642
+ source: "iceberg",
643
+ };
644
+ try {
645
+ store.set(dataSourceConnectionsAtom, {
646
+ latestEngineSelected: null,
647
+ connectionsMap: new Map(),
648
+ });
649
+ expect(adapter.defaultMetadata.engine).toBe(DUCKDB_ENGINE);
650
+ expect(adapter.defaultCode).toBe('_df = mo.sql(f"""SELECT * FROM """)');
651
+
652
+ store.set(dataSourceConnectionsAtom, {
653
+ latestEngineSelected: null,
654
+ connectionsMap: new Map([
655
+ [connection.name, connection],
656
+ [newestConnection.name, newestConnection],
657
+ [icebergConnection.name, icebergConnection],
658
+ [DUCKDB_ENGINE, { ...connection, name: DUCKDB_ENGINE }],
659
+ ]),
660
+ });
661
+ expect(adapter.defaultMetadata.engine).toBe(newestConnection.name);
662
+ expect(adapter.defaultCode).toContain("engine=newest_connection");
663
+ expect(
664
+ store.get(dataSourceConnectionsAtom).latestEngineSelected,
665
+ ).toBeNull();
666
+
667
+ const refreshConnection = (connection: DataSourceConnection) => {
668
+ store.set(
669
+ dataSourceConnectionsAtom,
670
+ dataSourceTesting.reducer(store.get(dataSourceConnectionsAtom), {
671
+ type: "addDataSourceConnection",
672
+ payload: { connections: [connection] },
673
+ }),
674
+ );
675
+ };
676
+ refreshConnection(connection);
677
+ expect(adapter.defaultMetadata.engine).toBe(connection.name);
678
+ expect(adapter.defaultCode).toContain("engine=first_connection");
679
+
680
+ setLatestEngineSelected(connection.name);
681
+ refreshConnection(newestConnection);
682
+ expect(adapter.defaultCode).toContain("engine=first_connection");
683
+
684
+ setLatestEngineSelected(DUCKDB_ENGINE);
685
+ refreshConnection(connection);
686
+ expect(adapter.defaultMetadata.engine).toBe(DUCKDB_ENGINE);
687
+ expect(adapter.defaultCode).toBe('_df = mo.sql(f"""SELECT * FROM """)');
688
+ } finally {
689
+ store.set(dataSourceConnectionsAtom, previousState);
690
+ }
691
+ });
692
+
625
693
  it("should include engine in defaultCode when selected", () => {
626
694
  const engine = "postgres_engine" as ConnectionName;
627
695
  setLatestEngineSelected(engine);
@@ -17,14 +17,10 @@ describe("parsePython", () => {
17
17
  const pythonParser = python().language.parser;
18
18
  const config = parsePython(pythonParser, IS_ACTIVE);
19
19
 
20
- expect(config.defineNodes).toBeDefined();
21
- if (config.defineNodes) {
22
- expect(config.defineNodes).toHaveLength(2);
23
- // @ts-expect-error - we know that the defineNodes are NodeSpec
24
- expect(config.defineNodes[0].name).toBe("Python");
25
- // @ts-expect-error - we know that the defineNodes are NodeSpec
26
- expect(config.defineNodes[1].name).toBe("PythonMark");
27
- }
20
+ expect(config.defineNodes).toMatchObject([
21
+ { name: "Python" },
22
+ { name: "PythonMark" },
23
+ ]);
28
24
  });
29
25
 
30
26
  it("should not parse double curly braces", () => {
@@ -76,7 +76,22 @@ export interface SQLLanguageAdapterMetadata extends SQLMetadata {
76
76
  }
77
77
 
78
78
  function getLatestEngine(): ConnectionName {
79
- return store.get(dataSourceConnectionsAtom).latestEngineSelected;
79
+ const { latestEngineSelected, connectionsMap } = store.get(
80
+ dataSourceConnectionsAtom,
81
+ );
82
+ if (latestEngineSelected !== null) {
83
+ return latestEngineSelected;
84
+ }
85
+
86
+ // Map insertion order prefers the most recently discovered connection.
87
+ const connections = [...connectionsMap.values()].reverse();
88
+ return (
89
+ connections.find(
90
+ (connection) =>
91
+ !INTERNAL_SQL_ENGINES.has(connection.name) &&
92
+ connection.source !== "iceberg",
93
+ )?.name ?? DUCKDB_ENGINE
94
+ );
80
95
  }
81
96
 
82
97
  /**
@@ -47,7 +47,10 @@ const awarenessLogger = logger.get("awareness").disabled();
47
47
  const AWARENESS_PREFIX = "awareness:";
48
48
 
49
49
  // Utility functions for message handling
50
- function prefixMessage(token: string, message: Uint8Array): Uint8Array {
50
+ function prefixMessage(
51
+ token: string,
52
+ message: Uint8Array,
53
+ ): Uint8Array<ArrayBuffer> {
51
54
  const tokenBytes = new TextEncoder().encode(token);
52
55
  return new Uint8Array([...tokenBytes, ...message]);
53
56
  }
@@ -154,7 +157,7 @@ if (isRtcEnabled()) {
154
157
  doc.subscribeLocalUpdates((update) => {
155
158
  logger.debug("local update, sending to server");
156
159
  const ws = getWs();
157
- ws.send(update);
160
+ ws.send(new Uint8Array(update));
158
161
  });
159
162
 
160
163
  // Handle awareness changes