@marimo-team/islands 0.24.3-dev5 → 0.24.3-dev50

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 (376) hide show
  1. package/dist/{ConnectedDataExplorerComponent-C9OF_75w.js → ConnectedDataExplorerComponent-KVhjDMSe.js} +1066 -1066
  2. package/dist/ErrorBoundary-BW0xr_AR.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-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/{html-to-image-BhNoIBSU.js → cells-BSgNCBZ8.js} +6740 -10126
  18. package/dist/{channel-CyiYUzJv.js → channel-B5XnTarr.js} +1 -1
  19. package/dist/chat-ui-CygzVJ9s.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-BdKqYmPi.js +138 -0
  46. package/dist/{common-xHoep60C.js → common-D9PY0k7A.js} +8839 -12646
  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-BZiw7m3d.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-iJn-Nryx.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-BAHeJT2Q.js +380 -0
  99. package/dist/flowDiagram-HODETNUW-6dMdB8pR.js +16 -0
  100. package/dist/{formats-CJMVUfb3.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-Bp9hhneH.js} +2143 -1910
  105. package/dist/{glide-utils-NShAPPtn.js → glide-utils-B3rUT5PI.js} +15 -15
  106. package/dist/globals-BUgvsAck.js +19 -0
  107. package/dist/highlighted-body-KPVGNVTW-Ad3MKZ18.js +38 -0
  108. package/dist/html-to-image-kpuRfdfZ.js +3253 -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 +8105 -13485
  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-C743iqsh.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-CpK6fX_C.js → process-output-DFe2tVIY.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-DwuC-61O.js → reveal-component-CgMzL2w5.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-D-Rx3ux5.js → toDate-WXg1yLcI.js} +10 -9
  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-CPehZbUb.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__/requests.ts +7 -0
  185. package/src/__tests__/__snapshots__/CellStatus.test.tsx.snap +12 -12
  186. package/src/components/chat/acp/__tests__/agent-panel.test.tsx +270 -0
  187. package/src/components/chat/acp/agent-panel.tsx +45 -44
  188. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +2 -6
  189. package/src/components/data-table/column-summary/chart-spec-model.tsx +1 -1
  190. package/src/components/data-table/columns.tsx +64 -67
  191. package/src/components/editor/RecoveryButton.tsx +1 -0
  192. package/src/components/editor/__tests__/dynamic-favicon.test.tsx +36 -2
  193. package/src/components/editor/ai/add-cell-with-ai.tsx +1 -0
  194. package/src/components/editor/ai/ai-completion-editor.tsx +3 -1
  195. package/src/components/editor/alerts/connecting-alert.tsx +1 -66
  196. package/src/components/editor/alerts/connection-notice.tsx +140 -0
  197. package/src/components/editor/app-container.tsx +9 -3
  198. package/src/components/editor/boundary/ErrorBoundary.tsx +38 -16
  199. package/src/components/editor/boundary/__tests__/ErrorBoundary.test.tsx +311 -0
  200. package/src/components/editor/cell/code/__tests__/rtc-editor-config.test.ts +50 -0
  201. package/src/components/editor/cell/code/cell-editor.tsx +41 -42
  202. package/src/components/editor/chrome/components/__tests__/feedback-button.test.tsx +94 -0
  203. package/src/components/editor/chrome/components/feedback-button.tsx +63 -42
  204. package/src/components/editor/chrome/panels/__tests__/packages-panel.test.tsx +114 -7
  205. package/src/components/editor/chrome/panels/__tests__/sandbox-recovery.test.tsx +165 -0
  206. package/src/components/editor/chrome/panels/packages-panel.tsx +93 -166
  207. package/src/components/editor/chrome/panels/sandbox-controller.tsx +106 -0
  208. package/src/components/editor/chrome/panels/sandbox-panel.tsx +173 -0
  209. package/src/components/editor/chrome/wrapper/footer-items/backend-status.tsx +3 -1
  210. package/src/components/editor/code/__tests__/readonly-diff.test.tsx +65 -0
  211. package/src/components/editor/code/readonly-diff.tsx +1 -1
  212. package/src/components/editor/connections/database/__tests__/__snapshots__/as-code.test.ts.snap +98 -98
  213. package/src/components/editor/connections/database/__tests__/as-code.test.ts +11 -5
  214. package/src/components/editor/dynamic-favicon.tsx +17 -10
  215. package/src/components/editor/file-tree/__tests__/tree-actions.test.tsx +54 -0
  216. package/src/components/editor/file-tree/tree-actions.tsx +11 -14
  217. package/src/components/editor/header/__tests__/status.test.tsx +8 -20
  218. package/src/components/editor/header/filename-input.tsx +2 -0
  219. package/src/components/editor/header/status.tsx +5 -3
  220. package/src/components/editor/notebook-cell.tsx +4 -2
  221. package/src/components/editor/output/JsonOutput.tsx +182 -632
  222. package/src/components/editor/output/Outputs.css +50 -17
  223. package/src/components/editor/output/__tests__/JsonOutput-interactions.test.tsx +254 -0
  224. package/src/components/editor/output/__tests__/JsonOutput-mimetype.test.tsx +41 -46
  225. package/src/components/editor/output/__tests__/{json-output.test.ts → json-output-formatting.test.ts} +113 -75
  226. package/src/components/editor/output/__tests__/json-output-pagination.test.ts +252 -0
  227. package/src/components/editor/output/json-output/formatting.ts +167 -0
  228. package/src/components/editor/output/json-output/pagination.ts +155 -0
  229. package/src/components/editor/output/json-output/renderers.tsx +196 -0
  230. package/src/components/editor/output/json-output/themes.ts +52 -0
  231. package/src/components/editor/renderers/cell-array.tsx +1 -5
  232. package/src/components/home/components.tsx +17 -0
  233. package/src/components/pages/gallery-page.tsx +2 -4
  234. package/src/components/pages/home-page.tsx +2 -4
  235. package/src/components/slides/slide-form.tsx +1 -0
  236. package/src/components/slides/slide-notes-editor.tsx +1 -0
  237. package/src/components/terminal/terminal.tsx +4 -4
  238. package/src/components/tracing/tracing-spec.ts +1 -1
  239. package/src/components/ui/table.tsx +1 -1
  240. package/src/components/ui/use-toast.ts +8 -0
  241. package/src/core/MarimoApp.tsx +0 -2
  242. package/src/core/cells/__tests__/__snapshots__/cells.test.ts.snap +259 -259
  243. package/src/core/cells/__tests__/cell.test.ts +61 -0
  244. package/src/core/cells/__tests__/cells.test.ts +37 -37
  245. package/src/core/cells/cell.ts +9 -1
  246. package/src/core/cells/pending-delete-service.ts +12 -16
  247. package/src/core/codemirror/language/__tests__/sql.test.ts +70 -2
  248. package/src/core/codemirror/language/languages/sql/sql.ts +16 -1
  249. package/src/core/codemirror/rtc/extension.ts +5 -2
  250. package/src/core/datasets/__tests__/data-source.test.ts +2 -0
  251. package/src/core/datasets/data-source-connections.ts +15 -10
  252. package/src/core/edit-app.tsx +8 -5
  253. package/src/core/errors/state.ts +1 -2
  254. package/src/core/islands/__tests__/parse.test.ts +140 -7
  255. package/src/core/islands/bootstrap.ts +1 -0
  256. package/src/core/islands/bridge.ts +3 -0
  257. package/src/core/islands/parse.ts +20 -0
  258. package/src/core/network/connection-notice.ts +84 -0
  259. package/src/core/network/requests-lazy.ts +3 -0
  260. package/src/core/network/requests-network.ts +12 -0
  261. package/src/core/network/requests-static.ts +3 -0
  262. package/src/core/network/requests-toasting.tsx +3 -0
  263. package/src/core/network/resolve.ts +2 -1
  264. package/src/core/network/types.ts +7 -0
  265. package/src/core/packages/__tests__/usePackageAction.test.tsx +129 -0
  266. package/src/core/packages/__tests__/useSandboxController.test.tsx +165 -0
  267. package/src/core/packages/package-data.ts +35 -0
  268. package/src/core/packages/sandbox-state.ts +15 -0
  269. package/src/core/packages/toast-components.tsx +11 -0
  270. package/src/core/packages/useInstallPackage.ts +1 -1
  271. package/src/core/packages/usePackageAction.ts +51 -0
  272. package/src/core/packages/usePackageDependencies.ts +22 -0
  273. package/src/core/packages/useSandboxController.ts +188 -0
  274. package/src/core/run-app.tsx +2 -0
  275. package/src/core/runtime/__tests__/runtime.test.ts +11 -0
  276. package/src/core/runtime/runtime.ts +7 -2
  277. package/src/core/wasm/bridge.ts +11 -0
  278. package/src/core/websocket/__tests__/useMarimoKernelConnection.hook.test.tsx +212 -2
  279. package/src/core/websocket/transports/transport.ts +1 -1
  280. package/src/core/websocket/transports/ws.ts +1 -1
  281. package/src/core/websocket/types.ts +11 -1
  282. package/src/core/websocket/useMarimoKernelConnection.tsx +43 -8
  283. package/src/css/app/Cell.css +2 -0
  284. package/src/hooks/useDebounce.ts +2 -0
  285. package/src/plugins/core/BadPlugin.tsx +3 -14
  286. package/src/plugins/core/RenderHTML.tsx +22 -2
  287. package/src/plugins/core/__test__/RenderHTML.test.ts +187 -0
  288. package/src/plugins/core/registerReactComponent.tsx +0 -1
  289. package/src/plugins/impl/FormPlugin.tsx +2 -0
  290. package/src/plugins/impl/MatrixPlugin.tsx +2 -0
  291. package/src/plugins/impl/RangeSliderPlugin.tsx +2 -0
  292. package/src/plugins/impl/SliderPlugin.tsx +2 -0
  293. package/src/plugins/impl/data-editor/__tests__/glide-data-editor.test.tsx +23 -18
  294. package/src/plugins/impl/data-frames/panel.tsx +1 -0
  295. package/src/plugins/impl/image-comparison/ImageComparisonComponent.tsx +1 -1
  296. package/src/plugins/impl/image-comparison/__tests__/ImageComparisonComponent.test.tsx +15 -0
  297. package/src/plugins/layout/AccordionPlugin.tsx +7 -2
  298. package/src/plugins/layout/JsonOutputPlugin.tsx +7 -10
  299. package/src/plugins/layout/__test__/AccordionPlugin.test.tsx +66 -0
  300. package/src/stories/sandbox.stories.tsx +308 -0
  301. package/dist/ErrorBoundary-CR-ZQN_c.js +0 -125
  302. package/dist/_baseMerge-Dv8bBloN.js +0 -73
  303. package/dist/_initCloneObject---vediN2.js +0 -95
  304. package/dist/arc-DOVLrCPd.js +0 -82
  305. package/dist/architecture-TIHT7OUA-MiJpPpQW.js +0 -3
  306. package/dist/array-CApNbSU9.js +0 -6
  307. package/dist/assets/__vite-browser-external-BdKGjRZ4.js +0 -1
  308. package/dist/assets/worker-DlIBfp9S.js +0 -98
  309. package/dist/blockDiagram-VBNYF7ZC-Bc--I65C.js +0 -3158
  310. package/dist/chat-ui-DjTMZRVP.js +0 -8455
  311. package/dist/chunk-3NCLNEKW-BIp_lB_4.js +0 -14
  312. package/dist/chunk-5FCAYU7R-C_HO9A1J.js +0 -23
  313. package/dist/chunk-5HE753X5-Bixm_MV-.js +0 -38
  314. package/dist/chunk-5JV3BV7I-CH5J3iZY.js +0 -54
  315. package/dist/chunk-5TONJI2A-DG6gDiSS.js +0 -62
  316. package/dist/chunk-7BUUIJ7U-5afmIPeo.js +0 -82
  317. package/dist/chunk-BIQX33UG-7TMBUf89.js +0 -23
  318. package/dist/chunk-CQNSW5MT-Cnqqsxt-.js +0 -38
  319. package/dist/chunk-CYSBUYHQ-BAbymFHR.js +0 -23
  320. package/dist/chunk-EMLP6XTP-Bsz-QL77.js +0 -23
  321. package/dist/chunk-J7OUQ5F2-CM_meqZH.js +0 -57
  322. package/dist/chunk-JG7HCLWE-DUnCDgPk.js +0 -62
  323. package/dist/chunk-MOZMSUNE-BG6IHvzT.js +0 -35
  324. package/dist/chunk-OSBZ3O6U-CYwj_bvR.js +0 -23
  325. package/dist/chunk-QBLGF6JB-B4vJ4j8J.js +0 -23
  326. package/dist/chunk-QR6OTTB3-D4wH2ldi.js +0 -3738
  327. package/dist/chunk-R7FJI6CG-Blf8FcmZ.js +0 -64
  328. package/dist/chunk-RYQCIY6F-BWbIlBIH.js +0 -241
  329. package/dist/chunk-U6XO7XAA-COw445DS.js +0 -63
  330. package/dist/chunk-UBXNYLIW-BHigVU4H.js +0 -32
  331. package/dist/chunk-YOTPTUD7-Dn044Q_d.js +0 -30
  332. package/dist/chunk-ZIRB5QZD-BR4TMfOa.js +0 -1153
  333. package/dist/classDiagram-JCYQIIEL-DmXSLxe_.js +0 -30
  334. package/dist/classDiagram-v2-OCEON4UE-CooqVexA.js +0 -30
  335. package/dist/click-outside-container-D_URcm3D.js +0 -167
  336. package/dist/code-block-37QAKDTI-CQrzBOr-.js +0 -107
  337. package/dist/copy-CD7S58CY.js +0 -141
  338. package/dist/cynefin-VYW2F7L2-CeHAxOEX.js +0 -3
  339. package/dist/dagre-VZM6K2ZE-CJggWPTJ.js +0 -328
  340. package/dist/dist-3_o3T78I.js +0 -1360
  341. package/dist/dist-ABQjhuek.js +0 -64
  342. package/dist/dist-CO5R6VMi.js +0 -538
  343. package/dist/dropdown-menu-DhCfcscX.js +0 -5858
  344. package/dist/emotion-is-prop-valid.esm-M57VsT8j.js +0 -14
  345. package/dist/error-banner-CsXbEEjo.js +0 -611
  346. package/dist/eventmodeling-45OFAUF4-B_lWZ-Pd.js +0 -3
  347. package/dist/flowDiagram-UKHOOZJN-g1AmrZzM.js +0 -17
  348. package/dist/gitGraph-TEB2WS4Q-Dj-eXUph.js +0 -3
  349. package/dist/info-DKCQHKI2-Bhb-pe2e.js +0 -3
  350. package/dist/line-CuKjIQa1.js +0 -34
  351. package/dist/map-BJpOfPlL.js +0 -149
  352. package/dist/math-BXtKgYah.js +0 -10
  353. package/dist/mermaid-4DMBBIKO-Ddp9TgNp.js +0 -2
  354. package/dist/mermaid-Bi23Ibnw.js +0 -1173
  355. package/dist/mermaid-parser.core-Din9FvSi.js +0 -99
  356. package/dist/packet-7NZHBO7P-fbkIIyKE.js +0 -3
  357. package/dist/path-BNHuHZP8.js +0 -87
  358. package/dist/pie-RZYD4A2V-CLRIsxY1.js +0 -3
  359. package/dist/purify.es-CB-YO1Hn.js +0 -774
  360. package/dist/radar-I7S5WNFK-BGzCbgXu.js +0 -3
  361. package/dist/railroad-3IZDKUUU-CvQIIcuU.js +0 -3
  362. package/dist/railroad-abnf-AHOZXSZD-CMwtlNtu.js +0 -3
  363. package/dist/railroad-ebnf-EBAXGLYW-n1QUOAsh.js +0 -3
  364. package/dist/railroad-peg-LSFZ7HO6-PjnrpmCs.js +0 -3
  365. package/dist/schemas-DzK6U94N.js +0 -6057
  366. package/dist/stateDiagram-v2-UEYNNEHI-BTRUs8Il.js +0 -30
  367. package/dist/step-CKczO72Q.js +0 -670
  368. package/dist/swimlanesDiagram-ULZ7WXOC-NBmgBl9G.js +0 -31
  369. package/dist/timer-DpDyj9G0.js +0 -596
  370. package/dist/tooltip-Dt77sBeT.js +0 -390
  371. package/dist/treeView-QDETBFTQ-DU8LwHuf.js +0 -3
  372. package/dist/treemap-6X3UGDF4-DUk4-k_O.js +0 -3
  373. package/dist/useTheme-CVJ0UOf2.js +0 -841
  374. package/dist/vega-loader.browser-DEggZzni.js +0 -1083
  375. package/dist/wardley-OPB4EBWU-Db-AaGas.js +0 -3
  376. package/src/components/editor/output/EmotionCacheProvider.tsx +0 -32
