@marimo-team/frontend 0.21.2-dev5 → 0.21.2-dev53

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 (386) hide show
  1. package/dist/assets/{CellStatus-CDSBsjjF.js → CellStatus-DX8MnBMk.js} +1 -1
  2. package/dist/assets/{ConnectedDataExplorerComponent-Buaffg3u.js → ConnectedDataExplorerComponent-7yXYooWG.js} +1 -1
  3. package/dist/assets/{DeferredRequestRegistry-O6RDJKs0.js → DeferredRequestRegistry-B8jPCuU1.js} +1 -1
  4. package/dist/assets/{ImperativeModal-qEtcJ95s.js → ImperativeModal-C3CD5-Aq.js} +1 -1
  5. package/dist/assets/JsonOutput-DqjAyzM8.js +46 -0
  6. package/dist/assets/{LazyAnyLanguageCodeMirror-m8w66E4s.js → LazyAnyLanguageCodeMirror-CcCHIX38.js} +2 -2
  7. package/dist/assets/{MarimoErrorOutput-az74f3Mp.js → MarimoErrorOutput-Dat_S09q.js} +5 -5
  8. package/dist/assets/RenderHTML-C7XM39M2.js +1 -0
  9. package/dist/assets/{add-cell-with-ai-DUn4LN4W.js → add-cell-with-ai-y2xroEGf.js} +9 -9
  10. package/dist/assets/{add-connection-dialog-CBz0AUVX.js → add-connection-dialog-QDBOmil3.js} +23 -23
  11. package/dist/assets/{agent-panel-u83dsDsM.js → agent-panel-DziFrEjJ.js} +6 -6
  12. package/dist/assets/ai-model-dropdown-CiJpv5wN.js +5 -0
  13. package/dist/assets/{alert-dialog-9WfvUF7e.js → alert-dialog-ebk_-wsU.js} +1 -1
  14. package/dist/assets/{any-language-editor-DwQMnAM3.js → any-language-editor-DZYnKlJB.js} +1 -1
  15. package/dist/assets/{app-config-button-rDu-lCIB.js → app-config-button-CpAv9Tiu.js} +1 -1
  16. package/dist/assets/{architectureDiagram-VXUJARFQ-DfMHHFZ3.js → architectureDiagram-VXUJARFQ-DKmk99ac.js} +1 -1
  17. package/dist/assets/{azure-BTXHztTw.js → azure-Dw5gKmUz.js} +1 -1
  18. package/dist/assets/{blockDiagram-VD42YOAC-CuEDwbg7.js → blockDiagram-VD42YOAC-TpAhP5OQ.js} +1 -1
  19. package/dist/assets/{c4Diagram-YG6GDRKO-CD9uz7WG.js → c4Diagram-YG6GDRKO-Dg8hCyKf.js} +1 -1
  20. package/dist/assets/{cache-panel-qIxnndwr.js → cache-panel-D0OsHk_D.js} +1 -1
  21. package/dist/assets/cell-editor-RbAVpSFb.js +22 -0
  22. package/dist/assets/{cell-link-Q_UEP94Z.js → cell-link-CNgO3c-T.js} +1 -1
  23. package/dist/assets/{cells-fq1RMGX_.js → cells-39RE4UzS.js} +77 -76
  24. package/dist/assets/channel-D1wPYhc9.js +1 -0
  25. package/dist/assets/{chat-display-D_Fuuy6r.js → chat-display-BPUVrlA6.js} +1 -1
  26. package/dist/assets/{chat-panel-BO-JoQSp.js → chat-panel-esz5TfF-.js} +2 -2
  27. package/dist/assets/{chunk-5FQGJX7Z-CM1a_K7I.js → chunk-5FQGJX7Z-sGWxL7Ey.js} +3 -3
  28. package/dist/assets/{chunk-ABZYJK2D-D_Wumzom.js → chunk-ABZYJK2D-DXJ7hnjx.js} +1 -1
  29. package/dist/assets/{chunk-ATLVNIR6-BZ0lTgIn.js → chunk-ATLVNIR6-CTEqcLEc.js} +1 -1
  30. package/dist/assets/{chunk-B4BG7PRW-Dw1S6osV.js → chunk-B4BG7PRW-CkAIqtPf.js} +1 -1
  31. package/dist/assets/{chunk-DI55MBZ5-Q63FTCPP.js → chunk-DI55MBZ5-C4F9vu8o.js} +1 -1
  32. package/dist/assets/{chunk-EXTU4WIE-CfkJ_R7W.js → chunk-EXTU4WIE-BT0Py-4P.js} +1 -1
  33. package/dist/assets/{chunk-JA3XYJ7Z-B41fGeoj.js → chunk-JA3XYJ7Z-CGd7jja_.js} +1 -1
  34. package/dist/assets/{chunk-JZLCHNYA-D43EJxQw.js → chunk-JZLCHNYA-CqY-RYTj.js} +1 -1
  35. package/dist/assets/{chunk-N4CR4FBY-DCtw0-ni.js → chunk-N4CR4FBY-aUDjVzN7.js} +2 -2
  36. package/dist/assets/{chunk-QN33PNHL-CLA2rsaS.js → chunk-QN33PNHL-DHnCb5-U.js} +1 -1
  37. package/dist/assets/{chunk-QXUST7PY-De1DpbnL.js → chunk-QXUST7PY-CRO5kYCE.js} +1 -1
  38. package/dist/assets/{chunk-S3R3BYOJ-qrwvlUdq.js → chunk-S3R3BYOJ-CSHQgcuP.js} +1 -1
  39. package/dist/assets/{chunk-TZMSLE5B-C4KcThb0.js → chunk-TZMSLE5B-CE7o9asH.js} +1 -1
  40. package/dist/assets/classDiagram-2ON5EDUG-BDIQSKYv.js +1 -0
  41. package/dist/assets/classDiagram-v2-WZHVMYZB-Cdh4cVOB.js +1 -0
  42. package/dist/assets/{code-block-37QAKDTI-D4FF4cnN.js → code-block-37QAKDTI-DMpe1jNG.js} +1 -1
  43. package/dist/assets/{column-preview-WsubyItX.js → column-preview-BUKHsglA.js} +1 -1
  44. package/dist/assets/{command-rfxSsiHU.js → command-DmzEbs6L.js} +1 -1
  45. package/dist/assets/{command-palette-Bez4BqJF.js → command-palette-BX5gNpUr.js} +1 -1
  46. package/dist/assets/{common-BYwO983A.js → common-B4yshY-H.js} +1 -1
  47. package/dist/assets/{components-Ozq0825a.js → components-DCqJqyys.js} +1 -1
  48. package/dist/assets/{components-Bpgzv_5_.js → components-oKCjx6cN.js} +1 -1
  49. package/dist/assets/{config-3Aq84phF.js → config-DqxNMQDN.js} +1 -1
  50. package/dist/assets/{context-CIAP2NOh.js → context-CRmPPhx9.js} +1 -1
  51. package/dist/assets/{context-aware-panel-CfsfBlhO.js → context-aware-panel-DC0Te9Hj.js} +2 -2
  52. package/dist/assets/copy-KjcPgPw9.js +1 -0
  53. package/dist/assets/{copy-icon-BgmMM9Zg.js → copy-icon-P0kzz1Pr.js} +1 -1
  54. package/dist/assets/{dagre-6UL2VRFP-BhMnPhuU.js → dagre-6UL2VRFP-XqoNLMQ3.js} +1 -1
  55. package/dist/assets/{data-grid-overlay-editor-kbv73SQ7.js → data-grid-overlay-editor-Cus1-BFN.js} +1 -1
  56. package/dist/assets/{datasource-F9sJtuof.js → datasource-DKHG39NV.js} +2 -2
  57. package/dist/assets/{dates-CHaNfieI.js → dates-CTqMeMGY.js} +1 -1
  58. package/dist/assets/{dependency-graph-panel-AOBcX2tP.js → dependency-graph-panel-7GKT3dyD.js} +4 -4
  59. package/dist/assets/{diagram-PSM6KHXK-Cr2t4zul.js → diagram-PSM6KHXK-BuzKNNcN.js} +1 -1
  60. package/dist/assets/{diagram-QEK2KX5R-DLU_hSO4.js → diagram-QEK2KX5R-A5LBQS11.js} +1 -1
  61. package/dist/assets/{diagram-S2PKOQOG-C7EkNAO3.js → diagram-S2PKOQOG-dkJE8SA0.js} +1 -1
  62. package/dist/assets/{dialog-CVN1lcMF.js → dialog-1_jIyAb_.js} +1 -1
  63. package/dist/assets/{dist-DJBpXGro.js → dist-6P6vjf93.js} +1 -1
  64. package/dist/assets/dist-BWGxTsTP.js +1 -0
  65. package/dist/assets/{dist-CblX3KGI.js → dist-B_buFm3B.js} +1 -1
  66. package/dist/assets/{dist-CXLJUPFl.js → dist-BatEf-0f.js} +1 -1
  67. package/dist/assets/dist-C3AnARPE.js +1 -0
  68. package/dist/assets/{dist-BNC_tnlW.js → dist-C6ohaMKU.js} +1 -1
  69. package/dist/assets/{dist-BoDHthoc.js → dist-CO9Pg2Rc.js} +1 -1
  70. package/dist/assets/{dist-By6zhkxZ.js → dist-CSV6H5w_.js} +1 -1
  71. package/dist/assets/{dist-6FIAeDIu.js → dist-CYs1oP7g.js} +1 -1
  72. package/dist/assets/{dist-DbK_4_qo.js → dist-DD9ZJMK5.js} +1 -1
  73. package/dist/assets/{dist-DlTbNRBn.js → dist-DReDpc2z.js} +1 -1
  74. package/dist/assets/dist-DSlq5ZeQ.js +1 -0
  75. package/dist/assets/{dist-DrceDAhM.js → dist-DXyIIB32.js} +1 -1
  76. package/dist/assets/{dist-CcGcwrUD.js → dist-DkaderFA.js} +1 -1
  77. package/dist/assets/{dist-BiZQlfhr.js → dist-Dq3BlK4R.js} +1 -1
  78. package/dist/assets/{dist-ClzRAVN-.js → dist-Dxov2ltb.js} +1 -1
  79. package/dist/assets/{dist-BXXPfIam.js → dist-EtGG9C1A.js} +1 -1
  80. package/dist/assets/{dist-C3MmXcLA.js → dist-NjId5Gdz.js} +1 -1
  81. package/dist/assets/dist-ZM59OWYL.js +1 -0
  82. package/dist/assets/dist-_TwZ4tIe.js +1 -0
  83. package/dist/assets/dist-f9b2H4q_.js +1 -0
  84. package/dist/assets/{dist-mxGLXOFm.js → dist-feWVQ4dq.js} +1 -1
  85. package/dist/assets/{documentation-panel-D28MpqbI.js → documentation-panel-D5d_BbHV.js} +1 -1
  86. package/dist/assets/{download-B9_ToVd4.js → download-B1vXaivj.js} +4 -4
  87. package/dist/assets/{dropdown-menu-DdPu5Kfu.js → dropdown-menu-BehqiLFL.js} +1 -1
  88. package/dist/assets/{edit-page-otS-QvnC.js → edit-page-B5cAZdO7.js} +7 -7
  89. package/dist/assets/{en-US-BO8E69bZ.js → en-US-f8tajDx1.js} +1 -1
  90. package/dist/assets/{erDiagram-Q2GNP2WA-DqlEo_Us.js → erDiagram-Q2GNP2WA-CgH6udOW.js} +1 -1
  91. package/dist/assets/{error-banner-BRG6IPhC.js → error-banner-J5F3weEj.js} +1 -1
  92. package/dist/assets/{error-panel-RRoj_iOR.js → error-panel-DnhKJ5Ou.js} +1 -1
  93. package/dist/assets/{es-CzkousWe.js → es-DYI7U61K.js} +1 -1
  94. package/dist/assets/{esm-CBkHtTOV.js → esm-BC1J92im.js} +1 -1
  95. package/dist/assets/{esm-DhTsVMLM.js → esm-DKLLCu3N.js} +1 -1
  96. package/dist/assets/{field-B1jGbQlH.js → field-B08lvxnl.js} +1 -1
  97. package/dist/assets/file-explorer-panel-BUk69TND.js +26 -0
  98. package/dist/assets/{file-icons-CWLHDa1J.js → file-icons-3DTS8ZM7.js} +1 -1
  99. package/dist/assets/{floating-outline-BvQKiC0F.js → floating-outline-DmugATcB.js} +1 -1
  100. package/dist/assets/{flowDiagram-NV44I4VS-CQlIJ12H.js → flowDiagram-NV44I4VS-D85BL4rA.js} +1 -1
  101. package/dist/assets/{focus-DYwTiH9-.js → focus-DlJH7sfh.js} +1 -1
  102. package/dist/assets/{form-CrQYrsUC.js → form-760_EqmF.js} +2 -2
  103. package/dist/assets/{formats-rhOJovGE.js → formats-wYuh1bqp.js} +1 -1
  104. package/dist/assets/{formatting-B4ZCH3ol.js → formatting-CraOPe94.js} +1 -1
  105. package/dist/assets/{gallery-page-eRea0yic.js → gallery-page--paiPvYX.js} +1 -1
  106. package/dist/assets/{ganttDiagram-JELNMOA3-B3EGIuZL.js → ganttDiagram-JELNMOA3-DzCOXWlF.js} +1 -1
  107. package/dist/assets/{gitGraphDiagram-V2S2FVAM-h5SlguJK.js → gitGraphDiagram-V2S2FVAM-BUHURX6t.js} +1 -1
  108. package/dist/assets/{glide-data-editor-xt5xNZeV.js → glide-data-editor-DYdoQTO5.js} +4 -4
  109. package/dist/assets/{globals-BsV5fVR-.js → globals-7M5DRsIb.js} +1 -1
  110. package/dist/assets/home-page-CxQ1e98h.js +4 -0
  111. package/dist/assets/{hooks-CHx5dUUq.js → hooks-C3jEff2O.js} +1 -1
  112. package/dist/assets/html-to-image-DTFXm6_Z.js +2 -0
  113. package/dist/assets/{index-GjXovVsl.css → index-BmoocKR0.css} +1 -1
  114. package/dist/assets/index-DNchElHl.js +38 -0
  115. package/dist/assets/{infoDiagram-HS3SLOUP-pzpClObZ.js → infoDiagram-HS3SLOUP-GG5r0Y5G.js} +1 -1
  116. package/dist/assets/{input-CUwqpKjd.js → input-CN1ZeRYm.js} +1 -1
  117. package/dist/assets/{isValid-BGe7pJXT.js → isValid-DY4Mgbr7.js} +1 -1
  118. package/dist/assets/{journeyDiagram-XKPGCS4Q-BrdRi92v.js → journeyDiagram-XKPGCS4Q-B1dvnV4D.js} +1 -1
  119. package/dist/assets/{kanban-definition-3W4ZIXB7-B6WqgFqh.js → kanban-definition-3W4ZIXB7-CefbrXQv.js} +1 -1
  120. package/dist/assets/{kiosk-mode-DNjEnIWb.js → kiosk-mode-CyTnrzwK.js} +1 -1
  121. package/dist/assets/{layout-CwFtCyW8.js → layout-3b3tzmbb.js} +3 -3
  122. package/dist/assets/{linear-BP9rwmWK.js → linear-BDnrHGYO.js} +1 -1
  123. package/dist/assets/{links-CIQwYQ48.js → links-CptYD1FP.js} +1 -1
  124. package/dist/assets/{logs-panel-BU1tNEVc.js → logs-panel-C4k_2IHW.js} +1 -1
  125. package/dist/assets/{markdown-renderer-MR9df58W.js → markdown-renderer-DSy5IuAx.js} +1 -1
  126. package/dist/assets/{menu-items-UxKrm8hS.js → menu-items-BpHXKv51.js} +1 -1
  127. package/dist/assets/mermaid-4DMBBIKO-g7AL4SLJ.js +1 -0
  128. package/dist/assets/{mermaid-Djr3jUAB.js → mermaid-C43VbdrM.js} +3 -3
  129. package/dist/assets/{mermaid-parser.core-DR82IMb2.js → mermaid-parser.core-CdM8D_p_.js} +1 -1
  130. package/dist/assets/{mindmap-definition-VGOIOE7T-DAmJpbPM.js → mindmap-definition-VGOIOE7T-CcV7D-wF.js} +1 -1
  131. package/dist/assets/{mode-AcL8c6qH.js → mode-D-iRbN9x.js} +1 -1
  132. package/dist/assets/{multi-map-Pp1P2DOX.js → multi-map-C8RbwBrw.js} +1 -1
  133. package/dist/assets/{name-cell-input-DVFEv_aO.js → name-cell-input-Dyb0ZO4X.js} +1 -1
  134. package/dist/assets/{number-overlay-editor-D__AflXQ.js → number-overlay-editor-BBJO1mf8.js} +1 -1
  135. package/dist/assets/{outline-panel-CP0oIuiU.js → outline-panel-D7CJwO8u.js} +1 -1
  136. package/dist/assets/{packages-panel-CzRELimG.js → packages-panel-Bp1SYjgc.js} +1 -1
  137. package/dist/assets/{panels-wTweRyIv.js → panels-D0aw6jdc.js} +1 -1
  138. package/dist/assets/{pieDiagram-ADFJNKIX-DbGIFRoq.js → pieDiagram-ADFJNKIX-C1fBf15W.js} +1 -1
  139. package/dist/assets/{popover-BPGG2gPG.js → popover-Bvoif-Mg.js} +1 -1
  140. package/dist/assets/{precisionRound-BOmLQIKI.js → precisionRound-CCOoIlcP.js} +1 -1
  141. package/dist/assets/{process-output-CTVsT--B.js → process-output-BxPWHcIi.js} +1 -1
  142. package/dist/assets/{quadrantDiagram-AYHSOK5B-CLAtyple.js → quadrantDiagram-AYHSOK5B-RVooN-fX.js} +1 -1
  143. package/dist/assets/{react-vega-BZav_-2n.js → react-vega-BKRQSy0g.js} +1 -1
  144. package/dist/assets/react-vega-DXESF7qN.js +1 -0
  145. package/dist/assets/{readonly-python-code-DH-1xZGq.js → readonly-python-code-D95oshJa.js} +1 -1
  146. package/dist/assets/{renderShortcut-CnD1Dah5.js → renderShortcut-BYvKm38e.js} +1 -1
  147. package/dist/assets/{request-registry-B-7cIM_I.js → request-registry-XB2EzJHm.js} +1 -1
  148. package/dist/assets/{requirementDiagram-UZGBJVZJ-DDDTB1LD.js → requirementDiagram-UZGBJVZJ-DtqOYJpH.js} +1 -1
  149. package/dist/assets/{run-page-FCvGnICa.js → run-page-B7CASued.js} +1 -1
  150. package/dist/assets/{sankeyDiagram-TZEHDZUN-DAWPOfBw.js → sankeyDiagram-TZEHDZUN-DmcooLA8.js} +1 -1
  151. package/dist/assets/{scratchpad-panel-k9lrm-rC.js → scratchpad-panel-BIVRgYOU.js} +1 -1
  152. package/dist/assets/{secrets-panel-B1Z-6dmz.js → secrets-panel-C24hZEiO.js} +1 -1
  153. package/dist/assets/{select-CxT2Geqr.js → select-Cnd3vm9n.js} +1 -1
  154. package/dist/assets/{sequenceDiagram-WL72ISMW-D_qAidD2.js → sequenceDiagram-WL72ISMW-S2qeLb7J.js} +1 -1
  155. package/dist/assets/{session-panel-WhN0qilM.js → session-panel-CNabBHQm.js} +1 -1
  156. package/dist/assets/{share-BdH_5I58.js → share-NjpZ54PJ.js} +1 -1
  157. package/dist/assets/{snippets-panel-BCDHUuku.js → snippets-panel-D1JAeJj1.js} +1 -1
  158. package/dist/assets/{spec-DbmSqx09.js → spec-DnVBmJUh.js} +1 -1
  159. package/dist/assets/{state-Ce7CVShi.js → state-BagvlaEz.js} +1 -1
  160. package/dist/assets/{state-3V5UxC3B.js → state-Cz_wrzCz.js} +1 -1
  161. package/dist/assets/{state-CBmCYWFH.js → state-DMQXxemS.js} +1 -1
  162. package/dist/assets/{stateDiagram-FKZM4ZOC-C7qgDrGA.js → stateDiagram-FKZM4ZOC-uuQ60pIl.js} +1 -1
  163. package/dist/assets/stateDiagram-v2-4FDKWEC3-D-GWhQTG.js +1 -0
  164. package/dist/assets/stex-CruVQx-P.js +1 -0
  165. package/dist/assets/{switch-CVKxYu_0.js → switch-Bwpd2AFq.js} +1 -1
  166. package/dist/assets/{terminal-Cr7wbEjz.js → terminal-Gl8Fi44y.js} +1 -1
  167. package/dist/assets/{time-D2GKc0U6.js → time-Bw8f15NM.js} +1 -1
  168. package/dist/assets/{timeline-definition-IT6M3QCI-hd6uJKGs.js → timeline-definition-IT6M3QCI-TKWeDnSQ.js} +1 -1
  169. package/dist/assets/{toggle-RCwU-rnE.js → toggle-C_gNjXg8.js} +1 -1
  170. package/dist/assets/{tooltip-D9723Brr.js → tooltip-CR_izE8Q.js} +1 -1
  171. package/dist/assets/tracing-DwAC7DWN.js +1 -0
  172. package/dist/assets/tracing-panel-D1iNgclL.js +2 -0
  173. package/dist/assets/{tree-Ch2-GuhG.js → tree-WVrWjdwv.js} +3 -3
  174. package/dist/assets/{useAddCell-YC7rpcmD.js → useAddCell-D6Q7JziZ.js} +1 -1
  175. package/dist/assets/{useBoolean-m1e6E3Ao.js → useBoolean-CrltYVhE.js} +1 -1
  176. package/dist/assets/{useCellActionButton-GUb2fXU8.js → useCellActionButton-B2G9OaX9.js} +1 -1
  177. package/dist/assets/{useDateFormatter-CpE7XQLs.js → useDateFormatter-DOoVZUts.js} +1 -1
  178. package/dist/assets/{useDeleteCell-DRUDRiy0.js → useDeleteCell-d8veThW7.js} +1 -1
  179. package/dist/assets/{useDependencyPanelTab-nFVMlEx0.js → useDependencyPanelTab-B3iIj3MO.js} +1 -1
  180. package/dist/assets/{useInstallPackage-C9V-on2J.js → useInstallPackage-CQEr5429.js} +1 -1
  181. package/dist/assets/{useNotebookActions-ChLHy-0O.js → useNotebookActions-SAEOWcBo.js} +1 -1
  182. package/dist/assets/{useNumberFormatter-DbDKSvEd.js → useNumberFormatter-BXZcbTzH.js} +1 -1
  183. package/dist/assets/{usePress-BHGkpw8X.js → usePress-alQ5Crny.js} +1 -1
  184. package/dist/assets/{useRunCells-5m6jCnyo.js → useRunCells-Dhl8ZTGh.js} +1 -1
  185. package/dist/assets/{useSplitCell-DGD9smMq.js → useSplitCell-BSnFazbH.js} +1 -1
  186. package/dist/assets/{utils-CdjCA1J8.js → utils-C24l2A1T.js} +1 -1
  187. package/dist/assets/{vega-component-CRbeDmeM.js → vega-component-9Pf4pVZL.js} +1 -1
  188. package/dist/assets/{vega-loader.browser-CZV6_g2i.js → vega-loader.browser-BJ9oKrvH.js} +1 -1
  189. package/dist/assets/{write-secret-modal-BCvuRAFb.js → write-secret-modal-BFCsWMoW.js} +1 -1
  190. package/dist/assets/{xychartDiagram-PRI3JC2R-CXlUBSbQ.js → xychartDiagram-PRI3JC2R-CIp-yeSa.js} +1 -1
  191. package/dist/index.html +125 -125
  192. package/package.json +1 -1
  193. package/src/__mocks__/notebook.ts +9 -9
  194. package/src/__tests__/branded.ts +20 -0
  195. package/src/components/app-config/user-config-form.tsx +5 -4
  196. package/src/components/data-table/__tests__/utils.test.ts +138 -1
  197. package/src/components/data-table/charts/__tests__/storage.test.ts +7 -7
  198. package/src/components/data-table/context-menu.tsx +9 -5
  199. package/src/components/data-table/data-table.tsx +3 -0
  200. package/src/components/data-table/range-focus/__tests__/atoms.test.ts +8 -2
  201. package/src/components/data-table/range-focus/__tests__/test-utils.ts +2 -0
  202. package/src/components/data-table/range-focus/__tests__/utils.test.ts +82 -8
  203. package/src/components/data-table/range-focus/atoms.ts +2 -2
  204. package/src/components/data-table/range-focus/utils.ts +50 -12
  205. package/src/components/data-table/types.ts +7 -0
  206. package/src/components/data-table/utils.ts +87 -0
  207. package/src/components/editor/__tests__/data-attributes.test.tsx +8 -8
  208. package/src/components/editor/ai/__tests__/completion-utils.test.ts +15 -15
  209. package/src/components/editor/navigation/__tests__/clipboard.test.ts +2 -2
  210. package/src/components/editor/navigation/__tests__/selection.test.ts +7 -6
  211. package/src/components/editor/navigation/__tests__/state.test.ts +8 -7
  212. package/src/components/editor/output/MarimoErrorOutput.tsx +7 -7
  213. package/src/components/editor/output/__tests__/traceback.test.tsx +4 -4
  214. package/src/components/editor/output/console/__tests__/ConsoleOutput.test.tsx +4 -4
  215. package/src/components/editor/renderers/vertical-layout/useFocusFirstEditor.ts +8 -1
  216. package/src/components/storage/storage-file-viewer.tsx +35 -1
  217. package/src/components/storage/storage-inspector.tsx +9 -4
  218. package/src/components/storage/storage-snippets.ts +3 -3
  219. package/src/components/tracing/tracing.tsx +3 -1
  220. package/src/components/ui/range-slider.tsx +108 -1
  221. package/src/core/ai/__tests__/staged-cells.test.ts +9 -8
  222. package/src/core/ai/context/providers/__tests__/cell-output.test.ts +31 -31
  223. package/src/core/ai/context/providers/__tests__/datasource.test.ts +3 -3
  224. package/src/core/ai/context/providers/__tests__/tables.test.ts +3 -2
  225. package/src/core/ai/context/providers/__tests__/variable.test.ts +84 -63
  226. package/src/core/ai/tools/__tests__/edit-notebook-tool.test.ts +10 -9
  227. package/src/core/ai/tools/__tests__/run-cells-tool.test.ts +6 -6
  228. package/src/core/ai/tools/edit-notebook-tool.ts +3 -3
  229. package/src/core/cells/__tests__/add-missing-import.test.ts +3 -3
  230. package/src/core/cells/__tests__/cells.test.ts +192 -135
  231. package/src/core/cells/__tests__/focus.test.ts +5 -4
  232. package/src/core/cells/__tests__/logs.test.ts +13 -12
  233. package/src/core/cells/__tests__/pending-delete-service.test.tsx +3 -3
  234. package/src/core/cells/__tests__/runs.test.ts +22 -21
  235. package/src/core/cells/__tests__/scrollCellIntoView.test.ts +8 -7
  236. package/src/core/cells/__tests__/session.test.ts +23 -22
  237. package/src/core/cells/cells.ts +1 -1
  238. package/src/core/cells/ids.ts +5 -5
  239. package/src/core/cells/logs.ts +2 -2
  240. package/src/core/cells/runs.ts +6 -8
  241. package/src/core/codemirror/__tests__/format.test.ts +34 -36
  242. package/src/core/codemirror/__tests__/setup.test.ts +2 -2
  243. package/src/core/codemirror/cells/__tests__/extensions.test.ts +114 -0
  244. package/src/core/codemirror/cells/__tests__/traceback-decorations.test.ts +33 -32
  245. package/src/core/codemirror/cells/extensions.ts +66 -23
  246. package/src/core/codemirror/completion/__tests__/keymap.test.ts +15 -35
  247. package/src/core/codemirror/completion/keymap.ts +14 -4
  248. package/src/core/codemirror/copilot/__tests__/getCodes.test.ts +12 -13
  249. package/src/core/codemirror/language/__tests__/utils.test.ts +3 -3
  250. package/src/core/codemirror/language/embedded/__tests__/embedded-python.test.ts +7 -8
  251. package/src/core/codemirror/language/languages/python.ts +4 -0
  252. package/src/core/codemirror/lsp/__tests__/notebook-lsp.test.ts +4 -3
  253. package/src/core/codemirror/lsp/notebook-lsp.ts +28 -2
  254. package/src/core/codemirror/reactive-references/__tests__/analyzer.test.ts +7 -6
  255. package/src/core/codemirror/reactive-references/analyzer.ts +2 -2
  256. package/src/core/codemirror/rtc/loro/__tests__/sync.test.ts +52 -0
  257. package/src/core/codemirror/rtc/loro/sync.ts +1 -0
  258. package/src/core/datasets/__tests__/data-source.test.ts +5 -6
  259. package/src/core/datasets/state.ts +1 -1
  260. package/src/core/errors/__tests__/errors.test.ts +2 -1
  261. package/src/core/export/__tests__/hooks.test.ts +37 -36
  262. package/src/core/islands/main.ts +2 -7
  263. package/src/core/kernel/__tests__/handlers.test.ts +5 -4
  264. package/src/core/kernel/handlers.ts +7 -4
  265. package/src/core/network/DeferredRequestRegistry.ts +2 -2
  266. package/src/core/network/__tests__/CachingRequestRegistry.test.ts +9 -10
  267. package/src/core/network/__tests__/DeferredRequestRegistry.test.ts +4 -6
  268. package/src/core/static/__tests__/virtual-file-tracker.test.ts +8 -8
  269. package/src/core/static/virtual-file-tracker.ts +1 -1
  270. package/src/core/storage/__tests__/state.test.ts +31 -21
  271. package/src/core/storage/state.ts +1 -1
  272. package/src/core/variables/__tests__/state.test.ts +6 -6
  273. package/src/core/variables/types.ts +2 -2
  274. package/src/core/wasm/__tests__/state.test.ts +8 -8
  275. package/src/core/websocket/useMarimoKernelConnection.tsx +12 -15
  276. package/src/css/md-tooltip.css +4 -39
  277. package/src/css/md.css +7 -0
  278. package/src/plugins/core/RenderHTML.tsx +17 -0
  279. package/src/plugins/core/__test__/RenderHTML.test.ts +45 -0
  280. package/src/plugins/core/sanitize-html.ts +25 -18
  281. package/src/plugins/impl/DataTablePlugin.tsx +23 -2
  282. package/src/plugins/impl/SliderPlugin.tsx +1 -3
  283. package/src/plugins/impl/__tests__/SliderPlugin.test.tsx +120 -0
  284. package/src/plugins/impl/anywidget/model.ts +1 -2
  285. package/src/stories/cell.stories.tsx +8 -8
  286. package/src/stories/layout/vertical/one-column.stories.tsx +9 -8
  287. package/src/stories/log-viewer.stories.tsx +8 -8
  288. package/src/stories/variables.stories.tsx +2 -2
  289. package/src/utils/__tests__/download.test.tsx +21 -20
  290. package/src/utils/copy.ts +18 -5
  291. package/src/utils/download.ts +4 -3
  292. package/src/utils/html-to-image.ts +6 -0
  293. package/src/utils/json/base64.ts +3 -3
  294. package/src/utils/traceback.ts +5 -3
  295. package/dist/assets/JsonOutput-DKXKGKvX.js +0 -46
  296. package/dist/assets/RenderHTML-DJ8khuob.js +0 -1
  297. package/dist/assets/ai-model-dropdown-DPTa_EpU.js +0 -5
  298. package/dist/assets/cell-editor-DX7IcqNr.js +0 -23
  299. package/dist/assets/channel-CkT8Qdo2.js +0 -1
  300. package/dist/assets/classDiagram-2ON5EDUG-BhMT_rTz.js +0 -1
  301. package/dist/assets/classDiagram-v2-WZHVMYZB-D-F4WEyb.js +0 -1
  302. package/dist/assets/copy-YwM0Pd7v.js +0 -1
  303. package/dist/assets/dist-BTqMkf4j.js +0 -1
  304. package/dist/assets/dist-DHw9sXeN.js +0 -1
  305. package/dist/assets/dist-Du0qZeXz.js +0 -1
  306. package/dist/assets/dist-a0FfbvMD.js +0 -1
  307. package/dist/assets/dist-cfkfP0ni.js +0 -1
  308. package/dist/assets/dist-pzQ9JG-p.js +0 -1
  309. package/dist/assets/file-explorer-panel-CB8vF5ob.js +0 -26
  310. package/dist/assets/home-page-itW0tRmv.js +0 -4
  311. package/dist/assets/html-to-image-BnSc-Wa0.js +0 -2
  312. package/dist/assets/index-0n92c_W7.js +0 -38
  313. package/dist/assets/mermaid-4DMBBIKO-PoHnhmy8.js +0 -1
  314. package/dist/assets/react-vega-Da-Ps9UW.js +0 -1
  315. package/dist/assets/stateDiagram-v2-4FDKWEC3-CEqeIlM0.js +0 -1
  316. package/dist/assets/stex-BBWVYm-R.js +0 -1
  317. package/dist/assets/tracing-DUVd0jtl.js +0 -1
  318. package/dist/assets/tracing-panel-CuTxPn_x.js +0 -2
  319. /package/dist/assets/{Combination-Cs9nbinQ.js → Combination-CSPK4t6z.js} +0 -0
  320. /package/dist/assets/{Deferred-BMfCOLaw.js → Deferred-CfyqLOPG.js} +0 -0
  321. /package/dist/assets/{SSRProvider-DC7ElCZZ.js → SSRProvider-CwqN9FWV.js} +0 -0
  322. /package/dist/assets/{badge-hTpPIsMT.js → badge-DImLVznf.js} +0 -0
  323. /package/dist/assets/{blob-CObhN-9g.js → blob-DgooIGjS.js} +0 -0
  324. /package/dist/assets/{bot-message-square-CK6eoGWy.js → bot-message-square-Dw41U6lL.js} +0 -0
  325. /package/dist/assets/{chart-no-axes-column-DV8gdCvH.js → chart-no-axes-column-a9XtWmzk.js} +0 -0
  326. /package/dist/assets/{check-BE0hEwVo.js → check-DZA_bRpw.js} +0 -0
  327. /package/dist/assets/{chevron-right-D0GQBpTb.js → chevron-right-CvVxySQk.js} +0 -0
  328. /package/dist/assets/{circle-check-gLIOLu8x.js → circle-check-CbaVeozR.js} +0 -0
  329. /package/dist/assets/{circle-play-DYGULlKZ.js → circle-play-DYn5nR6N.js} +0 -0
  330. /package/dist/assets/{circle-plus-CGG-gArM.js → circle-plus-nCze0-py.js} +0 -0
  331. /package/dist/assets/{clipboard-paste-DoYSN8Sv.js → clipboard-paste-EHXeKq9D.js} +0 -0
  332. /package/dist/assets/{code-xml-DwHPF_nL.js → code-xml-BlrJCgNZ.js} +0 -0
  333. /package/dist/assets/{copy-CkudG0Ej.js → copy-D6N1-xc1.js} +0 -0
  334. /package/dist/assets/{database-zap-DTWCDKdn.js → database-zap-BIGMFOfP.js} +0 -0
  335. /package/dist/assets/{defaultLocale-DK1MWd7f.js → defaultLocale-CGfP-Ye3.js} +0 -0
  336. /package/dist/assets/{defaultLocale-OkOxlkkM.js → defaultLocale-CuYNS33t.js} +0 -0
  337. /package/dist/assets/{dist-8UD0A5sU.js → dist-BF9S272t.js} +0 -0
  338. /package/dist/assets/{dist-apDpadc4.js → dist-Bk1itfBD.js} +0 -0
  339. /package/dist/assets/{dist-CQqv2gQL.js → dist-Dm11d0_A.js} +0 -0
  340. /package/dist/assets/{download-DBW9RXtT.js → download-nLboiTtW.js} +0 -0
  341. /package/dist/assets/{ellipsis-0_zJdF6H.js → ellipsis-d7eaKIFn.js} +0 -0
  342. /package/dist/assets/{ellipsis-vertical-CAB7tdza.js → ellipsis-vertical-DBQ5kWTo.js} +0 -0
  343. /package/dist/assets/{emotion-is-prop-valid.esm-D1keIaYa.js → emotion-is-prop-valid.esm-D7FeWASw.js} +0 -0
  344. /package/dist/assets/{errors-Bfogio62.js → errors-0IrrdfSG.js} +0 -0
  345. /package/dist/assets/{extends-DRbCSry7.js → extends-aq1t6BkR.js} +0 -0
  346. /package/dist/assets/{eye-off-vwi9L975.js → eye-off-CF3GmvXV.js} +0 -0
  347. /package/dist/assets/{file-DzHkbIdO.js → file-C-yMeaec.js} +0 -0
  348. /package/dist/assets/{file-headphone-B5q2Ow55.js → file-headphone-CPAP8asn.js} +0 -0
  349. /package/dist/assets/{file-plus-corner-lLQw9OnR.js → file-plus-corner-ks__N1mr.js} +0 -0
  350. /package/dist/assets/{github-BVtI-3F1.js → github-CRD4USKm.js} +0 -0
  351. /package/dist/assets/{image-DXfkah9d.js → image-CfyJzBP9.js} +0 -0
  352. /package/dist/assets/{link-Cf10mh3t.js → link-_dbp0XNB.js} +0 -0
  353. /package/dist/assets/{maps-OKerBHH8.js → maps-DQsjfyTy.js} +0 -0
  354. /package/dist/assets/{numbers-CYnquDho.js → numbers-Cno6K0UF.js} +0 -0
  355. /package/dist/assets/{objectWithoutPropertiesLoose-DP4vAkvg.js → objectWithoutPropertiesLoose-Dxmp_Bd_.js} +0 -0
  356. /package/dist/assets/{ordinal-BjO5SoTk.js → ordinal-CMAUv8ku.js} +0 -0
  357. /package/dist/assets/{paths-D2lG83Oh.js → paths-BVwhPRFT.js} +0 -0
  358. /package/dist/assets/{play-DKSqmedg.js → play-Bu_0ogGD.js} +0 -0
  359. /package/dist/assets/{plus-dVmh0yTy.js → plus-DJ99CUbx.js} +0 -0
  360. /package/dist/assets/{preload-helper-BW0IMuFq.js → preload-helper-y72bE5iF.js} +0 -0
  361. /package/dist/assets/{prop-types-RrUi-pOT.js → prop-types-DRf51_gT.js} +0 -0
  362. /package/dist/assets/{purify.es-BBn8CPhf.js → purify.es-Cf8RQecB.js} +0 -0
  363. /package/dist/assets/{range-DNqFcYmr.js → range-ClqUI25v.js} +0 -0
  364. /package/dist/assets/{refresh-ccw-DLpfIr8v.js → refresh-ccw-DQ6SJ8UC.js} +0 -0
  365. /package/dist/assets/{refresh-cw-CHAHPgkx.js → refresh-cw-Dg9tCj4k.js} +0 -0
  366. /package/dist/assets/{rotate-ccw-hLlF_82X.js → rotate-ccw-BCkZViUZ.js} +0 -0
  367. /package/dist/assets/{save-8fSvKYJT.js → save-CUdcv5qm.js} +0 -0
  368. /package/dist/assets/{session-BrEm7qNv.js → session-CByuQ-M-.js} +0 -0
  369. /package/dist/assets/{settings-CzQUw9rV.js → settings-B7nhfCat.js} +0 -0
  370. /package/dist/assets/{spinner-C5JoisA7.js → spinner-pCogyRyo.js} +0 -0
  371. /package/dist/assets/{square-CxAsQQ77.js → square-KVNDGpgy.js} +0 -0
  372. /package/dist/assets/{square-function-B006EYFX.js → square-function-BMNCw7Qb.js} +0 -0
  373. /package/dist/assets/{stex-0ac7Aukl.js → stex-C6JeW1YI.js} +0 -0
  374. /package/dist/assets/{table-BCnp9gKC.js → table-Od8PbuV-.js} +0 -0
  375. /package/dist/assets/{toDate-BqKH-Jd9.js → toDate-Cfp9W_O9.js} +0 -0
  376. /package/dist/assets/{trash-2-CAoNMkjq.js → trash-2-Bc_J7TQO.js} +0 -0
  377. /package/dist/assets/{trash-BZMAQneW.js → trash-Cxd189Vw.js} +0 -0
  378. /package/dist/assets/{triangle-alert-qZo1ox6x.js → triangle-alert-CzLrbLGN.js} +0 -0
  379. /package/dist/assets/{types-C1RN112u.js → types-CLOMZuqU.js} +0 -0
  380. /package/dist/assets/{use-toast-Hc8CXlvz.js → use-toast-BtZldTi5.js} +0 -0
  381. /package/dist/assets/{useDebounce-B0dx2Gp0.js → useDebounce-DwTO_rGp.js} +0 -0
  382. /package/dist/assets/{useTheme-BYXBU1of.js → useTheme-KDW4sktg.js} +0 -0
  383. /package/dist/assets/{uuid-ClFZlR7U.js → uuid-BukULOeS.js} +0 -0
  384. /package/dist/assets/{workflow-BmeqNuSH.js → workflow-BqHyyStM.js} +0 -0
  385. /package/dist/assets/{x-BI1M8X_v.js → x-CdLP7-v3.js} +0 -0
  386. /package/dist/assets/{youtube-DE-Ej6FR.js → youtube-CfU-SnDw.js} +0 -0
