@marimo-team/islands 0.23.9-dev1 → 0.23.9-dev11

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 (257) hide show
  1. package/dist/{ConnectedDataExplorerComponent-2lBNiUv6.js → ConnectedDataExplorerComponent-DFQ1yVhp.js} +20 -20
  2. package/dist/ErrorBoundary-rULOrC_p.js +175 -0
  3. package/dist/{ImageComparisonComponent-CNHIsPDj.js → ImageComparisonComponent-CHrI72em.js} +1 -1
  4. package/dist/{Plot-4wn-lMVn.js → Plot-CAYS29h9.js} +1 -1
  5. package/dist/{_baseUniq-CxZRxRRo.js → _baseUniq-B_2Hw7zG.js} +3 -3
  6. package/dist/{any-language-editor-VWs_7v27.js → any-language-editor-DfdpyDv_.js} +23 -23
  7. package/dist/architecture-7HQA4BMR-Kyc44TmC.js +6 -0
  8. package/dist/{architectureDiagram-VXUJARFQ-CXVJxFhH.js → architectureDiagram-VXUJARFQ-CT2SuxNw.js} +15 -15
  9. package/dist/{arrays-CldYf7p7.js → arrays-sEtDRoG4.js} +1 -1
  10. package/dist/{blockDiagram-VD42YOAC-DGDaxR8I.js → blockDiagram-VD42YOAC-Dy7hlFla.js} +7 -7
  11. package/dist/{button-Dj4BTre0.js → button-C5K9fIPF.js} +2 -2
  12. package/dist/{c4Diagram-YG6GDRKO-C2hc6ne8.js → c4Diagram-YG6GDRKO-BXlAmZ8Z.js} +4 -4
  13. package/dist/{capabilities-C9rrYCzf.js → capabilities-BceAxrAW.js} +2 -2
  14. package/dist/{channel-BBoIVUrJ.js → channel-D_PHgcig.js} +1 -1
  15. package/dist/{chat-ui-D3XBept8.js → chat-ui-xfKWgbtB.js} +29 -29
  16. package/dist/{check-BcUIXnUT.js → check-DTbrK0zt.js} +1 -1
  17. package/dist/{chunk-4F5CHEZ2-BZq7Kom7.js → chunk-4F5CHEZ2-D9nGEHV8.js} +1 -1
  18. package/dist/{chunk-5FQGJX7Z-BOg95xG5.js → chunk-5FQGJX7Z-BNjes6Yx.js} +5 -5
  19. package/dist/{chunk-ABZYJK2D-D0cLy8Bb.js → chunk-ABZYJK2D-Dz0-H2B5.js} +1 -1
  20. package/dist/{chunk-ATLVNIR6-BXsEjlHF.js → chunk-ATLVNIR6-o0Z5MZLd.js} +1 -1
  21. package/dist/{chunk-B2363JML-D9-XOau1.js → chunk-B2363JML-KEJpLGGP.js} +1 -1
  22. package/dist/{chunk-B4BG7PRW-Q1usn6T3.js → chunk-B4BG7PRW-BL98U9B4.js} +4 -4
  23. package/dist/{chunk-DI55MBZ5-D1qLYNrb.js → chunk-DI55MBZ5-Dwkn0LWm.js} +4 -4
  24. package/dist/{chunk-EXTU4WIE-BKNXdLmD.js → chunk-EXTU4WIE-9sNjmQrB.js} +1 -1
  25. package/dist/{chunk-FRFDVMJY-BSBUAX7r.js → chunk-FRFDVMJY-DzQqMWrl.js} +1 -1
  26. package/dist/{chunk-JA3XYJ7Z-D6c6cOBG.js → chunk-JA3XYJ7Z-C32Y7Epf.js} +2 -2
  27. package/dist/{chunk-JZLCHNYA-BvsPHJmL.js → chunk-JZLCHNYA-C6ftyVMN.js} +4 -4
  28. package/dist/{chunk-N4CR4FBY-8ycT-O9a.js → chunk-N4CR4FBY-DUhGZhZs.js} +5 -5
  29. package/dist/{chunk-PL6DKKU2-B0MTXvyc.js → chunk-PL6DKKU2-D7km-08O.js} +1 -1
  30. package/dist/{chunk-QN33PNHL-Bb-eUBW3.js → chunk-QN33PNHL-0K6SDYn3.js} +1 -1
  31. package/dist/{chunk-QXUST7PY-DV8yRwBd.js → chunk-QXUST7PY-DMhsRpYK.js} +5 -5
  32. package/dist/{chunk-S3R3BYOJ-mQeCz5CE.js → chunk-S3R3BYOJ-oAe3dEbO.js} +3 -3
  33. package/dist/{chunk-SJTYNZTY-CEG4F0pB.js → chunk-SJTYNZTY-BkJrPRFC.js} +1 -1
  34. package/dist/{chunk-TCCFYFTB-d3HOqL2I.js → chunk-TCCFYFTB-D58KeXnC.js} +6 -6
  35. package/dist/{chunk-TQ3KTPDO-DiCtqVSi.js → chunk-TQ3KTPDO-D_yA_wAb.js} +1 -1
  36. package/dist/{chunk-TZMSLE5B-BqW10dHe.js → chunk-TZMSLE5B-yBKS_DQU.js} +1 -1
  37. package/dist/{chunk-UMXZTB3W-97iS1iEl.js → chunk-UMXZTB3W-D7uwvNjd.js} +1 -1
  38. package/dist/{classDiagram-2ON5EDUG--Yh__LHb.js → classDiagram-2ON5EDUG-QjoAcuFE.js} +10 -10
  39. package/dist/{classDiagram-v2-WZHVMYZB-BC7X7Xtc.js → classDiagram-v2-WZHVMYZB-bUCv4gu2.js} +10 -10
  40. package/dist/{clone-BuIIsfA8.js → clone-Q4Fqwn6q.js} +1 -1
  41. package/dist/{code-block-37QAKDTI-BsGy1AOJ.js → code-block-37QAKDTI-m92Yc8pv.js} +2 -2
  42. package/dist/{code-visibility-BEBL2NuO.js → code-visibility-Dv-4kU3M.js} +8425 -8595
  43. package/dist/{constants-D0gkYoE2.js → constants-T20xxyNf.js} +2 -2
  44. package/dist/{copy-DLf4aN7I.js → copy-BuQpJEzp.js} +2 -2
  45. package/dist/{dagre-6UL2VRFP-DRBWoQUw.js → dagre-6UL2VRFP-J0JKgwOt.js} +11 -11
  46. package/dist/{dagre-VYEPqXIV.js → dagre-By_QsQgc.js} +11 -11
  47. package/dist/{data-grid-overlay-editor-efe5ZagF.js → data-grid-overlay-editor-mfEJ5475.js} +2 -2
  48. package/dist/{diagram-PSM6KHXK-H66ATWP2.js → diagram-PSM6KHXK-DYgJuNk9.js} +18 -18
  49. package/dist/{diagram-QEK2KX5R-DItl5Wns.js → diagram-QEK2KX5R-CKdBR2sb.js} +14 -14
  50. package/dist/{diagram-S2PKOQOG-CtuW_ZuL.js → diagram-S2PKOQOG-Dpi7mo5W.js} +14 -14
  51. package/dist/dist-0Fif7jnk.js +5 -0
  52. package/dist/{dist-Dh3wkoyH.js → dist-4j4c7bjm.js} +2 -2
  53. package/dist/{dist-CDFZi-QD.js → dist-B3P2fFpz.js} +1 -1
  54. package/dist/{dist-BNyrZfqT.js → dist-B3pZ0Ab6.js} +2 -2
  55. package/dist/dist-B5h_9sHB.js +6 -0
  56. package/dist/dist-B9M6R5ye.js +5 -0
  57. package/dist/dist-BCt3tnck.js +8 -0
  58. package/dist/{dist-BrBucRXs.js → dist-BTfv03uy.js} +2 -2
  59. package/dist/dist-BUIJwMwn.js +8 -0
  60. package/dist/{dist-CYEylvZA.js → dist-BbbIBDiQ.js} +1 -1
  61. package/dist/{dist-KnujRhFL.js → dist-BcuoonNH.js} +4 -4
  62. package/dist/{dist-DJ6zJQZ4.js → dist-Bde4a2kU.js} +2 -2
  63. package/dist/{dist-t_qL7eB8.js → dist-Bfwsv11D.js} +2 -2
  64. package/dist/{dist-CNtV21T_.js → dist-BhM8gdSO.js} +4 -4
  65. package/dist/{dist-nuW5EDYT.js → dist-BotSqB48.js} +2 -2
  66. package/dist/dist-BpquMd3k.js +5 -0
  67. package/dist/dist-BzJsqYfz.js +5 -0
  68. package/dist/{dist-D029TiHd.js → dist-Bz_sYWbr.js} +2 -2
  69. package/dist/{dist-D3ZI9nhS.js → dist-C1BYNeCR.js} +4 -4
  70. package/dist/{dist-Bc5pmZIw.js → dist-C5VC_yzu.js} +1 -1
  71. package/dist/dist-CA5ELXAf.js +6 -0
  72. package/dist/dist-CLBRs6Uv.js +5 -0
  73. package/dist/{dist-Dhk6FMb0.js → dist-CLJWPTX2.js} +3 -3
  74. package/dist/{dist-C34oIrQ9.js → dist-CLUtPrdy.js} +1 -1
  75. package/dist/dist-CStVCMbq.js +5 -0
  76. package/dist/{dist-B8RaFTRF.js → dist-CUCNs1ja.js} +2 -2
  77. package/dist/dist-CZRIEY3Y.js +8 -0
  78. package/dist/{dist-UcOPnRMa.js → dist-CcXxepx6.js} +3 -3
  79. package/dist/dist-CuUHbFD0.js +5 -0
  80. package/dist/{dist-B8BjrFUE.js → dist-Cy1WxgBD.js} +5 -5
  81. package/dist/{dist-WdPUFc56.js → dist-D4CewLk6.js} +1 -1
  82. package/dist/{dist-DMZNjfX4.js → dist-DRfcqpxJ.js} +2 -2
  83. package/dist/dist-DV7Iabxb.js +8 -0
  84. package/dist/{dist-usPCDYx8.js → dist-D_bzzWBm.js} +1 -1
  85. package/dist/{dist-BvCfQQQE.js → dist-DgnE8F-r.js} +1 -1
  86. package/dist/{dist-JEhxD_cn.js → dist-DhHh0jLg.js} +1 -1
  87. package/dist/{dist-DGAfI2rB.js → dist-DqAWR3CS.js} +2 -2
  88. package/dist/{dist--sWVZwjW.js → dist-Du8WkPuU.js} +1 -1
  89. package/dist/dist-DuEeHMvL.js +5 -0
  90. package/dist/{dist-BTyJtnNg.js → dist-DxvORzUR.js} +1 -1
  91. package/dist/{dist-B507mf_I.js → dist-RqXTaiir.js} +2 -2
  92. package/dist/{dist-Yrfc6L0I.js → dist-fQ0ViXGs.js} +3 -3
  93. package/dist/{dist-B4LJpMEg.js → dist-h2c8sZvT.js} +1 -1
  94. package/dist/{dist-C2ej4eOH.js → dist-luvabDEB.js} +2 -2
  95. package/dist/{dist-B52GXZbd.js → dist-p2qyWijU.js} +2 -2
  96. package/dist/{erDiagram-Q2GNP2WA--19X2kU5.js → erDiagram-Q2GNP2WA-BU-m41EQ.js} +10 -10
  97. package/dist/{error-banner-CVkfBUT3.js → error-banner-5bz0L9hS.js} +3 -3
  98. package/dist/{esm-CWp0KQeK.js → esm-BfhQmZjp.js} +4 -4
  99. package/dist/{esm-DjNnlmpf.js → esm-Duie8iU-.js} +23 -23
  100. package/dist/{extends-vAi97cpa.js → extends-BgdxCfYu.js} +6 -6
  101. package/dist/{flatten-CzBvFdvC.js → flatten-Bbw7g6-K.js} +1 -1
  102. package/dist/{flowDiagram-NV44I4VS-DQmWlo7f.js → flowDiagram-NV44I4VS-CRoXKjGq.js} +10 -10
  103. package/dist/{formats-Dsy9kkZu.js → formats-BHOojBDG.js} +4 -4
  104. package/dist/{ganttDiagram-JELNMOA3-BOGXJ8Lk.js → ganttDiagram-JELNMOA3-7mq5f9cO.js} +7 -7
  105. package/dist/{gitGraph-G5XIXVHT-DGlbae5m.js → gitGraph-G5XIXVHT-DiniR35k.js} +3 -3
  106. package/dist/{gitGraphDiagram-V2S2FVAM-DjzxfF0P.js → gitGraphDiagram-V2S2FVAM-Dfuokq6w.js} +13 -13
  107. package/dist/{glide-data-editor-DucgdjRo.js → glide-data-editor-CpzEdx8N.js} +557 -557
  108. package/dist/{graphlib-CVPKjKCS.js → graphlib-Ns7y5crs.js} +5 -5
  109. package/dist/{hasIn-COs6vImh.js → hasIn-Deg7jl_j.js} +3 -3
  110. package/dist/{html-to-image-CpggM7u1.js → html-to-image-DjEqYaQd.js} +109 -109
  111. package/dist/{info-VBDWY6EO-D2lvLLw5.js → info-VBDWY6EO-DVZvGhkQ.js} +3 -3
  112. package/dist/{infoDiagram-HS3SLOUP-ChNufFsP.js → infoDiagram-HS3SLOUP-CEnzWruK.js} +13 -13
  113. package/dist/{input-D4kjoQUB.js → input-DBDlwwuD.js} +70 -67
  114. package/dist/{isEmpty-Dd8mx_WL.js → isEmpty-CJJMn-QP.js} +1 -1
  115. package/dist/{isSymbol-BvIfMnn6.js → isSymbol-CoUCgMCM.js} +1 -1
  116. package/dist/{journeyDiagram-XKPGCS4Q-BO_O4Ij1.js → journeyDiagram-XKPGCS4Q-8XYSU1GI.js} +3 -3
  117. package/dist/{kanban-definition-3W4ZIXB7-CPpiiiWk.js → kanban-definition-3W4ZIXB7--9pT9z1R.js} +7 -7
  118. package/dist/{label-BLqV33b1.js → label-LWtdw5i8.js} +3 -3
  119. package/dist/{linear-2NnK4cxi.js → linear-B5-AFRiR.js} +2 -2
  120. package/dist/{loader-Dr8Qem8p.js → loader-BWLPpjKK.js} +2 -2
  121. package/dist/main.js +1681 -1555
  122. package/dist/{memoize-C9ltv0Cw.js → memoize-BOtf2yFf.js} +1 -1
  123. package/dist/{merge-CHn7Yx0N.js → merge-Be1CqGnU.js} +1 -1
  124. package/dist/mermaid-4DMBBIKO-DIdL224_.js +6 -0
  125. package/dist/{mermaid-DO-Daq7u.js → mermaid-D00onudG.js} +44 -44
  126. package/dist/{mermaid-parser.core-DreccfmS.js → mermaid-parser.core-C3XRsazI.js} +8 -8
  127. package/dist/{min-BNz2lZfk.js → min-Dtgc8txR.js} +4 -4
  128. package/dist/{mindmap-definition-VGOIOE7T-CC1_Vl0f.js → mindmap-definition-VGOIOE7T-B-4mnfFG.js} +9 -9
  129. package/dist/{now-Sgq5m3D-.js → now-Ch98bJO_.js} +2 -2
  130. package/dist/{number-overlay-editor-CpKi64Fy.js → number-overlay-editor-D-a0qCT8.js} +1 -1
  131. package/dist/{once-rJImu7SE.js → once-DPuqGUeo.js} +1 -1
  132. package/dist/{packet-DYOGHKS2-CmWtF3uO.js → packet-DYOGHKS2-34raHOiB.js} +3 -3
  133. package/dist/{pick-CRAXxDYn.js → pick-D1Qo8s2C.js} +4 -4
  134. package/dist/{pie-VRWISCQL-B6u8vus8.js → pie-VRWISCQL-BaLlzZa3.js} +3 -3
  135. package/dist/{pieDiagram-ADFJNKIX-Di34MOFQ.js → pieDiagram-ADFJNKIX-Cr3cNpZY.js} +15 -15
  136. package/dist/{precisionRound-CnHPY_5v.js → precisionRound-Tqb4mg-H.js} +1 -1
  137. package/dist/{process-output-X8TR20AK.js → process-output-Cz6wQSkL.js} +4 -4
  138. package/dist/{quadrantDiagram-AYHSOK5B-B9kVk1ny.js → quadrantDiagram-AYHSOK5B-BuNL8Q93.js} +4 -4
  139. package/dist/{radar-ZZBFDIW7-XAmXSa8s.js → radar-ZZBFDIW7-Ci7bfoZa.js} +3 -3
  140. package/dist/{react-vega-Dh6-UKKe.js → react-vega-B0sAlDTL.js} +9 -9
  141. package/dist/react-vega-B6ncY2Tp.js +9 -0
  142. package/dist/{requirementDiagram-UZGBJVZJ-BxGfGYEx.js → requirementDiagram-UZGBJVZJ-BG2lLUN1.js} +9 -9
  143. package/dist/{reveal-component-CEHb1Q34.js → reveal-component-BsyenC3H.js} +31 -31
  144. package/dist/{sankeyDiagram-TZEHDZUN-D09PBJ-n.js → sankeyDiagram-TZEHDZUN-DMal8sps.js} +3 -3
  145. package/dist/{sequenceDiagram-WL72ISMW-t_Dpemj0.js → sequenceDiagram-WL72ISMW-DT6Tk-Eo.js} +4 -4
  146. package/dist/{spec-hVaaZsY5.js → spec-BQbOvWbq.js} +4 -4
  147. package/dist/{stateDiagram-FKZM4ZOC-B18gTP_j.js → stateDiagram-FKZM4ZOC-CB_lodq3.js} +12 -12
  148. package/dist/{stateDiagram-v2-4FDKWEC3-B6e_t14A.js → stateDiagram-v2-4FDKWEC3-E0RGjKsm.js} +10 -10
  149. package/dist/stex-KfRnSHzF.js +4 -0
  150. package/dist/{strings-BiIhGaI8.js → strings-Bu3vlb6W.js} +7 -7
  151. package/dist/style.css +1 -1
  152. package/dist/{swiper-component-DlD2GU2g.js → swiper-component-B2t5sN1q.js} +3 -3
  153. package/dist/{time-C1SGcFMH.js → time-CsmIF9YZ.js} +3 -3
  154. package/dist/{timeline-definition-IT6M3QCI-DJnh1ks5.js → timeline-definition-IT6M3QCI-NfSKRvH0.js} +2 -2
  155. package/dist/{toDate-CIpC_34u.js → toDate-DqrFDZlc.js} +5 -5
  156. package/dist/{tooltip-DRaMBu06.js → tooltip-C5FYOpQc.js} +4 -4
  157. package/dist/{treemap-GDKQZRPO-Du95DV6u.js → treemap-GDKQZRPO-Cl6OQh8D.js} +3 -3
  158. package/dist/{types-Dzuoc3LN.js → types-CVvp1fKr.js} +2 -9
  159. package/dist/{useAsyncData-C56Khv_R.js → useAsyncData-4lY05iWF.js} +2 -2
  160. package/dist/{useDateFormatter-B_9k85Ex.js → useDateFormatter-BA4FCquG.js} +2 -2
  161. package/dist/{useDeepCompareMemoize-Dt98v2ua.js → useDeepCompareMemoize-C5Zu9gK6.js} +1 -1
  162. package/dist/{useIframeCapabilities-BkYHTrss.js → useIframeCapabilities-C4JTXTIh.js} +1 -1
  163. package/dist/{useLifecycle-BF6-z62y.js → useLifecycle-YLdDriVo.js} +4 -4
  164. package/dist/{useTheme-DykuNHR2.js → useTheme-u3PW8S24.js} +22 -21
  165. package/dist/{vega-component-cSdqoAxe.js → vega-component-CdQu2ErN.js} +18 -18
  166. package/dist/{vega-loader.browser-3_z8GoFC.js → vega-loader.browser-CZ-J8Py3.js} +3 -3
  167. package/dist/{xychartDiagram-PRI3JC2R-Dk2d_bX0.js → xychartDiagram-PRI3JC2R-BvwftqMA.js} +9 -9
  168. package/dist/{zod-BWkcDORu.js → zod-CoBiJ5v4.js} +3 -3
  169. package/package.json +1 -1
  170. package/src/components/data-table/TableBottomBar.tsx +27 -6
  171. package/src/components/data-table/TableTopBar.tsx +7 -1
  172. package/src/components/data-table/__tests__/TableBottomBar.test.tsx +73 -0
  173. package/src/components/data-table/__tests__/column-explorer.test.tsx +128 -0
  174. package/src/components/data-table/__tests__/column-header.test.tsx +110 -277
  175. package/src/components/data-table/__tests__/data-table.test.tsx +52 -1
  176. package/src/components/data-table/__tests__/date-filter-inputs.test.tsx +33 -0
  177. package/src/components/data-table/__tests__/filter-pill-editor.test.tsx +75 -38
  178. package/src/components/data-table/__tests__/filter-pills.test.tsx +287 -0
  179. package/src/components/data-table/__tests__/filter-test-utils.ts +47 -0
  180. package/src/components/data-table/__tests__/filters.test.ts +5 -5
  181. package/src/components/data-table/__tests__/header-items.test.tsx +47 -1
  182. package/src/components/data-table/__tests__/useColumnVisibility.test.ts +42 -0
  183. package/src/components/data-table/add-filter-button.tsx +85 -0
  184. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +98 -26
  185. package/src/components/data-table/column-header.tsx +94 -691
  186. package/src/components/data-table/columns.tsx +3 -4
  187. package/src/components/data-table/context-menu.tsx +26 -12
  188. package/src/components/data-table/data-table.tsx +125 -56
  189. package/src/components/data-table/date-filter-inputs.tsx +13 -10
  190. package/src/components/data-table/export-actions.tsx +17 -6
  191. package/src/components/data-table/filter-by-values-picker.tsx +13 -19
  192. package/src/components/data-table/filter-editor-context.tsx +34 -0
  193. package/src/components/data-table/filter-pill-editor.tsx +152 -175
  194. package/src/components/data-table/filter-pills.tsx +190 -153
  195. package/src/components/data-table/filters/builders.ts +102 -0
  196. package/src/components/data-table/filters/defaults.ts +31 -0
  197. package/src/components/data-table/filters/format.ts +131 -0
  198. package/src/components/data-table/filters/guards.ts +51 -0
  199. package/src/components/data-table/filters/index.ts +7 -0
  200. package/src/components/data-table/filters/operators.ts +76 -0
  201. package/src/components/data-table/filters/serialize.ts +186 -0
  202. package/src/components/data-table/filters/types.ts +33 -0
  203. package/src/components/data-table/header-items.tsx +25 -85
  204. package/src/components/data-table/hooks/use-column-visibility.ts +56 -0
  205. package/src/components/data-table/pagination.tsx +16 -3
  206. package/src/components/data-table/table-explorer-panel/table-explorer-panel.tsx +16 -6
  207. package/src/components/data-table/value-chips.tsx +52 -0
  208. package/src/components/dependency-graph/minimap-content.tsx +2 -2
  209. package/src/components/editor/errors/mangled-local-chip.tsx +50 -0
  210. package/src/components/editor/output/MarimoErrorOutput.tsx +110 -27
  211. package/src/components/editor/output/MarimoTracebackOutput.tsx +51 -34
  212. package/src/components/ui/number-field.tsx +13 -1
  213. package/src/core/codemirror/cells/traceback-decorations.ts +1 -1
  214. package/src/css/app/Cell.css +0 -1
  215. package/src/plugins/impl/DataTablePlugin.tsx +94 -33
  216. package/src/plugins/impl/__tests__/DataTablePlugin.test.tsx +1 -0
  217. package/src/plugins/impl/data-frames/DataFramePlugin.tsx +8 -6
  218. package/src/stories/dataframe.stories.tsx +1 -0
  219. package/src/utils/__tests__/local-variables.test.ts +132 -0
  220. package/src/utils/dates.ts +39 -0
  221. package/src/utils/local-variables.ts +67 -0
  222. package/dist/ErrorBoundary-D3wrPNma.js +0 -167
  223. package/dist/architecture-7HQA4BMR-CS9jOrqM.js +0 -6
  224. package/dist/dist-21ButRCu.js +0 -8
  225. package/dist/dist-B--tLnAP.js +0 -5
  226. package/dist/dist-BoHGySTM.js +0 -5
  227. package/dist/dist-ByAz19Qc.js +0 -5
  228. package/dist/dist-C1Ap5CYU.js +0 -5
  229. package/dist/dist-C93EysN4.js +0 -5
  230. package/dist/dist-CY-lVor6.js +0 -8
  231. package/dist/dist-CYDuv4bR.js +0 -8
  232. package/dist/dist-Cfo5EE2t.js +0 -6
  233. package/dist/dist-CjivSDvN.js +0 -5
  234. package/dist/dist-Cqwx-MH7.js +0 -5
  235. package/dist/dist-DbpcoFAV.js +0 -6
  236. package/dist/dist-FUNenbiQ.js +0 -5
  237. package/dist/dist-zhSud5X3.js +0 -8
  238. package/dist/mermaid-4DMBBIKO-B7VQMwJx.js +0 -6
  239. package/dist/react-vega-Cavbrg4l.js +0 -9
  240. package/dist/stex-ChDHQs3R.js +0 -4
  241. package/src/components/data-table/__tests__/column-header.test.ts +0 -65
  242. package/src/components/data-table/filters.ts +0 -386
  243. /package/dist/{_baseFor-BGiY-cm1.js → _baseFor-4jw-lnCC.js} +0 -0
  244. /package/dist/{clsx-CyyyQ8Ue.js → clsx-CIWA5tNO.js} +0 -0
  245. /package/dist/{defaultLocale-DoeErsX2.js → defaultLocale-BoHTsDG6.js} +0 -0
  246. /package/dist/{defaultLocale-BpsHxBd7.js → defaultLocale-u-3osm0P.js} +0 -0
  247. /package/dist/{dist-CCADb07R.js → dist-DNdhYsgW.js} +0 -0
  248. /package/dist/{emotion-is-prop-valid.esm-DtW2o230.js → emotion-is-prop-valid.esm-DzSb5hsH.js} +0 -0
  249. /package/dist/{invariant-UcGKQEhF.js → invariant-wRzNXIsJ.js} +0 -0
  250. /package/dist/{jsx-runtime-COBk7ree.js → jsx-runtime-DebpN0FN.js} +0 -0
  251. /package/dist/{main-CThhXnXU.js → main-Tj_-QTyF.js} +0 -0
  252. /package/dist/{micromark-factory-space-CwHmg6iz.js → micromark-factory-space-DF2w36zS.js} +0 -0
  253. /package/dist/{ordinal-B43ZeR68.js → ordinal-ArJavP1Q.js} +0 -0
  254. /package/dist/{purify.es-DT70lfR0.js → purify.es-H92eMd9-.js} +0 -0
  255. /package/dist/{range-BOiA8qqU.js → range-C-rmrM1O.js} +0 -0
  256. /package/dist/{react-dom-BWRJ_g_k.js → react-dom-BTJzcVJ9.js} +0 -0
  257. /package/dist/{stex-DrxP7bb3.js → stex-BIsgBmK4.js} +0 -0