@@ -1,11 +1,25 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
  // @vitest-environment jsdom
3
3
 
4
- import { act, renderHook } from "@testing-library/react";
4
+ import {
5
+ act,
6
+ fireEvent,
7
+ render,
8
+ renderHook,
9
+ screen,
10
+ } from "@testing-library/react";
5
11
  import { createStore, Provider as JotaiProvider } from "jotai";
6
12
  import type React from "react";
7
13
  import { ErrorBoundary } from "react-error-boundary";
8
- import { beforeEach, describe, expect, it, type Mock, vi } from "vitest";
14
+ import {
15
+ afterEach,
16
+ beforeEach,
17
+ describe,
18
+ expect,
19
+ it,
20
+ type Mock,
21
+ vi,
22
+ } from "vitest";
9
23
 
10
24
  vi.mock("@/core/websocket/useWebSocket", async () => {
11
25
  const actual =
@@ -26,6 +40,13 @@ vi.mock("@/core/runtime/config", async () => {
26
40
  };
27
41
  });
28
42
 
43
+ import { MockNotebook } from "@/__mocks__/notebook";
44
+ import { cellId } from "@/__tests__/branded";
45
+ import { notebookAtom } from "@/core/cells/cells";
46
+ import { AppConfigSchema } from "@/core/config/config-schema";
47
+ import { ConnectionNotice } from "@/components/editor/alerts/connection-notice";
48
+ import { kernelStartupErrorAtom } from "@/core/errors/state";
49
+ import type { NotificationPayload } from "@/core/kernel/messages";
29
50
  import { useRuntimeManager } from "@/core/runtime/config";
30
51
  import { initialRunCompletedAtom } from "../../kernel/state";
31
52
  import { connectionAtom } from "../../network/connection";
@@ -188,3 +209,192 @@ describe("useMarimoKernelConnection messages", () => {
188
209
  expect(store.get(initialRunCompletedAtom)).toBe(true);
189
210
  });
190
211
  });
