@marimo-team/islands 0.24.3-dev3 → 0.24.3-dev31

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 (293) hide show
  1. package/dist/{ConnectedDataExplorerComponent-qIKbwYin.js → ConnectedDataExplorerComponent-BLO7UDpo.js} +18 -18
  2. package/dist/{ErrorBoundary-CR-ZQN_c.js → ErrorBoundary-B7uSdDUm.js} +6 -6
  3. package/dist/{ImageComparisonComponent-2a9TMMm2.js → ImageComparisonComponent-RspMflu6.js} +3 -3
  4. package/dist/{Plot-C-9MQeGP.js → Plot-CTyjbQDT.js} +21032 -20666
  5. package/dist/_baseMerge-Bnytch8P.js +165 -0
  6. package/dist/{abnfDiagram-N423BO3Z-CQKwzX8t.js → abnfDiagram-VCTEODGH-DCb2K_RB.js} +17 -18
  7. package/dist/{any-language-editor-CpTnK43-.js → any-language-editor-C0dftc2Z.js} +8 -8
  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-Bb_n642s.js} +25 -25
  11. package/dist/assets/__vite-browser-external-BajL8aoc.js +1 -0
  12. package/dist/assets/worker-BemUy60C.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/{channel-CyiYUzJv.js → channel-B5XnTarr.js} +1 -1
  18. package/dist/chat-ui-DiMxe-GH.js +5835 -0
  19. package/dist/{check-CHig47QV.js → check-mcQyZmFG.js} +1 -1
  20. package/dist/{chunk-2Q5K7J3B-BMuJl2jB.js → chunk-2Q5K7J3B-BMkUkeuy.js} +2 -2
  21. package/dist/chunk-4HAMMTFA-D2qv8E0X.js +4188 -0
  22. package/dist/{chunk-5VM5RSS4-Bcq0ftdy.js → chunk-5VM5RSS4-DKsmPCL6.js} +2 -2
  23. package/dist/{chunk-NSK5VX7P-CDTMcJB0.js → chunk-75Z2AOVW-5_HsvXwr.js} +23 -23
  24. package/dist/{chunk-I66GZJ75-BqyTCAPf.js → chunk-DU6HZSFF-BUgAHvnM.js} +21 -4
  25. package/dist/{chunk-2GRJ4B5K-DgO8Qudq.js → chunk-F27PBJKO-DHmYWZXr.js} +4 -4
  26. package/dist/{chunk-KEIR6QF5-C4KX3XYh.js → chunk-FOHPRMQF-BpYR8RqP.js} +4 -4
  27. package/dist/{chunk-WRU74C26-BpWsbiDK.js → chunk-GMAD6QVW-Czynz8aA.js} +486 -258
  28. package/dist/chunk-GVQU2GXP-yQEdulRS.js +37 -0
  29. package/dist/{chunk-5RXB4S5H-tLNUVDdO.js → chunk-IMKFNOWR-Du9BN2Ul.js} +11 -11
  30. package/dist/{chunk-JWPE2WC7-BJwjGUnF.js → chunk-JWPE2WC7-DJvv1t8U.js} +2 -2
  31. package/dist/chunk-L3NEJ4N5-DwRWnDDK.js +245 -0
  32. package/dist/{chunk-7Z6QIM7H-Dc18hFxH.js → chunk-OSK3NFVY-BBKU_Ign.js} +222 -144
  33. package/dist/{chunk-W5SLKNZC-DLnvpEtV.js → chunk-P2QGCYS3-C0iGU29N.js} +20 -20
  34. package/dist/{chunk-KBJHAD2P-BuqWqkcW.js → chunk-POPQ4Y6H-BCbS3Ozc.js} +4 -4
  35. package/dist/{chunk-4I5QYGJK-DpytHuZQ.js → chunk-PWAF6VOD-CTFCL0jI.js} +4 -4
  36. package/dist/{chunk-JQJVKLGR-CgqCwe8E.js → chunk-SHT3W25Y-tUelricH.js} +109 -63
  37. package/dist/{chunk-6Q2QTUOP-DmTcEBMn.js → chunk-SVP7TREG-DK3egkfQ.js} +5 -5
  38. package/dist/{chunk-GF5L2VYU-B0wgCQgS.js → chunk-TICWLB2K-DRANTdnp.js} +13 -13
  39. package/dist/{chunk-XXDRQBXY-D73H4IN0.js → chunk-XXDRQBXY-Dnl5VBqG.js} +3 -3
  40. package/dist/{chunk-Y2CYZVJY-DoegUj_e.js → chunk-Y2CYZVJY-DKKS1VyV.js} +1 -1
  41. package/dist/{chunk-5FQGJX7Z-B85XCPv6.js → chunk-YOKDWASO-DrWbKnxA.js} +6925 -5460
  42. package/dist/classDiagram-ZZMXUADV-7wCSVH7o.js +30 -0
  43. package/dist/classDiagram-v2-VYDZK3BY-QwnvcnhB.js +30 -0
  44. package/dist/{common-CwJerb7K.js → common-BTmw6ocq.js} +7398 -6912
  45. package/dist/{compiler-runtime-CAH9RLw2.js → compiler-runtime-Cj8ZWiNS.js} +2 -2
  46. package/dist/{copy-CD7S58CY.js → copy-C0N4m1lm.js} +4 -4
  47. package/dist/{cose-bilkent-JH36ORCC-FUWHkXFX.js → cose-bilkent-JH36ORCC-_LyRKVqm.js} +2 -2
  48. package/dist/cubic-OaEBhQPK.js +1404 -0
  49. package/dist/cynefin-OW5HDTMX-obq-i80l.js +3 -0
  50. package/dist/{cynefinDiagram-MW4NZA55-BXSFK93J.js → cynefinDiagram-5FMLGOSQ-CB7O4IZB.js} +10 -10
  51. package/dist/{dagre-CGyalH38.js → dagre-DfYd3btw.js} +678 -537
  52. package/dist/dagre-GXQ25YYZ-C-a95ISW.js +425 -0
  53. package/dist/{data-grid-overlay-editor-DZM4BAaI.js → data-grid-overlay-editor-C5eUZVTo.js} +8 -9
  54. package/dist/{data-grid-types-BnZwWG8z.js → data-grid-types-BucVmDDp.js} +1 -1
  55. package/dist/{defaultLocale-DKaU_opG.js → defaultLocale-JI_lnoCe.js} +1 -1
  56. package/dist/{diagram-7IWD3JNH-BjfzDNvj.js → diagram-S7CK7UJ4-BsKLYQaH.js} +40 -39
  57. package/dist/{diagram-UB23O5K3-DDg-7wLA.js → diagram-UQ7AKVKN-ppYdvuTN.js} +10 -10
  58. package/dist/{diagram-B4RE2ZJO-CKccR9eE.js → diagram-VSXAHHWV-BKpmG23x.js} +10 -10
  59. package/dist/{diagram-Q27KOJAE-Zhz01ss7.js → diagram-VX7I27RA-CAMK2l0E.js} +21 -21
  60. package/dist/{diagram-LBJQPF4R-CJ-bOruh.js → diagram-Z3DM3KII-CxQ7MggT.js} +10 -10
  61. package/dist/{dist-dAqZAPcF.js → dist-1HDa70oE.js} +3 -3
  62. package/dist/{dist-3_o3T78I.js → dist-6ChWbo8z.js} +13 -13
  63. package/dist/{dist-Re9sOPOx.js → dist-9x1ZRe-e.js} +2 -2
  64. package/dist/{dist-DEeLqRlU.js → dist-B1vYLK28.js} +1 -1
  65. package/dist/{dist-C5Bn52W4.js → dist-B8D7McG3.js} +3 -3
  66. package/dist/{dist-_XvgytiS.js → dist-BHCHt1NI.js} +1 -1
  67. package/dist/{dist-CRjAdnqF.js → dist-BRxfaJgs.js} +3 -3
  68. package/dist/{dist-Byj2bV8o.js → dist-BVGtK7Ht.js} +1 -1
  69. package/dist/{dist-BIN5LKyE.js → dist-BaHjhkpZ.js} +2 -2
  70. package/dist/{dist-DVFbIwc5.js → dist-BtKIs9N-.js} +1 -1
  71. package/dist/{dist-BrQGcfQ9.js → dist-C2KzV-vf.js} +2 -2
  72. package/dist/{dist-DJFiGP2k.js → dist-C2wDlYdD.js} +2 -2
  73. package/dist/{dist-BVRM2y1P.js → dist-C8xMLVYi.js} +2 -2
  74. package/dist/dist-CMh_W4y4.js +538 -0
  75. package/dist/{dist-BzN60Z2s.js → dist-CPGxfVGX.js} +1 -1
  76. package/dist/{dist-C7v-9nUK.js → dist-Cm3iAFMD.js} +3 -3
  77. package/dist/{dist-CGAxEiaM.js → dist-Cs2FijYk.js} +2 -2
  78. package/dist/{dist-hXd65f0_.js → dist-D1PpnuZB.js} +1 -1
  79. package/dist/{dist-VdvbxG72.js → dist-DHOTQar0.js} +1 -1
  80. package/dist/{dist-DcgzXCfy.js → dist-DPcEtqmG.js} +2 -2
  81. package/dist/{dist-D4Z_qdP4.js → dist-Df0wKI0F.js} +1 -1
  82. package/dist/{dist-qhLI-SHd.js → dist-DszxuxS1.js} +2 -2
  83. package/dist/{dist-BEmkrGoQ.js → dist-Kxgjxakw.js} +1 -1
  84. package/dist/{dist-BbSMhhD2.js → dist-KzZ7WELx.js} +2 -2
  85. package/dist/{dist-jWUab2d1.js → dist-lA1Cttkb.js} +1 -1
  86. package/dist/{dropdown-menu-DhCfcscX.js → dropdown-menu-C73aTomr.js} +184 -184
  87. package/dist/{ebnfDiagram-BXEA7PRR-Dm75pCAS.js → ebnfDiagram-PWID7BFC-DzybELvk.js} +17 -18
  88. package/dist/{erDiagram-JOGREHBK-rVDG3VSQ.js → erDiagram-RLTQ6QDP-BVxV97ld.js} +1037 -798
  89. package/dist/{error-banner-WDhUzJyg.js → error-banner-hCaH06e3.js} +207 -207
  90. package/dist/{esm-CR1nhb1c.js → esm-BElI3qKH.js} +22 -22
  91. package/dist/{esm-C1d0g6Bv.js → esm-G4Fhsgng.js} +51 -37
  92. package/dist/{esm-CesmlDrs.js → esm-blALgIVy.js} +332 -319
  93. package/dist/eventmodeling-NTZA5JFV-D7nP7Uyu.js +3 -0
  94. package/dist/{extends-BPB6_lTK.js → extends-Do6pRuJa.js} +8 -8
  95. package/dist/flowDiagram-HODETNUW-BKvXsWYX.js +16 -0
  96. package/dist/{formats-CJMVUfb3.js → formats-vDAoRpYs.js} +8 -8
  97. package/dist/{ganttDiagram-PKOTCBZU-9D-LXF6P.js → ganttDiagram-EL5Y4UJY-DbzEBLbl.js} +15 -15
  98. package/dist/gitGraph-4MIJSDKK-Dy9uQXGh.js +3 -0
  99. package/dist/{gitGraphDiagram-DS77QQ5N-BfpsXTLf.js → gitGraphDiagram-WWUBYQGX-BMf0iKi1.js} +10 -10
  100. package/dist/{glide-data-editor-sPZ8fUFn.js → glide-data-editor-Bcy8iaZa.js} +2785 -2562
  101. package/dist/{glide-utils-NShAPPtn.js → glide-utils-BMnFm0vZ.js} +4 -4
  102. package/dist/highlighted-body-KPVGNVTW-Ad3MKZ18.js +38 -0
  103. package/dist/{html-to-image-BTYnN4ev.js → html-to-image-mVIbKn_Y.js} +5720 -5452
  104. package/dist/info-A6RAGUB7-DKoayiHY.js +3 -0
  105. package/dist/{infoDiagram-6WML65LV-DqCTXHVy.js → infoDiagram-27XIBGKW-B_ucqo-U.js} +7 -7
  106. package/dist/{ishikawaDiagram-WSZJBQD7-BCUYmZ1v.js → ishikawaDiagram-5VMMS53U-BZFx9b-o.js} +8 -8
  107. package/dist/{journeyDiagram-NVQOT4AX-BXB6M4zN.js → journeyDiagram-3NMN7TZE-D2LcKDUO.js} +8 -8
  108. package/dist/{jsx-runtime-CpoKNRgu.js → jsx-runtime-DgDPJV9S.js} +1 -1
  109. package/dist/{kanban-definition-27J2QSJJ-CGRhrDUX.js → kanban-definition-UXKFOSKX-BpIfcu3G.js} +29 -29
  110. package/dist/katex-DFBiSucW.js +21840 -0
  111. package/dist/{label-lwzzBHUW.js → label-e37ixur5.js} +6 -6
  112. package/dist/{linear-D5r_1YqD.js → linear-Cnaq3Tfb.js} +4 -4
  113. package/dist/{loader-VZ__bv4g.js → loader-D2W4oM-3.js} +15 -15
  114. package/dist/main.js +7018 -12382
  115. package/dist/mermaid-B1Jb9HfY.js +3084 -0
  116. package/dist/mermaid-HWGCJPDP-DYCzSILp.js +2 -0
  117. package/dist/mermaid-parser.core-DxuSfYwJ.js +638 -0
  118. package/dist/{mhchem-BjwrxcV-.js → mhchem-DWCF06w9.js} +1 -1
  119. package/dist/{micromark-factory-space-DruVGzeG.js → micromark-factory-space-DGxAzmw8.js} +2 -2
  120. package/dist/{mindmap-definition-FAOFIHXS-C9gRhzZq.js → mindmap-definition-YA3MSWOX-CmpAfv8K.js} +17 -17
  121. package/dist/{node-sql-parser-DesT1xNw.js → node-sql-parser-BiZOJ-FS.js} +0 -3
  122. package/dist/{number-overlay-editor-De2CabLL.js → number-overlay-editor-CFofZaOi.js} +5 -5
  123. package/dist/packet-AYTQ26CC-Yw7ajchJ.js +3 -0
  124. package/dist/{pegDiagram-VL7TDLO6-Df9IUjMD.js → pegDiagram-XKGWAZYB-DO-0Q8SE.js} +19 -20
  125. package/dist/{pick-SnHlmIBN.js → pick-B7vX8zxG.js} +1 -1
  126. package/dist/pie-WAS4IAKB-BKdKOAkL.js +3 -0
  127. package/dist/{pieDiagram-7S7Q4E2Y-BmRzQ8ZP.js → pieDiagram-E7YTZNPT-B1MbuA_g.js} +29 -31
  128. package/dist/{process-output-CsALk6tp.js → process-output-Cr6U5ULK.js} +4 -4
  129. package/dist/purify.es-DgKyQviY.js +805 -0
  130. package/dist/{quadrantDiagram-CIZ2JOQS-wFBvWcxS.js → quadrantDiagram-AXDQQJYC-DftINo6g.js} +5 -5
  131. package/dist/radar-RG4KPBEZ-ScR_D_Ts.js +3 -0
  132. package/dist/railroad-74A4TZTK-DQvPSdo5.js +3 -0
  133. package/dist/railroad-abnf-HS5TGJTU-CsJQG2O8.js +3 -0
  134. package/dist/railroad-ebnf-LZEXJU2U-BgEobkSn.js +3 -0
  135. package/dist/railroad-peg-WCYAUIDC-DjLAjofI.js +3 -0
  136. package/dist/{railroadDiagram-AXF67PYL-DxbIatiN.js → railroadDiagram-O6MQD6OU-DPVOQUXC.js} +17 -18
  137. package/dist/{react-dom-C94wmq5w.js → react-dom-BUgJ-ab_.js} +3 -3
  138. package/dist/{react-DMWcHin-.js → react-ofJbxM4x.js} +2 -2
  139. package/dist/{react-vega-DSD5aT7_.js → react-vega-5AcMW8gG.js} +10012 -9369
  140. package/dist/{requirementDiagram-LRYGKXZP-X_x-Y713.js → requirementDiagram-BXWQKSXE-CC7wZ-tM.js} +20 -19
  141. package/dist/{reveal-component-DVMzBxwv.js → reveal-component-BK1wyO-B.js} +1171 -1105
  142. package/dist/{sankeyDiagram-W5VNT64P-BYJALbbm.js → sankeyDiagram-P5KCCOFB-CDKR5TJH.js} +4 -4
  143. package/dist/schemas-BDZr-nP0.js +5727 -0
  144. package/dist/{select-3qHpFKF9.js → select-UMOSCa3W.js} +246 -246
  145. package/dist/{sequenceDiagram-SI44F4Z6-BiPBe3Sv.js → sequenceDiagram-WJ2MYXX4-DomSyoJI.js} +11 -11
  146. package/dist/{sizeCapture-X5ZJPWSS-BKLDeh5H.js → sizeCapture-INFHLROL-Dx5SpkQF.js} +2 -2
  147. package/dist/{spec-CutWdqo3.js → spec-g740fOWu.js} +4 -4
  148. package/dist/{src-C31ngt98.js → src-CA_m4ONl.js} +298 -303
  149. package/dist/{stateDiagram-OKZ733FA-B7QyNBxH.js → stateDiagram-D77RDMKH-SQLLjdtF.js} +19 -20
  150. package/dist/stateDiagram-v2-MP3YSRHH-Dup4KkIr.js +30 -0
  151. package/dist/style.css +2 -2
  152. package/dist/{swimlanes-SLNWSIFB-B4f8VP3b.js → swimlanes-42K2YHIH-ZXbhyGv6.js} +1501 -1591
  153. package/dist/swimlanesDiagram-VR7AAH4N-CluwxV0g.js +30 -0
  154. package/dist/{swiper-component-C90YjhaV.js → swiper-component-IOUowglM.js} +39 -26
  155. package/dist/{time-aWGfjN8x.js → time-BieKwdYS.js} +42 -42
  156. package/dist/{timeline-definition-Z64GVDOM-Dacq_5lr.js → timeline-definition-24CTP7MA-B8i6B9RR.js} +7 -7
  157. package/dist/{toDate-D-Rx3ux5.js → toDate-C3JOXlJT.js} +10 -9
  158. package/dist/{tooltip-Dt77sBeT.js → tooltip-CdE8k0pS.js} +42 -42
  159. package/dist/treeView-Q6P3EWNA-DuRV97YF.js +3 -0
  160. package/dist/treemap-WGGIJYW6-AsLq-uwC.js +3 -0
  161. package/dist/{use-vega-container-remeasure-DUW4tRxq.js → use-vega-container-remeasure-4DwJbPWu.js} +2 -2
  162. package/dist/{useAsyncData-CH6-CgJF.js → useAsyncData-C0f7qnnN.js} +3 -3
  163. package/dist/{useDateFormatter-Cp9Jdxls.js → useDateFormatter-BKpQHt-W.js} +8 -8
  164. package/dist/{useDeepCompareMemoize-JC87C_jO.js → useDeepCompareMemoize-QCa0HbWB.js} +2 -2
  165. package/dist/{useIframeCapabilities-De3C-9b4.js → useIframeCapabilities-CVtNkI3Y.js} +2 -2
  166. package/dist/{useLifecycle-B4RGlyf0.js → useLifecycle-BGRBkTFT.js} +6 -6
  167. package/dist/useTheme-iQ0VoptU.js +904 -0
  168. package/dist/{vega-component-D-IXRnlx.js → vega-component-DRI4BDLQ.js} +15 -15
  169. package/dist/{vega-embed-container-TJ5z5dZw.js → vega-embed-container-CbnTccZi.js} +6 -6
  170. package/dist/vega-loader.browser-D95WfUcj.js +1139 -0
  171. package/dist/{vennDiagram-T6HMQDX7-D-Rcq3Iu.js → vennDiagram-4TSXK5OY-CS7lHhxI.js} +9 -9
  172. package/dist/wardley-WFR3VGLG-Na-tFhQJ.js +3 -0
  173. package/dist/{wardleyDiagram-T6FBY63Y-Z-Og7_Wd.js → wardleyDiagram-VM6X3IG4-BSm-L8JI.js} +10 -10
  174. package/dist/{xychartDiagram-ELKLHX3M-BDJ2dITA.js → xychartDiagram-S5SC5T6Z-8fKCJGrJ.js} +248 -139
  175. package/package.json +52 -52
  176. package/src/__mocks__/requests.ts +7 -2
  177. package/src/__tests__/__snapshots__/CellStatus.test.tsx.snap +12 -12
  178. package/src/components/chat/acp/__tests__/agent-panel.test.tsx +270 -0
  179. package/src/components/chat/acp/agent-panel.tsx +45 -44
  180. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +2 -6
  181. package/src/components/data-table/column-visibility-dropdown.tsx +9 -3
  182. package/src/components/datasources/components.tsx +4 -2
  183. package/src/components/editor/RecoveryButton.tsx +1 -0
  184. package/src/components/editor/chrome/components/feedback-button.tsx +10 -9
  185. package/src/components/editor/chrome/panels/__tests__/packages-panel.test.tsx +143 -0
  186. package/src/components/editor/chrome/panels/packages-panel.tsx +145 -51
  187. package/src/components/editor/code/__tests__/readonly-diff.test.tsx +65 -0
  188. package/src/components/editor/code/readonly-diff.tsx +1 -1
  189. package/src/components/editor/file-tree/__tests__/tree-actions.test.tsx +54 -0
  190. package/src/components/editor/file-tree/tree-actions.tsx +11 -14
  191. package/src/components/editor/notebook-cell.tsx +4 -2
  192. package/src/components/editor/output/Outputs.css +1 -0
  193. package/src/components/editor/package-alert.tsx +25 -1
  194. package/src/components/home/components.tsx +17 -0
  195. package/src/components/pages/gallery-page.tsx +2 -4
  196. package/src/components/pages/home-page.tsx +2 -4
  197. package/src/components/slides/slide-form.tsx +1 -0
  198. package/src/components/slides/slide-notes-editor.tsx +1 -0
  199. package/src/components/terminal/terminal.tsx +4 -4
  200. package/src/components/tracing/tracing-spec.ts +1 -1
  201. package/src/components/ui/table.tsx +1 -1
  202. package/src/core/cells/__tests__/cell.test.ts +61 -0
  203. package/src/core/cells/cell.ts +9 -1
  204. package/src/core/cells/pending-delete-service.ts +12 -16
  205. package/src/core/codemirror/language/__tests__/sql.test.ts +70 -2
  206. package/src/core/codemirror/language/languages/sql/sql.ts +16 -1
  207. package/src/core/codemirror/rtc/extension.ts +5 -2
  208. package/src/core/datasets/__tests__/data-source.test.ts +2 -0
  209. package/src/core/datasets/data-source-connections.ts +15 -10
  210. package/src/core/islands/__tests__/parse.test.ts +140 -7
  211. package/src/core/islands/parse.ts +20 -0
  212. package/src/core/packages/__tests__/useInstallPackage.test.tsx +47 -1
  213. package/src/core/packages/toast-components.tsx +26 -0
  214. package/src/core/packages/useInstallPackage.ts +7 -2
  215. package/src/core/runtime/__tests__/runtime.test.ts +11 -0
  216. package/src/core/runtime/runtime.ts +7 -2
  217. package/src/core/wasm/bridge.ts +1 -0
  218. package/src/core/websocket/transports/transport.ts +1 -1
  219. package/src/core/websocket/transports/ws.ts +1 -1
  220. package/src/css/app/Cell.css +2 -0
  221. package/src/plugins/core/RenderHTML.tsx +22 -2
  222. package/src/plugins/core/__test__/RenderHTML.test.ts +187 -0
  223. package/src/plugins/impl/data-frames/panel.tsx +1 -0
  224. package/src/plugins/layout/AccordionPlugin.tsx +7 -2
  225. package/src/plugins/layout/__test__/AccordionPlugin.test.tsx +66 -0
  226. package/dist/_baseMerge-Dv8bBloN.js +0 -73
  227. package/dist/_initCloneObject---vediN2.js +0 -95
  228. package/dist/arc-DOVLrCPd.js +0 -82
  229. package/dist/architecture-TIHT7OUA-MiJpPpQW.js +0 -3
  230. package/dist/array-CApNbSU9.js +0 -6
  231. package/dist/assets/__vite-browser-external-BdKGjRZ4.js +0 -1
  232. package/dist/assets/worker-DlIBfp9S.js +0 -98
  233. package/dist/blockDiagram-VBNYF7ZC-Bc--I65C.js +0 -3158
  234. package/dist/chat-ui-DttQ-5Ut.js +0 -8455
  235. package/dist/chunk-3NCLNEKW-BIp_lB_4.js +0 -14
  236. package/dist/chunk-5FCAYU7R-C_HO9A1J.js +0 -23
  237. package/dist/chunk-5HE753X5-Bixm_MV-.js +0 -38
  238. package/dist/chunk-5JV3BV7I-CH5J3iZY.js +0 -54
  239. package/dist/chunk-5TONJI2A-DG6gDiSS.js +0 -62
  240. package/dist/chunk-7BUUIJ7U-5afmIPeo.js +0 -82
  241. package/dist/chunk-BIQX33UG-7TMBUf89.js +0 -23
  242. package/dist/chunk-CQNSW5MT-Cnqqsxt-.js +0 -38
  243. package/dist/chunk-CYSBUYHQ-BAbymFHR.js +0 -23
  244. package/dist/chunk-EMLP6XTP-Bsz-QL77.js +0 -23
  245. package/dist/chunk-J7OUQ5F2-CM_meqZH.js +0 -57
  246. package/dist/chunk-JG7HCLWE-DUnCDgPk.js +0 -62
  247. package/dist/chunk-MOZMSUNE-BG6IHvzT.js +0 -35
  248. package/dist/chunk-OSBZ3O6U-CYwj_bvR.js +0 -23
  249. package/dist/chunk-QBLGF6JB-B4vJ4j8J.js +0 -23
  250. package/dist/chunk-QR6OTTB3-D4wH2ldi.js +0 -3738
  251. package/dist/chunk-R7FJI6CG-Blf8FcmZ.js +0 -64
  252. package/dist/chunk-RYQCIY6F-BWbIlBIH.js +0 -241
  253. package/dist/chunk-U6XO7XAA-COw445DS.js +0 -63
  254. package/dist/chunk-UBXNYLIW-BHigVU4H.js +0 -32
  255. package/dist/chunk-YOTPTUD7-Dn044Q_d.js +0 -30
  256. package/dist/chunk-ZIRB5QZD-BR4TMfOa.js +0 -1153
  257. package/dist/classDiagram-JCYQIIEL-DmXSLxe_.js +0 -30
  258. package/dist/classDiagram-v2-OCEON4UE-CooqVexA.js +0 -30
  259. package/dist/click-outside-container-D_URcm3D.js +0 -167
  260. package/dist/code-block-37QAKDTI-CQrzBOr-.js +0 -107
  261. package/dist/cynefin-VYW2F7L2-CeHAxOEX.js +0 -3
  262. package/dist/dagre-VZM6K2ZE-CJggWPTJ.js +0 -328
  263. package/dist/dist-ABQjhuek.js +0 -64
  264. package/dist/dist-CO5R6VMi.js +0 -538
  265. package/dist/eventmodeling-45OFAUF4-B_lWZ-Pd.js +0 -3
  266. package/dist/flowDiagram-UKHOOZJN-g1AmrZzM.js +0 -17
  267. package/dist/gitGraph-TEB2WS4Q-Dj-eXUph.js +0 -3
  268. package/dist/info-DKCQHKI2-Bhb-pe2e.js +0 -3
  269. package/dist/line-CuKjIQa1.js +0 -34
  270. package/dist/map-BJpOfPlL.js +0 -149
  271. package/dist/math-BXtKgYah.js +0 -10
  272. package/dist/mermaid-4DMBBIKO-Ddp9TgNp.js +0 -2
  273. package/dist/mermaid-BsHdQeQf.js +0 -1173
  274. package/dist/mermaid-parser.core-Din9FvSi.js +0 -99
  275. package/dist/packet-7NZHBO7P-fbkIIyKE.js +0 -3
  276. package/dist/path-BNHuHZP8.js +0 -87
  277. package/dist/pie-RZYD4A2V-CLRIsxY1.js +0 -3
  278. package/dist/purify.es-CB-YO1Hn.js +0 -774
  279. package/dist/radar-I7S5WNFK-BGzCbgXu.js +0 -3
  280. package/dist/railroad-3IZDKUUU-CvQIIcuU.js +0 -3
  281. package/dist/railroad-abnf-AHOZXSZD-CMwtlNtu.js +0 -3
  282. package/dist/railroad-ebnf-EBAXGLYW-n1QUOAsh.js +0 -3
  283. package/dist/railroad-peg-LSFZ7HO6-PjnrpmCs.js +0 -3
  284. package/dist/schemas-DzK6U94N.js +0 -6057
  285. package/dist/stateDiagram-v2-UEYNNEHI-BTRUs8Il.js +0 -30
  286. package/dist/step-CKczO72Q.js +0 -670
  287. package/dist/swimlanesDiagram-ULZ7WXOC-NBmgBl9G.js +0 -31
  288. package/dist/timer-DpDyj9G0.js +0 -596
  289. package/dist/treeView-QDETBFTQ-DU8LwHuf.js +0 -3
  290. package/dist/treemap-6X3UGDF4-DUk4-k_O.js +0 -3
  291. package/dist/useTheme-CVJ0UOf2.js +0 -841
  292. package/dist/vega-loader.browser-DEggZzni.js +0 -1083
  293. package/dist/wardley-OPB4EBWU-Db-AaGas.js +0 -3