@@ -8,8 +8,9 @@ import type {
8
8
  PaginationState,
9
9
  RowSelectionState,
10
10
  SortingState,
11
+ Table as TanstackTable,
11
12
  } from "@tanstack/react-table";
12
- import { Provider } from "jotai";
13
+ import { Provider, useAtomValue } from "jotai";
13
14
  import { Table2Icon } from "lucide-react";
14
15
  import type { JSX } from "react";
15
16
  import React, {
@@ -28,6 +29,7 @@ import { TablePanel } from "@/components/data-table/charts/charts";
28
29
  import { hasChart } from "@/components/data-table/charts/storage";
29
30
  import { ColumnChartSpecModel } from "@/components/data-table/column-summary/chart-spec-model";
30
31
  import { ColumnChartContext } from "@/components/data-table/column-summary/column-summary";
32
+ import { downloadSizeLimitAtom } from "@/components/data-table/download-policy/atoms";
31
33
  import { filtersToFilterGroup } from "@/components/data-table/filters";
32
34
  import { usePanelOwnership } from "@/components/data-table/hooks/use-panel-ownership";
33
35
  import { LoadingTable } from "@/components/data-table/loading-table";
@@ -190,11 +192,11 @@ interface Data<T> {
190
192
  fieldTypes?: FieldTypesWithExternalType | null;
191
193
  freezeColumnsLeft?: string[];
192
194
  freezeColumnsRight?: string[];
195
+ hiddenColumns?: string[];
193
196
  textJustifyColumns?: Record<string, "left" | "center" | "right">;
194
197
  wrappedColumns?: string[];
195
198
  headerTooltip?: Record<string, string>;
196
199
  totalColumns: number;
197
- sizeBytes?: number | null;
198
200
  maxColumns: number | "all";
199
201
  hasStableRowId: boolean;
200
202
  lazy: boolean;
@@ -221,12 +223,14 @@ type DataTableFunctions = {
221
223
  cell_styles?: CellStyleState | null;
222
224
  cell_hover_texts?: Record<string, Record<string, string | null>> | null;
223
225
  raw_data?: TableData<T> | null;
224
- size_bytes?: number | null;
225
226
  }>;
226
227
  get_data_url?: GetDataUrl;
227
228
  get_row_ids?: GetRowIds;
228
229
  calculate_top_k_rows?: CalculateTopKRows;
229
230
  preview_column?: PreviewColumn;
231
+ get_size_bytes: (opts: Record<string, never>) => Promise<{
232
+ size_bytes?: number | null;
233
+ }>;
230
234
  };
231
235
 
232
236
  type S = (number | string | { rowId: string; columnName?: string })[];
@@ -265,6 +269,7 @@ export const DataTablePlugin = createPlugin<S>("marimo-table")
265
269
  rowHeaders: columnToFieldTypesSchema,
266
270
  freezeColumnsLeft: z.array(z.string()).optional(),
267
271
  freezeColumnsRight: z.array(z.string()).optional(),
272
+ hiddenColumns: z.array(z.string()).optional(),
268
273
  textJustifyColumns: z
269
274
  .record(z.string(), z.enum(["left", "center", "right"]))
270
275
  .optional(),
@@ -272,7 +277,6 @@ export const DataTablePlugin = createPlugin<S>("marimo-table")
272
277
  headerTooltip: z.record(z.string(), z.string()).optional(),
273
278
  fieldTypes: columnToFieldTypesSchema.nullish(),
274
279
  totalColumns: z.number(),
275
- sizeBytes: z.number().nullish(),
276
280
  maxColumns: z.union([z.number(), z.literal("all")]).default("all"),
277
281
  hasStableRowId: z.boolean().default(false),
278
282
  maxHeight: z.number().optional(),
@@ -330,7 +334,6 @@ export const DataTablePlugin = createPlugin<S>("marimo-table")
330
334
  .nullable(),
331
335
  cell_hover_texts: cellHoverTextSchema.nullable(),
332
336
  raw_data: z.union([z.string(), z.array(z.looseObject({}))]).nullish(),
333
- size_bytes: z.number().nullish(),
334
337
  }),