212
+
213
+ it.each(["kernel-ready", "reconnected"])(
214
+ "waits for %s before marking the session connected",
215
+ async (op) => {
216
+ const store = createStore();
217
+ store.set(connectionAtom, { state: WebSocketState.CONNECTING });
218
+ vi.mocked(useConnectionTransport).mockClear();
219
+ vi.mocked(useConnectionTransport).mockReturnValue(
220
+ makeTransport(WebSocket.OPEN),
221
+ );
222
+ vi.mocked(useRuntimeManager).mockReturnValue(
223
+ makeRuntimeManager() as unknown as ReturnType<typeof useRuntimeManager>,
224
+ );
225
+ renderConnectionHook(store);
226
+ const options = vi.mocked(useConnectionTransport).mock.calls.at(-1)![0];
227
+
228
+ await act(async () => {
229
+ await options.onOpen(new Event("open"));
230
+ });
231
+ expect(store.get(connectionAtom).state).toBe(WebSocketState.CONNECTING);
232
+
233
+ act(() => {
234
+ options.onMessage(
235
+ new MessageEvent("message", {
236
+ data: JSON.stringify({
237
+ op,
238
+ data: {
239
+ op,
240
+ cell_ids: [],
241
+ codes: [],
242
+ names: [],
243
+ configs: [],
244
+ layout: null,
245
+ resumed: true,
246
+ ui_values: {},
247
+ last_executed_code: {},
248
+ last_execution_time: {},
249
+ app_config: { width: "normal" },
250
+ kiosk: false,
251
+ capabilities: { terminal: false },
252
+ auto_instantiated: false,
253
+ consumer_capabilities: { edit: true, interact: true },
254
+ },
255
+ }),
256
+ }),
257
+ );
258
+ });
259
+ expect(store.get(connectionAtom).state).toBe(WebSocketState.OPEN);
260
+ },
261
+ );
262
+
263
+ describe("connection notice", () => {
264
+ beforeEach(() => vi.useFakeTimers());
265
+ afterEach(() => vi.useRealTimers());
266
+
267
+ function renderNotice() {
268
+ const store = createStore();
269
+ store.set(connectionAtom, { state: WebSocketState.CONNECTING });
270
+ const transport = makeTransport(WebSocket.OPEN);
271
+ vi.mocked(useConnectionTransport).mockReturnValue(transport);
272
+ vi.mocked(useRuntimeManager).mockReturnValue(
273
+ makeRuntimeManager() as unknown as ReturnType<typeof useRuntimeManager>,
274
+ );
275
+ const Connection = () => {
276
+ const { reconnect } = useMarimoKernelConnection({
277
+ sessionId: "test-session" as SessionId,
278
+ autoInstantiate: false,
279
+ setCells: () => {},
280
+ });
281
+ return (
282
+ <ConnectionNotice
283
+ appConfig={AppConfigSchema.parse({})}
284
+ onRetry={reconnect}
285
+ />
286
+ );
287
+ };
288
+ render(
289
+ <JotaiProvider store={store}>
290
+ <ErrorBoundary fallback={null}>
291
+ <Connection />
292
+ </ErrorBoundary>
293
+ </JotaiProvider>,
294
+ );
295
+ const options = vi.mocked(useConnectionTransport).mock.calls.at(-1)![0];
296
+ const send = (data: NotificationPayload["data"]) =>
297
+ act(() => {
298
+ options.onMessage(
299
+ new MessageEvent("message", {
300
+ data: JSON.stringify({ op: data.op, data }),
301
+ }),
302
+ );
303
+ });
304
+ return { store, transport, options, send };
305
+ }
306
+
307
+ it("keeps elapsed time across startup phases and leaves reconnection to the footer once cells are available", () => {
308
+ const { store, options, send } = renderNotice();
309
+ send({ op: "startup-progress", phase: "preparing-environment" });
310
+ expect(
311
+ screen.queryByRole("region", { name: "Notebook startup" }),
312
+ ).not.toBeInTheDocument();
313
+ act(() => vi.advanceTimersByTime(500));
314
+ expect(screen.getByRole("status")).toHaveTextContent(
315
+ "Preparing environment",
316
+ );
317
+ act(() => vi.advanceTimersByTime(35_000));
318
+ expect(screen.getByText("Elapsed 35s")).toBeInTheDocument();
319
+ act(() =>
320
+ store.set(
321
+ notebookAtom,
322
+ MockNotebook.notebookState({
323
+ cellData: { [cellId("test")]: { code: "answer = 42" } },
324
+ }),
325
+ ),
326
+ );
327
+ send({ op: "startup-progress", phase: "starting-kernel" });
328
+ expect(screen.getByRole("status")).toHaveTextContent("Starting notebook");
329
+ expect(screen.getByText("Elapsed 35s")).toBeInTheDocument();
330
+ send({ op: "reconnected" });
331
+ expect(
332
+ screen.queryByRole("region", { name: "Notebook startup" }),
333
+ ).not.toBeInTheDocument();
334
+ act(() => options.onClose(new CloseEvent("close")));
335
+ act(() => vi.advanceTimersByTime(500));
336
+ expect(store.get(connectionAtom)).toEqual({
337
+ state: WebSocketState.CONNECTING,
338
+ phase: "reconnecting",
339
+ });
340
+ expect(
341
+ screen.queryByRole("region", { name: "Notebook startup" }),
342
+ ).not.toBeInTheDocument();
343
+ });
344
+
345
+ it("does not flash a notice when startup finishes within the delay", () => {
346
+ const { send } = renderNotice();
347
+ send({ op: "startup-progress", phase: "preparing-environment" });
348
+ act(() => vi.advanceTimersByTime(200));
349
+ send({ op: "startup-progress", phase: "starting-kernel" });
350
+ act(() => vi.advanceTimersByTime(200));
351
+ expect(
352
+ screen.queryByRole("region", { name: "Notebook startup" }),
353
+ ).not.toBeInTheDocument();
354
+ send({ op: "reconnected" });
355
+ act(() => vi.advanceTimersByTime(500));
356
+ expect(
357
+ screen.queryByRole("region", { name: "Notebook startup" }),
358
+ ).not.toBeInTheDocument();
359
+ });
360
+
361
+ it.each([
362
+ ["preparing-environment", "Sandbox setup failed"],
363
+ ["starting-kernel", "Kernel failed to start"],
364
+ ] as const)(
365
+ "keeps a %s failure available until the user retries",
366
+ async (phase, title) => {
367
+ const { store, transport, options, send } = renderNotice();
368
+ send({ op: "startup-progress", phase });
369
+ const error = "A full diagnostic\nwith <stderr> details";
370
+ send({ op: "kernel-startup-error", error });
371
+ transport.readyState = WebSocket.CLOSED;
372
+ act(() =>
373
+ options.onClose(
374
+ new CloseEvent("close", { reason: "MARIMO_KERNEL_STARTUP_ERROR" }),
375
+ ),
376
+ );
377
+ expect(screen.getByRole("status")).toHaveTextContent(title);
378
+ act(() => vi.advanceTimersByTime(30_000));
379
+ expect(screen.getByRole("status")).toHaveTextContent(title);
380
+ expect(screen.getByLabelText("Error details")).toHaveTextContent(error, {
381
+ normalizeWhitespace: false,
382
+ });
383
+ expect(transport.reconnect).not.toHaveBeenCalled();
384
+ await act(async () =>
385
+ fireEvent.click(screen.getByRole("button", { name: "Try again" })),
386
+ );
387
+ expect(transport.reconnect).toHaveBeenCalledOnce();
388
+ expect(store.get(kernelStartupErrorAtom)).toBeNull();
389
+ expect(
390
+ screen.queryByRole("button", { name: "Try again" }),
391
+ ).not.toBeInTheDocument();
392
+ send({ op: "startup-progress", phase: "preparing-environment" });
393
+ act(() => vi.advanceTimersByTime(500));
394
+ expect(screen.getByRole("status")).toHaveTextContent(
395
+ "Preparing environment",
396
+ );
397
+ expect(screen.getByText("Elapsed 0s")).toBeInTheDocument();
398
+ },
399
+ );
400
+ });
@@ -15,7 +15,7 @@ export type ConnectionTransportCallback<T extends ConnectionEvent> = (
15
15
  export interface IConnectionTransport {
16
16
  reconnect(code?: number | undefined, reason?: string | undefined): void;
17
17
  close(): void;
18
- send(data: string | ArrayBuffer | Blob | ArrayBufferView): void;
18
+ send(data: string | ArrayBuffer | Blob | ArrayBufferView<ArrayBuffer>): void;
19
19
  addEventListener<T extends ConnectionEvent>(
20
20
  event: T,
21
21
  callback: ConnectionTransportCallback<T>,
@@ -42,7 +42,7 @@ export class WsTransport implements IConnectionTransport {
42
42
  this.inner.close();
43
43
  }
44
44
 
45
- send(data: string | ArrayBuffer | Blob | ArrayBufferView): void {
45
+ send(data: string | ArrayBuffer | Blob | ArrayBufferView<ArrayBuffer>): void {
46
46
  this.inner.send(data);
47
47
  }
48
48
 
@@ -1,5 +1,11 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
+ import type { NotificationMessageData } from "../kernel/messages";
4
+
5
+ type ConnectionPhase =
6
+ | NotificationMessageData<"startup-progress">["phase"]
7
+ | "reconnecting";
8
+
3
9
  // TODO: rename to ConnectionState
4
10
  export const WebSocketState = {
5
11
  NOT_STARTED: "NOT_STARTED",
@@ -28,10 +34,14 @@ export type ConnectionStatus =
28
34
  * Human-readable reason for closing the connection.
29
35
  */
30
36
  reason: string;
37
+ phase?: ConnectionPhase;
38
+ }
39
+ | {
40
+ state: typeof WebSocketState.CONNECTING;
41
+ phase?: ConnectionPhase;
31
42
  }
32
43
  | {
33
44
  state:
34
- | typeof WebSocketState.CONNECTING
35
45
  | typeof WebSocketState.OPEN
36
46
  | typeof WebSocketState.CLOSING
37
47
  | typeof WebSocketState.NOT_STARTED;
@@ -1,5 +1,6 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
+ import { invalidatePackageData } from "@/core/packages/package-data";
3
4
  import { useAtom, useAtomValue, useSetAtom } from "jotai";
4
5
  import { useRef } from "react";
5
6
  import { useErrorBoundary } from "react-error-boundary";
@@ -240,7 +241,15 @@ export function useMarimoKernelConnection(opts: {
240
241
  case "reload":
241
242
  reloadSafe();
242
243
  return;
244
+ case "startup-progress":
245
+ setConnection({
246
+ state: WebSocketState.CONNECTING,
247
+ phase: msg.data.phase,
248
+ });
249
+ return;
243
250
  case "kernel-ready": {
251
+ setKernelStartupError(null);
252
+ setConnection({ state: WebSocketState.OPEN });
244
253
  setInitialRunCompleted(
245
254
  Boolean(msg.data.resumed || msg.data.auto_instantiated),
246
255
  );
@@ -363,6 +372,16 @@ export function useMarimoKernelConnection(opts: {
363
372
  });
364
373
  return;
365
374
  case "installing-package-alert":
375
+ if (
376
+ msg.data.source !== "server" &&
377
+ msg.data.log_status !== "append" &&
378
+ msg.data.log_status !== "start" &&
379
+ Object.values(msg.data.packages).some(
380
+ (status) => status === "installed" || status === "restart-required",
381
+ )
382
+ ) {
383
+ invalidatePackageData();
384
+ }
366
385
  addPackageAlert({
367
386
  ...msg.data,
368
387
  kind: "installing",
@@ -439,6 +458,8 @@ export function useMarimoKernelConnection(opts: {
439
458
  return;
440
459
 
441
460
  case "reconnected":
461
+ setKernelStartupError(null);
462
+ setConnection({ state: WebSocketState.OPEN });
442
463
  return;
443
464
 
444
465
  case "focus-cell":
@@ -482,6 +503,7 @@ export function useMarimoKernelConnection(opts: {
482
503
  return;
483
504
  }
484
505
  shouldTryReconnecting.current = true;
506
+ setKernelStartupError(null);
485
507
  setConnection({ state: WebSocketState.CONNECTING });
486
508
  const healthy = await runtimeManager.reconcileFromHealth();
487
509
  if (!healthy) {
@@ -513,17 +535,11 @@ export function useMarimoKernelConnection(opts: {
513
535
  headers: () => runtimeManager.headers(),
514
536
 
515
537
  /**
516
- * Open callback. Set the connection status to open.
538
+ * The transport is open; kernel-ready establishes session readiness.
517
539
  */
518
540
  onOpen: async () => {
519
541
  // If we are open, we can reset our reconnecting flag.
520
542
  shouldTryReconnecting.current = true;
521
-
522
- // DO NOT COMMIT THIS UNCOMMENTED
523
- // Uncomment to emulate a slow connection
524
- // await new Promise((resolve) => setTimeout(resolve, 10_000));
525
-
526
- setConnection({ state: WebSocketState.OPEN });
527
543
  },
528
544
 
529
545
  /**
@@ -565,7 +581,26 @@ export function useMarimoKernelConnection(opts: {
565
581
  onClose: (e) => {
566
582
  Logger.warn("WebSocket closed", e.code, e.reason);
567
583
  const decision = classifyCloseEvent(e);
568
- setConnection(decision.status);
584
+ setConnection((previous) => {
585
+ const status = decision.status;
586
+ if (
587
+ status.state === WebSocketState.CLOSED &&
588
+ status.code === WebSocketClosedReason.KERNEL_STARTUP_ERROR &&
589
+ (previous.state === WebSocketState.CONNECTING ||
590
+ previous.state === WebSocketState.CLOSED)
591
+ ) {
592
+ return { ...status, phase: previous.phase };
593
+ }
594
+ if (
595
+ status.state === WebSocketState.CONNECTING &&
596
+ (previous.state === WebSocketState.OPEN ||
597
+ (previous.state === WebSocketState.CONNECTING &&
598
+ previous.phase === "reconnecting"))
599
+ ) {
600
+ return { ...status, phase: "reconnecting" };
601
+ }
602
+ return status;
603
+ });
569
604
  if (decision.kind === "terminal" && decision.closeTransport) {
570
605
  ws.close(); // close to prevent reconnecting
571
606
  return;
@@ -82,6 +82,7 @@
82
82
  .console-output-area {
83
83
  max-height: 610px;
84
84
  overflow: auto;
85
+ overscroll-behavior: contain;
85
86
  }
86
87
 
87
88
  /* Special case for particular components */
@@ -521,6 +522,7 @@
521
522
  display: flow-root;
522
523
 
523
524
  overflow: auto;
525
+ overscroll-behavior: contain;
524
526
  }
525
527
 
526
528
  .marimo-output-stale,
@@ -48,6 +48,8 @@ export function useDebounceControlledState<T>(opts: {
48
48
 
49
49
  // Handle external changes:
50
50
  useEffect(() => {
51
+ // TODO: Replace this synchronization with a controlled-state primitive.
52
+ // oxlint-disable-next-line react/no-deriving-state-in-effects -- Synchronize the debounced draft when the controlled value changes.
51
53
  setInternalValue(initialValue);
52
54
  }, [initialValue]);
53
55
 
@@ -9,21 +9,15 @@ const AccordionTrigger = AccordionPrimitive.Trigger;
9
9
 
10
10
  import type { JSX } from "react";
11
11
  import { ZodError } from "zod";
12
- import { EmotionCacheProvider } from "@/components/editor/output/EmotionCacheProvider";
13
12
  import { JsonOutput } from "@/components/editor/output/JsonOutput";
14
13
  import { Alert, AlertTitle } from "../../components/ui/alert";
15
14
 
16
15
  interface Props {
17
16
  error: ZodError | Error;
18
- shadowRoot: ShadowRoot | null;
19
17
  badData: Record<string, unknown>;
20
18
  }
21
19
 
22
- export const BadPluginData: React.FC<Props> = ({
23
- error,
24
- badData,
25
- shadowRoot,
26
- }) => {
20
+ export const BadPluginData: React.FC<Props> = ({ error, badData }) => {
27
21
  if (error instanceof ZodError) {
28
22
  return (
29
23
  <Alert variant="destructive">
@@ -49,9 +43,7 @@ export const BadPluginData: React.FC<Props> = ({
49
43
  View Data:
50
44
  </AccordionTrigger>
51
45
  <AccordionContent className="text-[0.84375rem]">
52
- <EmotionCacheProvider container={shadowRoot}>
53
- <JsonOutput data={badData} />
54
- </EmotionCacheProvider>
46
+ <JsonOutput data={badData} />
55
47
  </AccordionContent>
56
48
  </AccordionItem>
57
49
  </Accordion>
@@ -65,9 +57,6 @@ export const BadPluginData: React.FC<Props> = ({
65
57
  export function renderError(
66
58
  error: ZodError | Error,
67
59
  badData: Record<string, unknown>,
68
- shadowRoot: ShadowRoot | null,
69
60
  ): JSX.Element {
70
- return (
71
- <BadPluginData error={error} badData={badData} shadowRoot={shadowRoot} />
72
- );
61
+ return <BadPluginData error={error} badData={badData} />;
73
62
  }
@@ -262,9 +262,29 @@ const wrapTooltipTargets: TransformFn = (
262
262
  if (tagName.startsWith("marimo-")) {
263
263
  return undefined;
264
264
  }
265
- const tooltipContent = domNode.attribs["data-tooltip"];
265
+ const tooltipContent = domNode.attribs["data-tooltip"].replace(
266
+ /^[\r\n]+|[\r\n]+$/g,
267
+ "",
268
+ );
266
269
  return (
267
- <Tooltip content={tooltipContent}>{reactNode as JSX.Element}</Tooltip>
270
+ <Tooltip
271
+ content={
272
+ tooltipContent.includes("\n") ? (
273
+ <span className="whitespace-pre-wrap">
274
+ {tooltipContent.split(/\r?\n/).map((line, i) => (
275
+ <React.Fragment key={i}>
276
+ {i > 0 && <br />}
277
+ {line}
278
+ </React.Fragment>
279
+ ))}
280
+ </span>
281
+ ) : (
282
+ tooltipContent
283
+ )
284
+ }
285
+ >
286
+ {reactNode as JSX.Element}
287
+ </Tooltip>
268
288
  );
269
289
  }
270
290
  };
@@ -1,5 +1,7 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
  import type { ExtractAtomValue } from "jotai";
3
+ import { isValidElement, type ReactNode } from "react";
4
+ import { renderToStaticMarkup } from "react-dom/server";
3
5
  import { afterEach, beforeEach, describe, expect, test } from "vitest";
4
6
  import { hasRunAnyCellAtom } from "@/components/editor/cell/useRunCells";
5
7
  import { userConfigAtom } from "@/core/config/config";
@@ -450,6 +452,191 @@ describe("wrapTooltipTargets", () => {
450
452
  </Tooltip>
451
453
  `);
452
454
  });
455
+
456
+ test("data-tooltip multiline via &#10; entity renders <br/>", () => {
457
+ const html =
458
+ '<span data-tooltip="Line A&#10;Line B&#10;Line C">hover</span>';
459
+ const result = parseHtml({ html });
460
+ expect(result).toMatchInlineSnapshot(`
461
+ <Tooltip
462
+ content={
463
+ <span
464
+ className="whitespace-pre-wrap"
465
+ >
466
+ <React.Fragment>
467
+ Line A
468
+ </React.Fragment>
469
+ <React.Fragment>
470
+ <br />
471
+ Line B
472
+ </React.Fragment>
473
+ <React.Fragment>
474
+ <br />
475
+ Line C
476
+ </React.Fragment>
477
+ </span>
478
+ }
479
+ >
480
+ <span
481
+ data-tooltip="Line A
482
+ Line B
483
+ Line C"
484
+ >
485
+ hover
486
+ </span>
487
+ </Tooltip>
488
+ `);
489
+ });
490
+
491
+ test("data-tooltip multiline via literal \\n renders <br/>", () => {
492
+ const html = '<span data-tooltip="Line A\nLine B">hover</span>';
493
+ expect(parseHtml({ html })).toMatchInlineSnapshot(`
494
+ <Tooltip
495
+ content={
496
+ <span
497
+ className="whitespace-pre-wrap"
498
+ >
499
+ <React.Fragment>
500
+ Line A
501
+ </React.Fragment>
502
+ <React.Fragment>
503
+ <br />
504
+ Line B
505
+ </React.Fragment>
506
+ </span>
507
+ }
508
+ >
509
+ <span
510
+ data-tooltip="Line A
511
+ Line B"
512
+ >
513
+ hover
514
+ </span>
515
+ </Tooltip>
516
+ `);
517
+ });
518
+
519
+ test("data-tooltip single line still works as before", () => {
520
+ const html = '<span data-tooltip="Single line">hover</span>';
521
+ expect(parseHtml({ html })).toMatchInlineSnapshot(`
522
+ <Tooltip
523
+ content="Single line"
524
+ >
525
+ <span
526
+ data-tooltip="Single line"
527
+ >
528
+ hover
529
+ </span>
530
+ </Tooltip>
531
+ `);
532
+ });
533
+
534
+ test.each([
535
+ ["CRLF", "A\r\nB", '<span class="whitespace-pre-wrap">A<br/>B</span>'],
536
+ [
537
+ "encoded CRLF",
538
+ "A&#13;&#10;B",
539
+ '<span class="whitespace-pre-wrap">A<br/>B</span>',
540
+ ],
541
+ ["leading newline", "\nA", "A"],
542
+ ["trailing newline", "A\n", "A"],
543
+ [
544
+ "boundary newlines",
545
+ "\n\nA\nB\n\n",
546
+ '<span class="whitespace-pre-wrap">A<br/>B</span>',
547
+ ],
548
+ [
549
+ "boundary CRLF",
550
+ "&#13;&#10;A&#13;&#10;B&#13;&#10;",
551
+ '<span class="whitespace-pre-wrap">A<br/>B</span>',
552
+ ],
553
+ ["only newlines", "\n\n", ""],
554
+ ["only CRLF", "&#13;&#10;&#13;&#10;", ""],
555
+ [
556
+ "internal blank line",
557
+ "A\n\nB",
558
+ '<span class="whitespace-pre-wrap">A<br/><br/>B</span>',
559
+ ],
560
+ [
561
+ "spaces and tabs",
562
+ "\n A\t\n\tB \n",
563
+ '<span class="whitespace-pre-wrap"> A\t<br/>\tB </span>',
564
+ ],
565
+ [
566
+ "HTML text",
567
+ "&lt;b&gt;A&lt;/b&gt;\nB",
568
+ '<span class="whitespace-pre-wrap">&lt;b&gt;A&lt;/b&gt;<br/>B</span>',
569
+ ],
570
+ ])("data-tooltip handles %s", (_, content, expected) => {
571
+ const result = parseHtml({
572
+ html: `<span data-tooltip="${content}">Hover me</span>`,
573
+ });
574
+ if (!isValidElement<{ content: ReactNode }>(result)) {
575
+ throw new Error("Expected a Tooltip element");
576
+ }
577
+ expect(renderToStaticMarkup(result.props.content)).toBe(expected);
578
+ });
579
+
580
+ test("data-tooltip with newline renders as line breaks", () => {
581
+ const html = '<span data-tooltip="Line one\nLine two">Hover me</span>';
582
+ expect(parseHtml({ html })).toMatchInlineSnapshot(`
583
+ <Tooltip
584
+ content={
585
+ <span
586
+ className="whitespace-pre-wrap"
587
+ >
588
+ <React.Fragment>
589
+ Line one
590
+ </React.Fragment>
591
+ <React.Fragment>
592
+ <br />
593
+ Line two
594
+ </React.Fragment>
595
+ </span>
596
+ }
597
+ >
598
+ <span
599
+ data-tooltip="Line one
600
+ Line two"
601
+ >
602
+ Hover me
603
+ </span>
604
+ </Tooltip>
605
+ `);
606
+ });
607
+
608
+ test("data-tooltip with multiple newlines renders all as line breaks", () => {
609
+ const html = '<span data-tooltip="A\nB\nC">Hover me</span>';
610
+ expect(parseHtml({ html })).toMatchInlineSnapshot(`
611
+ <Tooltip
612
+ content={
613
+ <span
614
+ className="whitespace-pre-wrap"
615
+ >
616
+ <React.Fragment>
617
+ A
618
+ </React.Fragment>
619
+ <React.Fragment>
620
+ <br />
621
+ B
622
+ </React.Fragment>
623
+ <React.Fragment>
624
+ <br />
625
+ C
626
+ </React.Fragment>
627
+ </span>
628
+ }
629
+ >
630
+ <span
631
+ data-tooltip="A
632
+ B
633
+ C"
634
+ >
635
+ Hover me
636
+ </span>
637
+ </Tooltip>
638
+ `);
639
+ });
453
640
  });
454
641
 
455
642
  describe("parseHtml with < nad >", () => {