@@ -1,8 +1,10 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
+ import type { Table } from "@tanstack/react-table";
3
4
  import type { TableData } from "@/plugins/impl/DataTablePlugin";
4
5
  import { vegaLoadData } from "@/plugins/impl/vega/loader";
5
6
  import { jsonParseWithSpecialChar } from "@/utils/json/json-parser";
7
+ import { getMimeValues } from "./mime-cell";
6
8
  import { INDEX_COLUMN_NAME } from "./types";
7
9
 
8
10
  /**
@@ -32,6 +34,21 @@ export async function loadTableData<T = object>(
32
34
  return tableData;
33
35
  }
34
36
 
37
+ /**
38
+ * Load both table and raw table data. Raw table data is typically when
39
+ * there is formatting applied to the table data.
40
+ */
41
+ export async function loadTableAndRawData<T>(
42
+ tableData: TableData<T>,
43
+ rawTableData?: TableData<T> | null,
44
+ ): Promise<[T[], T[] | undefined]> {
45
+ if (rawTableData) {
46
+ return Promise.all([loadTableData(tableData), loadTableData(rawTableData)]);
47
+ }
48
+
49
+ return [await loadTableData(tableData), undefined];
50
+ }
51
+
35
52
  /**
36
53
  * Get the stable row ID for a row.
37
54
  *
@@ -87,3 +104,73 @@ export function stringifyUnknownValue(opts: {
87
104
  }
88
105
  return String(value);
89
106
  }
107
+
108
+ function stripHtml(html: string): string {
109
+ const div = document.createElement("div");
110
+ div.innerHTML = html;
111
+ const text = (div.textContent || div.innerText || "").trim();
112
+ return text || html;
113
+ }
114
+
115
+ const HTML_MIMETYPES = new Set(["text/html", "text/markdown"]);
116
+
117
+ function isRecord(value: unknown): value is Record<string, unknown> {
118
+ return value !== null && typeof value === "object" && !Array.isArray(value);
119
+ }
120
+
121
+ /**
122
+ * Get clipboard-ready text and optional HTML for a cell.
123
+ *
124
+ * @param rawValue - The raw (unformatted) value, or undefined if not available.
125
+ * @param displayedValue - The displayed value (may be a mime bundle).
126
+ */
127
+ export function getClipboardContent(
128
+ rawValue: unknown,
129
+ displayedValue: unknown,
130
+ ): { text: string; html?: string } {
131
+ const mimeValues =
132
+ typeof displayedValue === "object" && displayedValue !== null
133
+ ? getMimeValues(displayedValue)
134
+ : undefined;
135
+
136
+ let html: string | undefined;
137
+ if (mimeValues) {
138
+ // text/markdown from mo.md() contains rendered HTML
139
+ const htmlParts = mimeValues
140
+ .filter((v) => HTML_MIMETYPES.has(v.mimetype))
141
+ .map((v) => v.data);
142
+ html = htmlParts.length > 0 ? htmlParts.join("") : undefined;
143
+ }
144
+
145
+ let text: string;
146
+ if (rawValue !== undefined && rawValue !== displayedValue) {
147
+ text = stringifyUnknownValue({ value: rawValue });
148
+ } else if (mimeValues) {
149
+ text = mimeValues
150
+ .map((v) => (HTML_MIMETYPES.has(v.mimetype) ? stripHtml(v.data) : v.data))
151
+ .join(", ");
152
+ } else {
153
+ text = stringifyUnknownValue({ value: displayedValue });
154
+ }
155
+
156
+ return { text, html };
157
+ }
158
+
159
+ /**
160
+ * Get the raw (unformatted) value for a row/column from the table,
161
+ * or undefined if raw data is not available.
162
+ */
163
+ export function getRawValue<TData>(
164
+ table: Table<TData>,
165
+ rowIndex: number,
166
+ columnId: string,
167
+ ): unknown {
168
+ const rawData = table.options.meta?.rawData;
169
+ if (rawData) {
170
+ const rawRow = rawData[rowIndex];
171
+ if (isRecord(rawRow)) {
172
+ return rawRow[columnId];
173
+ }
174
+ }
175
+ return undefined;
176
+ }
@@ -5,9 +5,9 @@ import { beforeAll, describe, expect, it } from "vitest";
5
5
  import { SetupMocks } from "@/__mocks__/common";