335
338
  ),
336
339
  get_row_ids: rpc.input(z.object({}).passthrough()).output(
@@ -362,6 +365,9 @@ export const DataTablePlugin = createPlugin<S>("marimo-table")
362
365
  stats: columnStats.nullable(),
363
366
  }),
364
367
  ),
368
+ get_size_bytes: rpc
369
+ .input(z.object({}))
370
+ .output(z.object({ size_bytes: z.number().nullish() })),
365
371
  })
366
372
  .renderer((props) => {
367
373
  return (
@@ -536,7 +542,6 @@ export const LoadingDataTableComponent = memo(
536
542
  rows: T[];
537
543
  rawRows?: T[];
538
544
  totalRows: number | TooManyRows;
539
- sizeBytes?: number | null;
540
545
  cellStyles: CellStyleState | undefined | null;
541
546
  cellHoverTexts?: Record<string, Record<string, string | null>> | null;
542
547
  }>(async () => {
@@ -553,7 +558,6 @@ export const LoadingDataTableComponent = memo(
553
558
  let tableData = props.data;
554
559
  let rawTableData: TableData<T> | undefined | null = props.rawData;
555
560
  let totalRows = props.totalRows;
556
- let sizeBytes = props.sizeBytes ?? null;
557
561
  let cellStyles = props.cellStyles;
558
562
  let cellHoverTexts = props.cellHoverTexts;
559
563
 
@@ -597,7 +601,6 @@ export const LoadingDataTableComponent = memo(
597
601
  tableData = searchResults.data;
598
602
  rawTableData = searchResults.raw_data;
599
603
  totalRows = searchResults.total_rows;
600
- sizeBytes = searchResults.size_bytes ?? null;
601
604
  cellStyles = searchResults.cell_styles || {};
602
605
  cellHoverTexts = searchResults.cell_hover_texts || {};
603
606
  }
@@ -610,7 +613,6 @@ export const LoadingDataTableComponent = memo(
610
613
  rows: tableData,
611
614
  rawRows: rawData,
612
615
  totalRows: totalRows,
613
- sizeBytes,
614
616
  cellStyles,
615
617
  cellHoverTexts,
616
618
  };
@@ -622,7 +624,6 @@ export const LoadingDataTableComponent = memo(
622
624
  useDeepCompareMemoize(props.fieldTypes),
623
625
  props.data,
624
626
  props.totalRows,
625
- props.sizeBytes,
626
627
  props.lazy,
627
628
  props.cellHoverTexts,
628
629
  props.cellStyles,
@@ -630,6 +631,34 @@ export const LoadingDataTableComponent = memo(
630
631
  paginationState.pageIndex,
631
632
  ]);
632
633
 
634
+ const policy = useAtomValue(downloadSizeLimitAtom);
635
+ const { data: sizeBytesData, isPending: sizeBytesPending } = useAsyncData<
636
+ number | null
637
+ >(async () => {
638
+ if (
639
+ !policy ||
640
+ !props.showDownload ||
641
+ props.lazy ||
642
+ props.totalRows === 0
643
+ ) {
644
+ return null;
645
+ }
646
+ const result = await props.get_size_bytes({});
647
+ return result.size_bytes ?? null;
648
+ }, [
649
+ policy,
650
+ props.showDownload,
651
+ props.get_size_bytes,
652
+ props.lazy,
653
+ props.totalRows,
654
+ searchQuery,
655
+ useDeepCompareMemoize(filters),
656
+ useDeepCompareMemoize(sorting),
657
+ ]);
658
+ const sizeBytes = sizeBytesData ?? null;
659
+ const sizeBytesIsLoading =
660
+ !!policy && props.showDownload && sizeBytesPending;
661
+
633
662
  const getRow = useCallback(
634
663
  async (rowId: number) => {
635
664
  const sortArgs =
@@ -737,7 +766,8 @@ export const LoadingDataTableComponent = memo(
737
766
  setFilters={setFilters}
738
767
  reloading={isFetching && !isPending}
739
768
  totalRows={data?.totalRows ?? props.totalRows}
740
- sizeBytes={data?.sizeBytes ?? props.sizeBytes ?? null}
769
+ sizeBytes={sizeBytes}
770
+ sizeBytesIsLoading={sizeBytesIsLoading}
741
771
  paginationState={paginationState}
742
772
  setPaginationState={setPaginationState}
743
773
  cellStyles={data?.cellStyles ?? props.cellStyles}
@@ -785,6 +815,7 @@ const DataTableComponent = ({
785
815
  rawData,
786
816
  totalRows,
787
817
  sizeBytes,
818
+ sizeBytesIsLoading,
788
819
  maxColumns,
789
820
  pagination,
790
821
  selection,
@@ -814,6 +845,7 @@ const DataTableComponent = ({
814
845
  reloading,
815
846
  freezeColumnsLeft,
816
847
  freezeColumnsRight,
848
+ hiddenColumns,
817
849
  textJustifyColumns,
818
850
  wrappedColumns,
819
851
  headerTooltip,
@@ -835,6 +867,8 @@ const DataTableComponent = ({
835
867
  rawData?: unknown[];
836
868
  columnSummaries?: ColumnSummaries;
837
869
  getRow: (rowIdx: number) => Promise<GetRowResult>;
870
+ sizeBytes?: number | null;
871
+ sizeBytesIsLoading?: boolean;
838
872
  }): JSX.Element => {
839
873
  const id = useId();
840
874
  const [viewedRowIdx, setViewedRowIdx] = useState(0);
@@ -1007,6 +1041,52 @@ const DataTableComponent = ({
1007
1041
  const isInVscode = isInVscodeExtension();
1008
1042
  const isIslandsMode = isIslands();
1009
1043
 
1044
+ const renderTableExplorerPanel = useMemo(() => {
1045
+ if (!isAnyPanelOpen || !(showRowExplorer || canShowColumnExplorer)) {
1046
+ return undefined;
1047
+ }
1048
+ return (table: TanstackTable<unknown>) => (
1049
+ <ContextAwarePanelItem>
1050
+ <TableExplorerPanel
1051
+ rowIdx={viewedRowIdx}
1052
+ setRowIdx={setViewedRow}
1053
+ totalRows={totalRows}
1054
+ fieldTypes={memoizedUnclampedFieldTypes}
1055
+ getRow={getRow}
1056
+ isSelectable={isSelectable}
1057
+ isRowSelected={Boolean(rowSelection[viewedRowIdx])}
1058
+ handleRowSelectionChange={handleRowSelectionChange}
1059
+ previewColumn={preview_column}
1060
+ totalColumns={totalColumns}
1061
+ tableId={id}
1062
+ table={table}
1063
+ showRowExplorer={showRowExplorer && !isInVscode}
1064
+ showColumnExplorer={canShowColumnExplorer && !isInVscode}
1065
+ activeTab={panelType}
1066
+ onTabChange={setPanelType}
1067
+ />
1068
+ </ContextAwarePanelItem>
1069
+ );
1070
+ }, [
1071
+ isAnyPanelOpen,
1072
+ showRowExplorer,
1073
+ canShowColumnExplorer,
1074
+ viewedRowIdx,
1075
+ setViewedRow,
1076
+ totalRows,
1077
+ memoizedUnclampedFieldTypes,
1078
+ getRow,
1079
+ isSelectable,
1080
+ rowSelection,
1081
+ handleRowSelectionChange,
1082
+ preview_column,
1083
+ totalColumns,
1084
+ id,
1085
+ isInVscode,
1086
+ panelType,
1087
+ setPanelType,
1088
+ ]);
1089
+
1010
1090
  return (
1011
1091
  <>
1012
1092
  {/* When the totalRows is "too_many" and the pageSize is the same as the
@@ -1032,28 +1112,6 @@ const DataTableComponent = ({
1032
1112
  </Banner>
1033
1113
  )}
1034
1114
 
1035
- {isAnyPanelOpen && (showRowExplorer || canShowColumnExplorer) && (
1036
- <ContextAwarePanelItem>
1037
- <TableExplorerPanel
1038
- rowIdx={viewedRowIdx}
1039
- setRowIdx={setViewedRow}
1040
- totalRows={totalRows}
1041
- fieldTypes={memoizedUnclampedFieldTypes}
1042
- getRow={getRow}
1043
- isSelectable={isSelectable}
1044
- isRowSelected={Boolean(rowSelection[viewedRowIdx])}
1045
- handleRowSelectionChange={handleRowSelectionChange}
1046
- previewColumn={preview_column}
1047
- totalColumns={totalColumns}
1048
- tableId={id}
1049
- showRowExplorer={showRowExplorer && !isInVscode}
1050
- showColumnExplorer={canShowColumnExplorer && !isInVscode}
1051
- activeTab={panelType}
1052
- onTabChange={setPanelType}
1053
- />
1054
- </ContextAwarePanelItem>
1055
- )}
1056
-
1057
1115
  <ColumnChartContext value={chartSpecModel}>
1058
1116
  <Labeled label={label} align="top" fullWidth={true}>
1059
1117
  <DataTable
@@ -1065,6 +1123,7 @@ const DataTableComponent = ({
1065
1123
  sorting={sorting}
1066
1124
  totalRows={totalRows}
1067
1125
  sizeBytes={sizeBytes}
1126
+ sizeBytesIsLoading={sizeBytesIsLoading}
1068
1127
  totalColumns={totalColumns}
1069
1128
  manualSorting={true}
1070
1129
  setSorting={setSorting}
@@ -1090,6 +1149,7 @@ const DataTableComponent = ({
1090
1149
  onRowSelectionChange={handleRowSelectionChange}
1091
1150
  freezeColumnsLeft={freezeColumnsLeft}
1092
1151
  freezeColumnsRight={freezeColumnsRight}
1152
+ hiddenColumns={hiddenColumns}
1093
1153
  onCellSelectionChange={handleCellSelectionChange}
1094
1154
  getRowIds={get_row_ids}
1095
1155
  toggleDisplayHeader={toggleDisplayHeader}
@@ -1108,6 +1168,7 @@ const DataTableComponent = ({
1108
1168
  isAnyPanelOpen={isAnyPanelOpen}
1109
1169
  viewedRowIdx={viewedRowIdx}
1110
1170
  onViewedRowChange={(rowIdx) => setViewedRowIdx(rowIdx)}
1171
+ renderTableExplorerPanel={renderTableExplorerPanel}
1111
1172
  />
1112
1173
  </Labeled>
1113
1174
  </ColumnChartContext>
@@ -107,6 +107,7 @@ describe("LoadingDataTableComponent", () => {
107
107
  }),
108
108
  get_data_url: vi.fn() as GetDataUrl,
109
109
  get_row_ids: vi.fn() as GetRowIds,
110
+ get_size_bytes: vi.fn().mockResolvedValue({ size_bytes: null }),
110
111
  };
111
112
 
112
113
  const Wrapper = ({ children }: { children: React.ReactNode }) => (
@@ -64,7 +64,6 @@ type PluginFunctions = {
64
64
  column_types_per_step: FieldTypesWithExternalType[];
65
65
  python_code?: string | null;
66
66
  sql_code?: string | null;
67
- size_bytes?: number | null;
68
67
  }>;
69
68
  get_column_values: (req: { column: string }) => Promise<{
70
69
  values: unknown[];
@@ -82,9 +81,11 @@ type PluginFunctions = {
82
81
  }) => Promise<{
83
82
  data: TableData<T>;
84
83
  total_rows: number;
85
- size_bytes?: number | null;
86
84
  }>;
87
85
  download_as: DownloadAsArgs;
86
+ get_size_bytes: (opts: Record<string, never>) => Promise<{
87
+ size_bytes?: number | null;
88
+ }>;
88
89
  };
89
90
 
90
91
  // Value is selection, but it is not currently exposed to the user
@@ -120,7 +121,6 @@ export const DataFramePlugin = createPlugin<S>("marimo-dataframe")
120
121
  column_types_per_step: z.array(columnToFieldTypesSchema),
121
122
  python_code: z.string().nullish(),
122
123
  sql_code: z.string().nullish(),
123
- size_bytes: z.number().nullish(),
124
124
  }),
125
125
  ),
126
126
  get_column_values: rpc.input(z.object({ column: z.string() })).output(
@@ -150,10 +150,12 @@ export const DataFramePlugin = createPlugin<S>("marimo-dataframe")
150
150
  z.object({
151
151
  data: z.union([z.string(), z.array(z.object({}).passthrough())]),
152
152
  total_rows: z.number(),
153
- size_bytes: z.number().nullish(),
154
153
  }),
155
154
  ),
156
155
  download_as: DownloadAsSchema,
156
+ get_size_bytes: rpc
157
+ .input(z.object({}))
158
+ .output(z.object({ size_bytes: z.number().nullish() })),
157
159
  })
158
160
  .renderer((props) => (
159
161
  <TableProviders>
@@ -192,6 +194,7 @@ export const DataFrameComponent = memo(
192
194
  get_column_values,
193
195
  search,
194
196
  download_as,
197
+ get_size_bytes,
195
198
  host,
196
199
  }: DataTableProps): JSX.Element => {
197
200
  const { data, error, isPending } = useAsyncData(
@@ -207,7 +210,6 @@ export const DataFrameComponent = memo(
207
210
  column_types_per_step,
208
211
  python_code,
209
212
  sql_code,
210
- size_bytes,
211
213
  } = data || {};
212
214
 
213
215
  const totalColumns = field_types?.length;
@@ -327,7 +329,6 @@ export const DataFrameComponent = memo(
327
329
  data={url || ""}
328
330
  hasStableRowId={false}
329
331
  totalRows={total_rows ?? 0}
330
- sizeBytes={size_bytes ?? null}
331
332
  totalColumns={totalColumns ?? 0}
332
333
  maxColumns="all"
333
334
  pageSize={pageSize}
@@ -336,6 +337,7 @@ export const DataFrameComponent = memo(
336
337
  rowHeaders={row_headers || Arrays.EMPTY}
337
338
  showDownload={showDownload}
338
339
  download_as={download_as}
340
+ get_size_bytes={get_size_bytes}
339
341
  enableSearch={false}
340
342
  showFilters={false}
341
343
  search={search}
@@ -42,6 +42,7 @@ export const DataFrame: StoryObj = {
42
42
  host={document.body}
43
43
  showDownload={false}
44
44
  download_as={async () => ({ url: "", filename: "" })}
45
+ get_size_bytes={async () => ({ size_bytes: null })}
45
46
  lazy={false}
46
47
  />
47
48
  );
@@ -0,0 +1,132 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+ import { describe, expect, it } from "vitest";
3
+ import {
4
+ containsMangledLocal,
5
+ splitMangledLocals,
6
+ unmangleLocal,
7
+ } from "../local-variables";
8
+
9
+ describe("unmangleLocal", () => {
10
+ it("extracts the cell id and original name", () => {
11
+ expect(unmangleLocal("_cell_Hbol_a")).toEqual({
12
+ cellId: "Hbol",
13
+ name: "_a",
14
+ });
15
+ });
16
+
17
+ it("handles names with multiple underscore segments", () => {
18
+ expect(unmangleLocal("_cell_Hbol_a_b")).toEqual({
19
+ cellId: "Hbol",
20
+ name: "_a_b",
21
+ });
22
+ });
23
+
24
+ it("returns null for non-mangled strings", () => {
25
+ expect(unmangleLocal("just_a_variable")).toBeNull();
26
+ expect(unmangleLocal("_private")).toBeNull();
27
+ });
28
+
29
+ it("handles the single-underscore local", () => {
30
+ // `_` is a valid local name (variables.py:62-63), mangling to
31
+ // `_cell_<id>_` with no trailing suffix.
32
+ expect(unmangleLocal("_cell_Hbol_")).toEqual({
33
+ cellId: "Hbol",
34
+ name: "_",
35
+ });
36
+ });
37
+
38
+ it("handles UUID-style cell ids", () => {
39
+ // External / VSCode notebooks use `external_prefix()` which is a
40
+ // `uuid4()` (hyphenated).
41
+ expect(
42
+ unmangleLocal("_cell_c9bf9e57-1685-4c89-bafb-ff5af830be8a_a"),
43
+ ).toEqual({
44
+ cellId: "c9bf9e57-1685-4c89-bafb-ff5af830be8a",
45
+ name: "_a",
46
+ });
47
+ });
48
+
49
+ it("does not match marimo cell file paths", () => {
50
+ // The compiled cell file is `__marimo__cell_<id>_.py` (two leading
51
+ // underscores, trailing `_` with no name); it must not be confused with a
52
+ // mangled local.
53
+ expect(unmangleLocal("__marimo__cell_Hbol_.py")).toBeNull();
54
+ expect(unmangleLocal("/tmp/marimo_42/__marimo__cell_Hbol_.py")).toBeNull();
55
+ });
56
+ });
57
+
58
+ describe("splitMangledLocals", () => {
59
+ it("returns a single text segment when nothing matches", () => {
60
+ expect(splitMangledLocals("plain text")).toEqual(["plain text"]);
61
+ });
62
+
63
+ it("splits a NameError message", () => {
64
+ expect(splitMangledLocals("name '_cell_Hbol_a' is not defined")).toEqual([
65
+ "name '",
66
+ { cellId: "Hbol", name: "_a" },
67
+ "' is not defined",
68
+ ]);
69
+ });
70
+
71
+ it("handles multiple mangled names in one string", () => {
72
+ expect(splitMangledLocals("_cell_AAAA_x and _cell_BBBB_y")).toEqual([
73
+ { cellId: "AAAA", name: "_x" },
74
+ " and ",
75
+ { cellId: "BBBB", name: "_y" },
76
+ ]);
77
+ });
78
+
79
+ it("leaves the cell file path alone", () => {
80
+ const path = "/tmp/marimo_42/__marimo__cell_Hbol_.py";
81
+ expect(splitMangledLocals(path)).toEqual([path]);
82
+ });
83
+
84
+ it("ignores `_cell_...` substrings preceded by `_`", () => {
85
+ // Mirrors `(?<!_)` in `variables.py`: a leading `_` (e.g. inside
86
+ // `__marimo__cell_<id>_<...>`) means this is not a mangle the compiler
87
+ // produced, so we must not demangle it.
88
+ const text = "see __marimo__cell_Hbol_a for details";
89
+ expect(splitMangledLocals(text)).toEqual([text]);
90
+ });
91
+
92
+ it("splits a UUID-style cell id", () => {
93
+ expect(
94
+ splitMangledLocals(
95
+ "name '_cell_c9bf9e57-1685-4c89-bafb-ff5af830be8a_a' is not defined",
96
+ ),
97
+ ).toEqual([
98
+ "name '",
99
+ {
100
+ cellId: "c9bf9e57-1685-4c89-bafb-ff5af830be8a",
101
+ name: "_a",
102
+ },
103
+ "' is not defined",
104
+ ]);
105
+ });
106
+
107
+ it("splits the single-underscore local", () => {
108
+ expect(splitMangledLocals("name '_cell_Hbol_' is not defined")).toEqual([
109
+ "name '",
110
+ { cellId: "Hbol", name: "_" },
111
+ "' is not defined",
112
+ ]);
113
+ });
114
+ });
115
+
116
+ describe("containsMangledLocal", () => {
117
+ it("detects mangled names", () => {
118
+ expect(containsMangledLocal("name '_cell_Hbol_a' is not defined")).toBe(
119
+ true,
120
+ );
121
+ });
122
+
123
+ it("ignores the cell file path", () => {
124
+ expect(containsMangledLocal("/tmp/marimo_42/__marimo__cell_Hbol_.py")).toBe(
125
+ false,
126
+ );
127
+ });
128
+
129
+ it("ignores `_cell_...` substrings preceded by `_`", () => {
130
+ expect(containsMangledLocal("see __marimo__cell_Hbol_a")).toBe(false);
131
+ });
132
+ });
@@ -134,6 +134,45 @@ export function timeAgo(
134
134
  return value.toString();
135
135
  }
136
136
 
137
+ function pad2(n: number): string {
138
+ return n.toString().padStart(2, "0");
139
+ }
140
+
141
+ function pad4(n: number): string {
142
+ return n.toString().padStart(4, "0");
143
+ }
144
+
145
+ /**
146
+ * Format a Date as `YYYY-MM-DD` using the date's local-time fields.
147
+ *
148
+ * The output reflects what the user sees in their own timezone (the calendar
149
+ * day on their clock), not the UTC day. Use this when round-tripping values
150
+ * that originated from local-time inputs — date pickers, "filter on this
151
+ * day", calendar UI — so the displayed and serialized days agree.
152
+ *
153
+ * Not suitable for cross-timezone storage; use `Date.toISOString()` for that.
154
+ */
155
+ export function dateToLocalISODate(d: Date): string {
156
+ return `${pad4(d.getFullYear())}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`;
157
+ }
158
+
159
+ /**
160
+ * Format a Date as `HH:MM:SS` using the date's local-time fields.
161
+ *
162
+ * See `dateToLocalISODate` for the rationale on local vs UTC.
163
+ */
164
+ export function dateToLocalISOTime(d: Date): string {
165
+ return `${pad2(d.getHours())}:${pad2(d.getMinutes())}:${pad2(d.getSeconds())}`;
166
+ }
167
+
168
+ /**
169
+ * Format a Date as `YYYY-MM-DDTHH:MM:SS` (no timezone suffix) using local
170
+ * fields. See `dateToLocalISODate` for the rationale on local vs UTC.
171
+ */
172
+ export function dateToLocalISODateTime(d: Date): string {
173
+ return `${dateToLocalISODate(d)}T${dateToLocalISOTime(d)}`;
174
+ }
175
+
137
176
  export const supportedDateFormats = ["yyyy", "yyyy-MM", "yyyy-MM-dd"] as const;
138
177
  export type DateFormat = (typeof supportedDateFormats)[number];
139
178
 
@@ -0,0 +1,67 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+ import type { CellId } from "@/core/cells/ids";
3
+
4
+ /**
5
+ * The marimo compiler rewrites underscore-prefixed references inside a cell
6
+ * (which Python would treat as module-private) into `_cell_<cell_id>_<name>`
7
+ * so each cell gets its own private namespace. When such a reference fails at
8
+ * runtime (`NameError: name '_cell_Hbol_a' is not defined`), the mangled name
9
+ * leaks into the error UI. These helpers undo that mangling for display.
10
+ *
11
+ * Mirrors `marimo/_ast/variables.py`.
12
+ */
13
+
14
+ // Matches `_cell_<cell_id><name>` for normal ids and UUIDs. The `[\w-]`
15
+ // id class admits hyphens; the `_\w*` name group admits the bare `_`
16
+ // local; the `(?<!_)` lookbehind skips `__marimo__cell_...` paths.
17
+ // Mirrors `_MANGLED_LOCAL_IN_TEXT_RE` in `variables.py`.
18
+ const MANGLED_LOCAL_BODY = String.raw`_cell_([^\W_][\w-]*?)(_\w*)`;
19
+ const MANGLED_LOCAL_PATTERN = String.raw`(?<!_)${MANGLED_LOCAL_BODY}`;
20
+ // Strict (whole-string) form for `unmangleLocal`; the leading `^` makes the
21
+ // lookbehind trivially satisfied, so use the bare body.
22
+ const ANCHORED_RE = new RegExp(`^${MANGLED_LOCAL_BODY}$`);
23
+ const UNANCHORED_RE = new RegExp(MANGLED_LOCAL_PATTERN);
24
+ const GLOBAL_RE = new RegExp(MANGLED_LOCAL_PATTERN, "g");
25
+
26
+ export interface UnmangledLocal {
27
+ cellId: CellId;
28
+ /** The original underscore-prefixed name, e.g. "_a". */
29
+ name: string;
30
+ }
31
+
32
+ export function unmangleLocal(mangled: string): UnmangledLocal | null {
33
+ const match = ANCHORED_RE.exec(mangled);
34
+ if (!match) {
35
+ return null;
36
+ }
37
+ return { cellId: match[1] as CellId, name: match[2] };
38
+ }
39
+
40
+ export type MangledSegment = string | UnmangledLocal;
41
+
42
+ /**
43
+ * Split a plain text string into alternating literal text and unmangled-local
44
+ * segments, so callers can render mixed React content.
45
+ */
46
+ export function splitMangledLocals(text: string): MangledSegment[] {
47
+ const segments: MangledSegment[] = [];
48
+ GLOBAL_RE.lastIndex = 0;
49
+ let lastIndex = 0;
50
+ let match: RegExpExecArray | null = GLOBAL_RE.exec(text);
51
+ while (match !== null) {
52
+ if (match.index > lastIndex) {
53
+ segments.push(text.slice(lastIndex, match.index));
54
+ }
55
+ segments.push({ cellId: match[1] as CellId, name: match[2] });
56
+ lastIndex = match.index + match[0].length;
57
+ match = GLOBAL_RE.exec(text);
58
+ }
59
+ if (lastIndex < text.length) {
60
+ segments.push(text.slice(lastIndex));
61
+ }
62
+ return segments;
63
+ }
64
+
65
+ export function containsMangledLocal(text: string): boolean {
66
+ return UNANCHORED_RE.test(text);
67
+ }