@@ -89,6 +89,7 @@ export const SlideNotesEditor = ({
89
89
  };
90
90
 
91
91
  return (
92
+ // oxlint-disable-next-line jsx-a11y/no-noninteractive-element-interactions -- Prevent slide navigation while editing speaker notes.
92
93
  <section
93
94
  className={cn(
94
95
  "h-full min-h-0 flex flex-col bg-muted/40 dark:bg-muted/20 border-t",
@@ -254,7 +254,9 @@ const TerminalComponent: React.FC<TerminalComponentProps> = ({
254
254
  try {
255
255
  await waitForConnectionOpen();
256
256
 
257
- const socket = new WebSocket(runtimeManager.getTerminalWsURL());
257
+ // Size the PTY before the shell draws its first prompt.
258
+ fitAddon.fit();
259
+ const socket = new WebSocket(runtimeManager.getTerminalWsURL(terminal));
258
260
  const attachAddon = new AttachAddon(socket);
259
261
  terminal.loadAddon(attachAddon);
260
262
  wsRef.current = socket;
@@ -270,9 +272,7 @@ const TerminalComponent: React.FC<TerminalComponentProps> = ({
270
272
 
271
273
  const handleOpen = () => {
272
274
  updateReadyState();
273
- // Send initial dimensions: the mount-time fit() may have fired
274
- // before the WS was OPEN, dropping the resize message and leaving
275
- // the PTY at its default 0x0 winsize.
275
+ // The container may have resized while the connection was opening.
276
276
  fitAddon.fit();
277
277
  if (terminal.cols > 0 && terminal.rows > 0) {
278
278
  socket.send(
@@ -1,7 +1,7 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
3
  import type { TopLevelSpec } from "vega-lite";
4
- import type { TimeUnit } from "vega-typings";
4
+ import type { TimeUnit } from "vega-lite/types_unstable/timeunit.js";
5
5
  import type { CellId } from "@/core/cells/ids";
6
6
  import type { CellRun } from "@/core/cells/runs";
7
7
  import type { ResolvedTheme } from "@/theme/useTheme";
@@ -7,7 +7,7 @@ const Table = React.forwardRef<
7
7
  HTMLTableElement,
8
8
  React.HTMLAttributes<HTMLTableElement>
9
9
  >(({ className, ...props }, ref) => (
10
- <div className="w-full overflow-auto scrollbar-thin flex-1 print:overflow-hidden">
10
+ <div className="w-full overflow-auto overscroll-contain scrollbar-thin flex-1 print:overflow-hidden">
11
11
  <table
12
12
  ref={ref}
13
13
  className={cn("w-full caption-bottom text-sm", className)}
@@ -220,6 +220,67 @@ describe("transitionCell serialization", () => {
220
220
  });
221
221
 
222
222
  describe("transitionCell stdin resolution", () => {
223
+ describe.each([
224
+ {
225
+ name: "interrupted",
226
+ message: {
227
+ output: {
228
+ channel: "marimo-error",
229
+ mimetype: "application/vnd.marimo+error",
230
+ data: [{ type: "interruption" }],
231
+ timestamp: 1,
232
+ },
233
+ } as CellMessage,
234
+ },
235
+ {
236
+ name: "idle",
237
+ message: { status: "idle" } as CellMessage,
238
+ },
239
+ ])("when $name", ({ name, message }) => {
240
+ it.each(["text/plain", "text/password"] as const)(
241
+ "preserves a processed %s prompt",
242
+ (mimetype) => {
243
+ const prompt: OutputMessage = {
244
+ channel: "stdin",
245
+ mimetype,
246
+ data: "Enter a value: ",
247
+ timestamp: 0,
248
+ };
249
+ const waiting = transitionCell(
250
+ createCellRuntimeState({ status: "running" }),
251
+ { console: prompt } as CellMessage,
252
+ );
253
+ const resolved = transitionCell(waiting, message);
254
+
255
+ expect(resolved.interrupted).toBe(name === "interrupted");
256
+ expect(resolved.consoleOutputs[0]).toMatchObject({
257
+ ...prompt,
258
+ response: "",
259
+ });
260
+ },
261
+ );
262
+
263
+ it.each(["text/plain", "text/password"] as const)(
264
+ "preserves an existing %s response",
265
+ (mimetype) => {
266
+ const prompt = {
267
+ channel: "stdin" as const,
268
+ mimetype,
269
+ data: "Enter a value: ",
270
+ timestamp: 0,
271
+ response: "submitted value",
272
+ };
273
+ const answered = createCellRuntimeState({
274
+ status: "running",
275
+ consoleOutputs: [prompt],
276
+ });
277
+ const resolved = transitionCell(answered, message);
278
+
279
+ expect(resolved.consoleOutputs).toEqual([prompt]);
280
+ },
281
+ );
282
+ });
283
+
223
284
  function stdinOutput(): OutputMessage {
224
285
  return {
225
286
  channel: "stdin",
@@ -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
  });
@@ -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) {
@@ -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);
@@ -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
@@ -106,6 +106,7 @@ describe("data source connections", () => {
106
106
 
107
107
  let newState = addConnection(connections, state);
108
108
  expect(newState.connectionsMap.size).toBe(defaultConnSize + 2);
109
+ newState = { ...newState, latestEngineSelected: connections[0].name };
109
110
 
110
111
  newState = reducer(newState, {
111
112
  type: "removeDataSourceConnection",
@@ -113,6 +114,7 @@ describe("data source connections", () => {
113
114
  });
114
115
  expect(newState.connectionsMap.size).toBe(defaultConnSize + 1);
115
116
  expect(newState.connectionsMap.has("conn2" as ConnectionName)).toBe(true);
117
+ expect(newState.latestEngineSelected).toBeNull();
116
118
  });
117
119
 
118
120
  it("can clear all connections", () => {
@@ -44,7 +44,8 @@ export interface DataSourceConnection extends Omit<
44
44
  export type ConnectionsMap = ReadonlyMap<ConnectionName, DataSourceConnection>;
45
45
 
46
46
  export interface DataSourceState {
47
- latestEngineSelected: ConnectionName;
47
+ // Null permits automatic selection; DuckDB can also be an explicit choice.
48
+ latestEngineSelected: ConnectionName | null;
48
49
  connectionsMap: ConnectionsMap;
49
50
  }
50
51
 
@@ -110,7 +111,7 @@ function tableSchemaPath(sqlTableContext: SQLTableContext): string[] {
110
111
 
111
112
  function initialState(): DataSourceState {
112
113
  return {
113
- latestEngineSelected: DUCKDB_ENGINE,
114
+ latestEngineSelected: null,
114
115
  connectionsMap: initialConnections,
115
116
  };
116
117
  }
@@ -136,6 +137,8 @@ const {
136
137
  // Backend will dedupe by connection name & keep the latest, so we use this as the key
137
138
  const newMap = new Map(connectionsMap);
138
139
  for (const conn of opts.connections) {
140
+ // Refresh insertion order so automatic selection follows discovery recency.
141
+ newMap.delete(conn.name);
139
142
  newMap.set(conn.name, conn);
140
143
  }
141
144
 
@@ -161,16 +164,17 @@ const {
161
164
  }),
162
165
  );
163
166
  return {
164
- // If the latest engine selected is not in the new map, use the default engine
165
- latestEngineSelected: newMap.has(latestEngineSelected)
166
- ? latestEngineSelected
167
- : DUCKDB_ENGINE,
167
+ // Allow automatic selection again when the selected connection disappears.
168
+ latestEngineSelected:
169
+ latestEngineSelected && newMap.has(latestEngineSelected)
170
+ ? latestEngineSelected
171
+ : null,
168
172
  connectionsMap: newMap,
169
173
  };
170
174
  },
171
175
 
172
176
  clearDataSourceConnections: (): DataSourceState => ({
173
- latestEngineSelected: DUCKDB_ENGINE,
177
+ latestEngineSelected: null,
174
178
  connectionsMap: new Map(),
175
179
  }),
176
180
 
@@ -183,9 +187,10 @@ const {
183
187
  const newMap = new Map(connectionsMap);
184
188
  newMap.delete(connectionName);
185
189
  return {
186
- latestEngineSelected: newMap.has(latestEngineSelected)
187
- ? latestEngineSelected
188
- : DUCKDB_ENGINE,
190
+ latestEngineSelected:
191
+ latestEngineSelected && newMap.has(latestEngineSelected)
192
+ ? latestEngineSelected
193
+ : null,
189
194
  connectionsMap: newMap,
190
195
  };
191
196
  },
@@ -19,6 +19,13 @@ import {
19
19
  } from "../parse";
20
20
  import { createMockIslandElement, createMockIslands } from "./test-utils.tsx";
21
21
 
22
+ function islandSnapshotPath(filename: string): string {
23
+ return new URL(
24
+ `../../../../../tests/_islands/snapshots/${filename}`,
25
+ import.meta.url,
26
+ ).pathname.replace(/^\/@fs/, "");
27
+ }
28
+
22
29
  function createPayloadCell(
23
30
  overrides: Partial<{
24
31
  cellId: string;
@@ -47,6 +54,7 @@ function appendPayload(
47
54
  payload: {
48
55
  schemaVersion: number;
49
56
  appId: string;
57
+ dependencies?: unknown;
50
58
  cells: ReturnType<typeof createPayloadCell>[];
51
59
  },
52
60
  ) {
@@ -58,6 +66,33 @@ function appendPayload(
58
66
  }
59
67
 
60
68
  describe("createMarimoFile", () => {
69
+ it("should serialize dependencies as top-level script metadata", () => {
70
+ const file = createMarimoFile({
71
+ dependencies: ['cowsay==6.1; sys_platform == "emscripten"'],
72
+ cells: [{ code: "import cowsay" }],
73
+ });
74
+ expect(file).toBe(
75
+ [
76
+ "# /// script",
77
+ '# dependencies = ["cowsay==6.1; sys_platform == \\"emscripten\\""]',
78
+ "# ///",
79
+ "import marimo",
80
+ "app = marimo.App()",
81
+ "@app.cell",
82
+ "def __():",
83
+ " import cowsay",
84
+ " return",
85
+ ].join("\n"),
86
+ );
87
+ });
88
+
89
+ it("should omit metadata for empty dependencies", () => {
90
+ const cells = [{ code: "import cowsay" }];
91
+ expect(createMarimoFile({ cells, dependencies: [] })).toBe(
92
+ createMarimoFile({ cells }),
93
+ );
94
+ });
95
+
61
96
  it("should return a string", () => {
62
97
  const app = {
63
98
  cells: [
@@ -736,13 +771,7 @@ describe("parseMarimoIslandApps", () => {
736
771
  });
737
772
 
738
773
  it("should parse Python-generated island payload snapshots", () => {
739
- const html = readFileSync(
740
- new URL(
741
- "../../../../../tests/_islands/snapshots/html-payload.txt",
742
- import.meta.url,
743
- ).pathname.replace(/^\/@fs/, ""),
744
- "utf8",
745
- );
774
+ const html = readFileSync(islandSnapshotPath("html-payload.txt"), "utf8");
746
775
  container.innerHTML = html;
747
776
 
748
777
  const result = parseMarimoIslandApps(container);
@@ -775,6 +804,108 @@ describe("parseMarimoIslandApps", () => {
775
804
  expect(islands[2].getAttribute(ISLAND_DATA_ATTRIBUTES.CELL_IDX)).toBe("1");
776
805
  });
777
806
 
807
+ it("should restore metadata from a Python-generated dependency payload", () => {
808
+ container.innerHTML = readFileSync(
809
+ islandSnapshotPath("body-dependencies.txt"),
810
+ "utf8",
811
+ );
812
+
813
+ const probed = parseMarimoIslandApps(container, { materialize: false });
814
+ const apps = parseMarimoIslandApps(container);
815
+
816
+ expect(probed).toEqual(apps);
817
+ expect(apps).toEqual([
818
+ {
819
+ id: "main",
820
+ payloadBacked: true,
821
+ dependencies: [
822
+ 'cowsay==6.1; sys_platform == "emscripten"',
823
+ "rich[jupyter]>=13",
824
+ "desktop; sys_platform != 'emscripten'",
825
+ "older-python; python_version < '3.13'",
826
+ "newer-python; python_version >= '3.13'",
827
+ ],
828
+ cells: [{ cellId: "Hbol", code: "import cowsay", output: "", idx: 0 }],
829
+ },
830
+ ]);
831
+ // The Python Pyodide test reads this file with the real metadata parser.
832
+ expect(createMarimoFile(apps[0])).toBe(
833
+ readFileSync(islandSnapshotPath("notebook-dependencies.txt"), "utf8"),
834
+ );
835
+ });
836
+
837
+ it("should carry dependencies from payloads into each generated notebook", () => {
838
+ for (const [appId, dependencies] of [
839
+ ["app1", ["cowsay==6.1"]],
840
+ ["app2", ["rich[jupyter]>=13"]],
841
+ ] as const) {
842
+ container.appendChild(
843
+ createMockIslandElement({ appId, cellId: "cell-1" }),
844
+ );
845
+ appendPayload(container, {
846
+ schemaVersion: 1,
847
+ appId,
848
+ dependencies,
849
+ cells: [createPayloadCell()],
850
+ });
851
+ }
852
+
853
+ const apps = parseMarimoIslandApps(container);
854
+ expect(apps.map((app) => [app.id, app.dependencies])).toEqual([
855
+ ["app1", ["cowsay==6.1"]],
856
+ ["app2", ["rich[jupyter]>=13"]],
857
+ ]);
858
+ expect(createMarimoFile(apps[0])).toContain(
859
+ '# /// script\n# dependencies = ["cowsay==6.1"]\n# ///\n',
860
+ );
861
+ });
862
+
863
+ it.each([null, "cowsay", [123], ["cowsay", null]])(
864
+ "should ignore payloads with malformed dependencies: %j",
865
+ (dependencies) => {
866
+ const island = createMockIslandElement({
867
+ appId: "app1",
868
+ cellId: "cell-1",
869
+ code: "import cowsay",
870
+ innerHTML: "<div>dom</div>",
871
+ });
872
+ island.setAttribute(ISLAND_DATA_ATTRIBUTES.REACTIVE, "true");
873
+ container.appendChild(island);
874
+ appendPayload(container, {
875
+ schemaVersion: 1,
876
+ appId: "app1",
877
+ dependencies,
878
+ cells: [createPayloadCell()],
879
+ });
880
+
881
+ expect(parseMarimoIslandApps(container)).toEqual([
882
+ {
883
+ id: "app1",
884
+ cells: [{ code: "import cowsay", output: "<div>dom</div>", idx: 0 }],
885
+ },
886
+ ]);
887
+ },
888
+ );
889
+
890
+ it("should merge dependencies from payloads belonging to the same app", () => {
891
+ for (const [cellId, dependencies] of [
892
+ ["cell-1", ["cowsay"]],
893
+ ["cell-2", ["cowsay", "rich"]],
894
+ ] as const) {
895
+ container.appendChild(createMockIslandElement({ appId: "app1", cellId }));
896
+ appendPayload(container, {
897
+ schemaVersion: 1,
898
+ appId: "app1",
899
+ dependencies,
900
+ cells: [createPayloadCell({ cellId })],
901
+ });
902
+ }
903
+
904
+ expect(
905
+ parseMarimoIslandApps(container).map((app) => app.dependencies),
906
+ ).toEqual([["cowsay", "rich"]]);
907
+ });
908
+
778
909
  it("should fall back to DOM islands for unsupported payload versions", () => {
779
910
  const island = createMockIslandElement({
780
911
  appId: "app1",
@@ -990,6 +1121,7 @@ describe("parseMarimoIslandApps", () => {
990
1121
  outputHtml: "<div>payload only</div>",
991
1122
  }),
992
1123
  ],
1124
+ dependencies: ["cowsay"],
993
1125
  });
994
1126
 
995
1127
  const result = parseMarimoIslandApps(container);
@@ -1076,6 +1208,7 @@ describe("parseMarimoIslandApps", () => {
1076
1208
  reactive: false,
1077
1209
  }),
1078
1210
  ],
1211
+ dependencies: ["cowsay"],
1079
1212
  });
1080
1213
 
1081
1214
  const result = parseMarimoIslandApps(container);
@@ -30,6 +30,8 @@ export interface MarimoIslandApp {
30
30
  * Whether cells came from a supported JSON payload instead of DOM parsing.
31
31
  */
32
32
  payloadBacked?: boolean;
33
+ /** Explicit notebook dependencies to install before starting the app. */
34
+ dependencies?: string[];
33
35
  /**
34
36
  * Cells in the app.
35
37
  */
@@ -62,6 +64,7 @@ interface MarimoIslandCell {
62
64
  interface MarimoIslandPayload {
63
65
  schemaVersion: 1;
64
66
  appId: string;
67
+ dependencies?: string[];
65
68
  cells: MarimoIslandPayloadCell[];
66
69
  }
67
70
 
@@ -235,6 +238,12 @@ function parsePayloadBackedApps({
235
238
  embed?.setAttribute(ISLAND_DATA_ATTRIBUTES.CELL_IDX, idx.toString());
236
239
  }
237
240
  }
241
+ const app = apps.get(payload.appId);
242
+ if (app && payload.dependencies?.length) {
243
+ app.dependencies = [
244
+ ...new Set([...(app.dependencies ?? []), ...payload.dependencies]),
245
+ ];
246
+ }
238
247
  }
239
248
 
240
249
  // A supported payload is the runtime source for its app. Extra same-app DOM
@@ -371,6 +380,7 @@ export function parseIslandElement(
371
380
 
372
381
  export function createMarimoFile(app: {
373
382
  cells: { code: string; disabled?: boolean }[];
383
+ dependencies?: string[];
374
384
  }): string {
375
385
  const lines = [
376
386
  "import marimo",
@@ -402,6 +412,13 @@ export function createMarimoFile(app: {
402
412
  .join("\n"),
403
413
  ];
404
414
 
415
+ if (app.dependencies?.length) {
416
+ lines.unshift(
417
+ "# /// script",
418
+ `# dependencies = ${JSON.stringify(app.dependencies)}`,
419
+ "# ///",
420
+ );
421
+ }
405
422
  return lines.join("\n");
406
423
  }
407
424
 
@@ -507,6 +524,9 @@ function isMarimoIslandPayload(
507
524
  return (
508
525
  payload.schemaVersion === 1 &&
509
526
  typeof payload.appId === "string" &&
527
+ (payload.dependencies === undefined ||
528
+ (Array.isArray(payload.dependencies) &&
529
+ payload.dependencies.every((dep) => typeof dep === "string"))) &&
510
530
  Array.isArray(payload.cells) &&
511
531
  payload.cells.every(isMarimoIslandPayloadCell)
512
532
  );