6
6
  import { MockNotebook } from "@/__mocks__/notebook";
7
7
  import { MockRequestClient } from "@/__mocks__/requests";
8
+ import { cellId } from "@/__tests__/branded";
8
9
  import { TooltipProvider } from "@/components/ui/tooltip";
9
10
  import { notebookAtom } from "@/core/cells/cells";
10
- import type { CellId } from "@/core/cells/ids";
11
11
  import { createCellRuntimeState } from "@/core/cells/types";
12
12
  import type { UserConfig } from "@/core/config/config-schema";
13
13
  import type { OutputMessage } from "@/core/kernel/messages";
@@ -39,7 +39,7 @@ describe("Cell data attributes", () => {
39
39
  "present",
40
40
  ])("should render cell with data-cell-id and data-cell-name in %s mode", (mode) => {
41
41
  const { store, wrapper } = createTestWrapper();
42
- const cellId = "test" as CellId;
42
+ const cid = cellId("test");
43
43
  const cellName = "test_cell";
44
44
 
45
45
  const userConfig: UserConfig = {
@@ -83,7 +83,7 @@ describe("Cell data attributes", () => {
83
83
 
84
84
  const notebook = MockNotebook.notebookState({
85
85
  cellData: {
86
- [cellId]: {
86
+ [cid]: {
87
87
  code: "",
88
88
  name: cellName,
89
89
  edited: false,
@@ -97,7 +97,7 @@ describe("Cell data attributes", () => {
97
97
  },
98
98
  });
99
99
 
100
- notebook.cellRuntime[cellId] = createCellRuntimeState({
100
+ notebook.cellRuntime[cid] = createCellRuntimeState({
101
101
  status: "idle",
102
102
  output: null,
103
103
  consoleOutputs: [],
@@ -117,7 +117,7 @@ describe("Cell data attributes", () => {
117
117
  const { container } = render(
118
118
  <TooltipProvider>
119
119
  <Cell
120
- cellId={cellId}
120
+ cellId={cid}
121
121
  mode={mode as AppMode}
122
122
  canDelete={true}
123
123
  userConfig={userConfig}
@@ -131,7 +131,7 @@ describe("Cell data attributes", () => {
131
131
  { wrapper },
132
132
  );
133
133
 
134
- const cellElement = container.querySelector(`[data-cell-id="${cellId}"]`);
134
+ const cellElement = container.querySelector(`[data-cell-id="${cid}"]`);
135
135
  expect(cellElement).toBeTruthy();
136
136
  expect(cellElement?.getAttribute("data-cell-name")).toBe(cellName);
137
137
  });
@@ -139,7 +139,7 @@ describe("Cell data attributes", () => {
139
139
 
140
140
  describe("Output data attributes", () => {
141
141
  it("should render output with data-cell-role", () => {
142
- const cellId = "test" as CellId;
142
+ const cid = cellId("test");
143
143
  const output: OutputMessage = {
144
144
  channel: "output",
145
145
  mimetype: "text/plain",
@@ -151,7 +151,7 @@ describe("Output data attributes", () => {
151
151
  <TooltipProvider>
152
152
  <OutputArea
153
153
  output={output}
154
- cellId={cellId}
154
+ cellId={cid}
155
155
  stale={false}
156
156
  loading={false}
157
157
  allowExpand={true}
@@ -1,5 +1,6 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
  import { beforeEach, describe, expect, it, type Mock, vi } from "vitest";
3
+ import { variableName } from "@/__tests__/branded";
3
4
  import { getCodes } from "@/core/codemirror/copilot/getCodes";
4
5
  import { dataSourceConnectionsAtom } from "@/core/datasets/data-source-connections";
5
6
  import { DUCKDB_ENGINE } from "@/core/datasets/engines";
@@ -7,7 +8,6 @@ import { datasetsAtom } from "@/core/datasets/state";
7
8
  import type { DatasetsState } from "@/core/datasets/types";
8
9
  import { store } from "@/core/state/jotai";
9
10
  import { variablesAtom } from "@/core/variables/state";
10
- import type { Variable, VariableName } from "@/core/variables/types";
11
11
  import { codeToCells, getAICompletionBody } from "../completion-utils";
12
12
 
13
13
  // Mock getCodes function
@@ -205,16 +205,16 @@ describe("getAICompletionBody", () => {
205
205
 
206
206
  it("should return the correct completion body with mentioned variables", () => {
207
207
  // Set up test data in the Jotai store
208
- const testVariables: Record<VariableName, Variable> = {
209
- ["var1" as VariableName]: {
210
- name: "var1" as VariableName,
208
+ const testVariables = {
209
+ [variableName("var1")]: {
210
+ name: variableName("var1"),
211
211
  value: "string value",
212
212
  dataType: "string",
213
213
  declaredBy: [],
214
214
  usedBy: [],
215
215
  },
216
- ["var2" as VariableName]: {
217
- name: "var2" as VariableName,
216
+ [variableName("var2")]: {
217
+ name: variableName("var2"),
218
218
  value: "42",
219
219
  dataType: "number",
220
220
  declaredBy: [],
@@ -253,9 +253,9 @@ describe("getAICompletionBody", () => {
253
253
  ];
254
254
  store.set(datasetsAtom, { tables: testDatasets } as DatasetsState);
255
255
 
256
- const testVariables: Record<VariableName, Variable> = {
257
- ["var1" as VariableName]: {
258
- name: "var1" as VariableName,
256
+ const testVariables = {
257
+ [variableName("var1")]: {
258
+ name: variableName("var1"),
259
259
  value: "string value",
260
260
  dataType: "string",
261
261
  declaredBy: [],
@@ -285,9 +285,9 @@ describe("getAICompletionBody", () => {
285
285
 
286
286
  it("should handle non-existent variables", () => {
287
287
  // Set up test data in the Jotai store
288
- const testVariables: Record<VariableName, Variable> = {
289
- ["existingVar" as VariableName]: {
290
- name: "existingVar" as VariableName,
288
+ const testVariables = {
289
+ [variableName("existingVar")]: {
290
+ name: variableName("existingVar"),
291
291
  value: "string value",
292
292
  dataType: "string",
293
293
  declaredBy: [],
@@ -322,9 +322,9 @@ describe("getAICompletionBody", () => {
322
322
  ];
323
323
  store.set(datasetsAtom, { tables: testDatasets } as DatasetsState);
324
324
 
325
- const testVariables: Record<VariableName, Variable> = {
326
- ["conflict" as VariableName]: {
327
- name: "conflict" as VariableName,
325
+ const testVariables = {
326
+ [variableName("conflict")]: {
327
+ name: variableName("conflict"),
328
328
  value: "string value",
329
329
  dataType: "string",
330
330
  declaredBy: [],
@@ -4,8 +4,8 @@
4
4
  import { act, renderHook } from "@testing-library/react";
5
5
  import { beforeEach, describe, expect, it, vi } from "vitest";
6
6
  import { asMock, MockModules, Mocks, SetupMocks } from "@/__mocks__/common";
7
+ import { cellId } from "@/__tests__/branded";
7
8
  import type { CellActions, NotebookState } from "@/core/cells/cells";
8
- import type { CellId } from "@/core/cells/ids";
9
9
  import { useCellClipboard } from "../clipboard";
10
10
 
11
11
  // Mock dependencies
@@ -179,7 +179,7 @@ describe("useCellClipboard", () => {
179
179
  });
180
180
 
181
181
  it("should filter out non-existent cells", async () => {
182
- const nonExistentCellId = "non-existent" as CellId;
182
+ const nonExistentCellId = cellId("non-existent");
183
183
 
184
184
  const { result } = renderHook(() => useCellClipboard());
185
185
 
@@ -1,6 +1,7 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
+
2
3
  import { beforeEach, describe, expect, it } from "vitest";
3
- import type { CellId } from "@/core/cells/ids";
4
+ import { cellId } from "@/__tests__/branded";
4
5
  import { MultiColumn } from "@/utils/id-tree";
5
6
  import type { CellSelectionState } from "../selection";
6
7
  import { exportedForTesting } from "../selection";
@@ -8,11 +9,11 @@ import { exportedForTesting } from "../selection";
8
9
  const { initialState, reducer, createActions } = exportedForTesting;
9
10
 
10
11
  const CellIds = {
11
- a: "a" as CellId,
12
- b: "b" as CellId,
13
- c: "c" as CellId,
14
- d: "d" as CellId,
15
- e: "e" as CellId,
12
+ a: cellId("a"),
13
+ b: cellId("b"),
14
+ c: cellId("c"),
15
+ d: cellId("d"),
16
+ e: cellId("e"),
16
17
  };
17
18
 
18
19
  describe("cell selection reducer", () => {
@@ -1,6 +1,7 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
3
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
4
+ import { cellId } from "@/__tests__/branded";
4
5
  import { type CellId, HTMLCellId } from "@/core/cells/ids";
5
6
 
6
7
  const mockScrollCellIntoView = vi.fn();
@@ -14,12 +15,12 @@ vi.mock("../focus-utils", () => ({
14
15
  type TemporarilyShownCodeState = Set<CellId>;
15
16
 
16
17
  describe("temporarilyShownCodeActions", () => {
17
- const cellId = "cell-1" as CellId;
18
+ const cid = cellId("cell-1");
18
19
  let cellElement: HTMLElement;
19
20
 
20
21
  beforeEach(() => {
21
22
  cellElement = document.createElement("div");
22
- cellElement.id = HTMLCellId.create(cellId);
23
+ cellElement.id = HTMLCellId.create(cid);
23
24
  document.body.append(cellElement);
24
25
  cellElement.focus();
25
26
 
@@ -37,17 +38,17 @@ describe("temporarilyShownCodeActions", () => {
37
38
  });
38
39
 
39
40
  it("should scroll cell into view when removing cell causes layout shift", () => {
40
- const state = new Set<CellId>([cellId]);
41
- removeCell(state, cellId);
41
+ const state = new Set<CellId>([cid]);
42
+ removeCell(state, cid);
42
43
 
43
- expect(mockScrollCellIntoView).toHaveBeenCalledWith(cellId);
44
+ expect(mockScrollCellIntoView).toHaveBeenCalledWith(cid);
44
45
  });
45
46
 
46
47
  it("should not scroll when focused cell is not found", () => {
47
48
  vi.spyOn(HTMLCellId, "findElementThroughShadowDOMs").mockReturnValue(null);
48
49
 
49
- const state = new Set<CellId>([cellId]);
50
- removeCell(state, cellId);
50
+ const state = new Set<CellId>([cid]);
51
+ removeCell(state, cid);
51
52
 
52
53
  expect(mockScrollCellIntoView).not.toHaveBeenCalled();
53
54
  });
@@ -316,7 +316,7 @@ export const MarimoErrorOutput = ({
316
316
  <ul className="list-disc">
317
317
  {error.cells.map((cid, cidIdx) => (
318
318
  <li className={liStyle} key={`cell-${cidIdx}`}>
319
- <CellLinkError cellId={cid as CellId} />
319
+ <CellLinkError cellId={cid} />
320
320
  </li>
321
321
  ))}
322
322
  </ul>
@@ -491,7 +491,7 @@ export const MarimoErrorOutput = ({
491
491
  ) : (
492
492
  <div>
493
493
  {processTextForUrls(error.msg, `exception-${idx}`)}
494
- <CellLinkError cellId={error.raising_cell as CellId} />
494
+ <CellLinkError cellId={error.raising_cell} />
495
495
  </div>
496
496
  )}
497
497
  </li>
@@ -518,7 +518,7 @@ export const MarimoErrorOutput = ({
518
518
  ) : (
519
519
  <div>
520
520
  {error.msg}
521
- <CellLinkError cellId={error.blamed_cell as CellId} />
521
+ <CellLinkError cellId={error.blamed_cell} />
522
522
  </div>
523
523
  )}
524
524
  </li>
@@ -554,13 +554,13 @@ export const MarimoErrorOutput = ({
554
554
  {error.msg}
555
555
  {error.blamed_cell == null ? (
556
556
  <span>
557
- (<CellLinkError cellId={error.raising_cell as CellId} />)
557
+ (<CellLinkError cellId={error.raising_cell} />)
558
558
  </span>
559
559
  ) : (
560
560
  <span>
561
- (<CellLinkError cellId={error.raising_cell as CellId} />
561
+ (<CellLinkError cellId={error.raising_cell} />
562
562
  &nbsp;blames&nbsp;
563
- <CellLinkError cellId={error.blamed_cell as CellId} />)
563
+ <CellLinkError cellId={error.blamed_cell} />)
564
564
  </span>
565
565
  )}
566
566
  </div>
@@ -578,7 +578,7 @@ export const MarimoErrorOutput = ({
578
578
  {ancestorStoppedErrors.map((error, idx) => (
579
579
  <div key={`ancestor-stopped-${idx}`}>
580
580
  {error.msg}
581
- <CellLinkError cellId={error.raising_cell as CellId} />
581
+ <CellLinkError cellId={error.raising_cell} />
582
582
  </div>
583
583
  ))}
584
584
  {cellId && (
@@ -3,8 +3,8 @@
3
3
  import { render } from "@testing-library/react";
4
4
  import { beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
5
5
  import { Tracebacks } from "@/__mocks__/tracebacks";
6
+ import { cellId } from "@/__tests__/branded";
6
7
  import { TooltipProvider } from "@/components/ui/tooltip";
7
- import type { CellId } from "@/core/cells/ids";
8
8
  import { initialModeAtom } from "@/core/mode";
9
9
  import { store } from "@/core/state/jotai";
10
10
  import { renderHTML } from "@/plugins/core/RenderHTML";
@@ -14,7 +14,7 @@ import {
14
14
  replaceTracebackPrefix,
15
15
  } from "../MarimoTracebackOutput";
16
16
 
17
- const cellId = "1" as CellId;
17
+ const cid = cellId("1");
18
18
 
19
19
  describe("traceback component", () => {
20
20
  beforeEach(() => {
@@ -25,7 +25,7 @@ describe("traceback component", () => {
25
25
  test("extracts cell-link", () => {
26
26
  const traceback = (
27
27
  <TooltipProvider>
28
- <MarimoTracebackOutput traceback={Tracebacks.raw} cellId={cellId} />
28
+ <MarimoTracebackOutput traceback={Tracebacks.raw} cellId={cid} />
29
29
  </TooltipProvider>
30
30
  );
31
31
  const { unmount, getAllByRole } = render(traceback);
@@ -45,7 +45,7 @@ describe("traceback component", () => {
45
45
  test("renames File to Cell for relevant lines", () => {
46
46
  const traceback = (
47
47
  <TooltipProvider>
48
- <MarimoTracebackOutput traceback={Tracebacks.raw} cellId={cellId} />
48
+ <MarimoTracebackOutput traceback={Tracebacks.raw} cellId={cid} />
49
49
  </TooltipProvider>
50
50
  );
51
51
  const { unmount, container } = render(traceback);
@@ -3,8 +3,8 @@
3
3
  import { act, fireEvent, render, screen } from "@testing-library/react";
4
4
  import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
5
5
  import { SetupMocks } from "@/__mocks__/common";
6
+ import { cellId } from "@/__tests__/branded";
6
7
  import { TooltipProvider } from "@/components/ui/tooltip";
7
- import type { CellId } from "@/core/cells/ids";
8
8
  import type { WithResponse } from "@/core/cells/types";
9
9
  import type { OutputMessage } from "@/core/kernel/messages";
10
10
  import { CONSOLE_CLEAR_DEBOUNCE_MS, ConsoleOutput } from "../ConsoleOutput";
@@ -24,7 +24,7 @@ describe("ConsoleOutput integration", () => {
24
24
  });
25
25
 
26
26
  const defaultProps = {
27
- cellId: "cell-1" as CellId,
27
+ cellId: cellId("cell-1"),
28
28
  cellName: "test_cell",
29
29
  consoleOutputs: [] as WithResponse<OutputMessage>[],
30
30
  stale: false,
@@ -55,7 +55,7 @@ describe("ConsoleOutput integration", () => {
55
55
 
56
56
  describe("ConsoleOutput pdb history", () => {
57
57
  const defaultProps = {
58
- cellId: "cell-1" as CellId,
58
+ cellId: cellId("cell-1"),
59
59
  cellName: "test_cell",
60
60
  consoleOutputs: [] as WithResponse<OutputMessage>[],
61
61
  stale: false,
@@ -215,7 +215,7 @@ describe("ConsoleOutput debounced clearing", () => {
215
215
  });
216
216
 
217
217
  const defaultProps = {
218
- cellId: "cell-1" as CellId,
218
+ cellId: cellId("cell-1"),
219
219
  cellName: "test_cell",
220
220
  consoleOutputs: [] as WithResponse<OutputMessage>[],
221
221
  stale: false,
@@ -91,7 +91,7 @@ function focusCellByName(cellName: string) {
91
91
 
92
92
  // Look for an editor to focus
93
93
  const { cellHandles } = getNotebook();
94
- const cellId = cellElement.dataset.cellId as CellId | undefined;
94
+ const cellId = extractCellIdFromDomElement(cellElement);
95
95
 
96
96
  if (!cellId) {
97
97
  Logger.error(`Missing cellId for cell with name ${cellName}`);
@@ -111,3 +111,10 @@ function focusCellByName(cellName: string) {
111
111
  focusFirstEditor();
112
112
  }
113
113
  }
114
+
115
+ function extractCellIdFromDomElement(
116
+ cellElement: HTMLElement,
117
+ ): CellId | undefined {
118
+ const cellIdStr = cellElement.dataset.cellId ?? undefined;
119
+ return cellIdStr as CellId | undefined;
120
+ }
@@ -4,27 +4,32 @@ import { FileIcon, LoaderCircle, RefreshCwIcon } from "lucide-react";
4
4
  import type React from "react";
5
5
  import { useCallback } from "react";
6
6
  import { useLocale } from "react-aria";
7
+ import { useAddCodeToNewCell } from "@/components/editor/cell/useAddCell";
7
8
  import { FilePreviewHeader } from "@/components/editor/file-tree/file-header";
8
9
  import { renderFileIcon } from "@/components/editor/file-tree/file-icons";
9
10
  import {
10
11
  FileContentRenderer,
11
12
  isMediaMime,
12
13
  } from "@/components/editor/file-tree/renderers";
14
+ import { Tooltip } from "@/components/ui/tooltip";
13
15
  import { toast } from "@/components/ui/use-toast";
14
16
  import { DownloadStorage } from "@/core/storage/request-registry";
15
- import type { StorageEntry } from "@/core/storage/types";
17
+ import type { StorageEntry, StorageNamespace } from "@/core/storage/types";
16
18
  import { useAsyncData } from "@/hooks/useAsyncData";
17
19
  import { downloadByURL } from "@/utils/download";
18
20
  import { formatBytes } from "@/utils/formatting";
19
21
  import { Logger } from "@/utils/Logger";
20
22
  import { CopyClipboardIcon } from "../icons/copy-icon";
21
23
  import { Button } from "../ui/button";
24
+ import { STORAGE_SNIPPETS } from "./storage-snippets";
22
25
 
23
26
  const MAX_MEDIA_PREVIEW_SIZE = 100 * 1024 * 1024; // 100 MB
24
27
 
25
28
  interface Props {
26
29
  entry: StorageEntry;
27
30
  namespace: string;
31
+ protocol: string;
32
+ backendType: StorageNamespace["backendType"];
28
33
  onBack: () => void;
29
34
  }
30
35
 
@@ -41,9 +46,12 @@ type PreviewData =
41
46
  export const StorageFileViewer: React.FC<Props> = ({
42
47
  entry,
43
48
  namespace,
49
+ protocol,
50
+ backendType,
44
51
  onBack,
45
52
  }) => {
46
53
  const { locale } = useLocale();
54
+ const addCodeToNewCell = useAddCodeToNewCell();
47
55
  const name = displayName(entry.path);
48
56
  const mime = entry.mimeType || "text/plain";
49
57
  const isMedia = isMediaMime(mime);
@@ -111,12 +119,38 @@ export const StorageFileViewer: React.FC<Props> = ({
111
119
  }
112
120
  }, [namespace, entry.path, name]);
113
121
 
122
+ const snippetActions = STORAGE_SNIPPETS.map((snippet) => {
123
+ const code = snippet.getCode({
124
+ variableName: namespace,
125
+ protocol,
126
+ entry,
127
+ backendType,
128
+ });
129
+ if (code === null) {
130
+ return null;
131
+ }
132
+ const Icon = snippet.icon;
133
+ return (
134
+ <Tooltip key={snippet.id} content={snippet.label}>
135
+ <Button
136
+ variant="text"
137
+ size="xs"
138
+ onClick={() => addCodeToNewCell(code)}
139
+ aria-label={snippet.label}
140
+ >
141
+ <Icon className="h-3.5 w-3.5" />
142
+ </Button>
143
+ </Tooltip>
144
+ );
145
+ });
146
+
114
147
  const header = (
115
148
  <FilePreviewHeader
116
149
  filename={name}
117
150
  filenameIcon={renderFileIcon(name)}
118
151
  onBack={onBack}
119
152
  onDownload={handleDownload}
153
+ actions={snippetActions}
120
154
  />
121
155
  );
122
156
 
@@ -50,7 +50,6 @@ import type {
50
50
  StoragePathKey,
51
51
  } from "@/core/storage/types";
52
52
  import { storagePathKey } from "@/core/storage/types";
53
- import type { VariableName } from "@/core/variables/types";
54
53
  import { cn } from "@/utils/cn";
55
54
  import { copyToClipboard } from "@/utils/copy";
56
55
  import { downloadByURL } from "@/utils/download";
@@ -65,6 +64,8 @@ import { STORAGE_SNIPPETS } from "./storage-snippets";
65
64
  interface OpenFileInfo {
66
65
  entry: StorageEntry;
67
66
  namespace: string;
67
+ protocol: string;
68
+ backendType: StorageNamespace["backendType"];
68
69
  }
69
70
 
70
71
  // Pixels per depth level. Applied as paddingLeft on each full-width item
@@ -316,7 +317,7 @@ const StorageEntryRow: React.FC<{
316
317
  if (isDir) {
317
318
  setIsExpanded(!effectiveExpanded);
318
319
  } else {
319
- onOpenFile({ entry, namespace });
320
+ onOpenFile({ entry, namespace, protocol, backendType });
320
321
  }
321
322
  }}
322
323
  >
@@ -362,7 +363,9 @@ const StorageEntryRow: React.FC<{
362
363
  >
363
364
  {!isDir && (
364
365
  <DropdownMenuItem
365
- onSelect={() => onOpenFile({ entry, namespace })}
366
+ onSelect={() =>
367
+ onOpenFile({ entry, namespace, protocol, backendType })
368
+ }
366
369
  >
367
370
  <ViewIcon className={MENU_ITEM_ICON_CLASS} />
368
371
  View
@@ -474,7 +477,7 @@ const StorageNamespaceSection: React.FC<{
474
477
  <span>{namespace.displayName}</span>
475
478
  {namespace.name && (
476
479
  <span className="text-xs text-muted-foreground font-normal">
477
- (<EngineVariable variableName={namespace.name as VariableName} />)
480
+ (<EngineVariable variableName={namespace.name} />)
478
481
  </span>
479
482
  )}
480
483
  <RefreshIconButton
@@ -586,6 +589,8 @@ export const StorageInspector: React.FC = () => {
586
589
  <StorageFileViewer
587
590
  entry={openFile.entry}
588
591
  namespace={openFile.namespace}
592
+ protocol={openFile.protocol}
593
+ backendType={openFile.backendType}
589
594
  onBack={() => setOpenFile(null)}
590
595
  />
591
596
  )}
@@ -1,7 +1,7 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
 
3
3
  import type { LucideIcon } from "lucide-react";
4
- import { BookOpenIcon, LinkIcon } from "lucide-react";
4
+ import { BookPlusIcon, FileSymlink } from "lucide-react";
5
5
  import type { StorageEntry, StorageNamespace } from "@/core/storage/types";
6
6
 
7
7
  type BackendType = StorageNamespace["backendType"];
@@ -31,7 +31,7 @@ export const STORAGE_SNIPPETS: StorageSnippet[] = [
31
31
  {
32
32
  id: "read-file",
33
33
  label: "Insert read snippet",
34
- icon: BookOpenIcon,
34
+ icon: BookPlusIcon,
35
35
  getCode: (ctx) => {
36
36
  if (ctx.entry.kind === "directory") {
37
37
  return null;
@@ -46,7 +46,7 @@ export const STORAGE_SNIPPETS: StorageSnippet[] = [
46
46
  {
47
47
  id: "download-file",
48
48
  label: "Insert download snippet",
49
- icon: LinkIcon,
49
+ icon: FileSymlink,
50
50
  getCode: (ctx) => {
51
51
  if (ctx.entry.kind === "directory") {
52
52
  return null;
@@ -243,7 +243,9 @@ const TraceBlockBody: React.FC<{
243
243
  signalName: VEGA_HOVER_SIGNAL,
244
244
  handler: (_name: string, value: unknown) => {
245
245
  const signalValue = value as VegaHoverCellSignal;
246
- const hoveredCell = signalValue.cell?.[0] as CellId | undefined;
246
+ const hoveredCell = (signalValue.cell?.[0] ?? undefined) as
247
+ | CellId
248
+ | undefined;
247
249
  setHoveredCellId(hoveredCell ?? null);
248
250
  },
249
251
  },