@marimo-team/islands 0.23.9-dev2 → 0.23.9-dev21

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 (279) hide show
  1. package/dist/{ConnectedDataExplorerComponent-2lBNiUv6.js → ConnectedDataExplorerComponent-DSyAzzpW.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/assets/__vite-browser-external-Ddfz4Fpd.js +1 -0
  11. package/dist/assets/{worker-CpBbwbQo.js → worker-CgL6N0XX.js} +2 -2
  12. package/dist/{blockDiagram-VD42YOAC-DGDaxR8I.js → blockDiagram-VD42YOAC-Dy7hlFla.js} +7 -7
  13. package/dist/{button-Dj4BTre0.js → button-C5K9fIPF.js} +2 -2
  14. package/dist/{c4Diagram-YG6GDRKO-C2hc6ne8.js → c4Diagram-YG6GDRKO-BXlAmZ8Z.js} +4 -4
  15. package/dist/{capabilities-C9rrYCzf.js → capabilities-BceAxrAW.js} +2 -2
  16. package/dist/{channel-BBoIVUrJ.js → channel-D_PHgcig.js} +1 -1
  17. package/dist/{chat-ui-D3XBept8.js → chat-ui-BW28GQUq.js} +3084 -3057
  18. package/dist/{check-BcUIXnUT.js → check-DTbrK0zt.js} +1 -1
  19. package/dist/{chunk-4F5CHEZ2-BZq7Kom7.js → chunk-4F5CHEZ2-D9nGEHV8.js} +1 -1
  20. package/dist/{chunk-5FQGJX7Z-BOg95xG5.js → chunk-5FQGJX7Z-BNjes6Yx.js} +5 -5
  21. package/dist/{chunk-ABZYJK2D-D0cLy8Bb.js → chunk-ABZYJK2D-Dz0-H2B5.js} +1 -1
  22. package/dist/{chunk-ATLVNIR6-BXsEjlHF.js → chunk-ATLVNIR6-o0Z5MZLd.js} +1 -1
  23. package/dist/{chunk-B2363JML-D9-XOau1.js → chunk-B2363JML-KEJpLGGP.js} +1 -1
  24. package/dist/{chunk-B4BG7PRW-Q1usn6T3.js → chunk-B4BG7PRW-BL98U9B4.js} +4 -4
  25. package/dist/{chunk-DI55MBZ5-D1qLYNrb.js → chunk-DI55MBZ5-Dwkn0LWm.js} +4 -4
  26. package/dist/{chunk-EXTU4WIE-BKNXdLmD.js → chunk-EXTU4WIE-9sNjmQrB.js} +1 -1
  27. package/dist/{chunk-FRFDVMJY-BSBUAX7r.js → chunk-FRFDVMJY-DzQqMWrl.js} +1 -1
  28. package/dist/{chunk-JA3XYJ7Z-D6c6cOBG.js → chunk-JA3XYJ7Z-C32Y7Epf.js} +2 -2
  29. package/dist/{chunk-JZLCHNYA-BvsPHJmL.js → chunk-JZLCHNYA-C6ftyVMN.js} +4 -4
  30. package/dist/{chunk-N4CR4FBY-8ycT-O9a.js → chunk-N4CR4FBY-DUhGZhZs.js} +5 -5
  31. package/dist/{chunk-PL6DKKU2-B0MTXvyc.js → chunk-PL6DKKU2-D7km-08O.js} +1 -1
  32. package/dist/{chunk-QN33PNHL-Bb-eUBW3.js → chunk-QN33PNHL-0K6SDYn3.js} +1 -1
  33. package/dist/{chunk-QXUST7PY-DV8yRwBd.js → chunk-QXUST7PY-DMhsRpYK.js} +5 -5
  34. package/dist/{chunk-S3R3BYOJ-mQeCz5CE.js → chunk-S3R3BYOJ-oAe3dEbO.js} +3 -3
  35. package/dist/{chunk-SJTYNZTY-CEG4F0pB.js → chunk-SJTYNZTY-BkJrPRFC.js} +1 -1
  36. package/dist/{chunk-TCCFYFTB-d3HOqL2I.js → chunk-TCCFYFTB-D58KeXnC.js} +6 -6
  37. package/dist/{chunk-TQ3KTPDO-DiCtqVSi.js → chunk-TQ3KTPDO-D_yA_wAb.js} +1 -1
  38. package/dist/{chunk-TZMSLE5B-BqW10dHe.js → chunk-TZMSLE5B-yBKS_DQU.js} +1 -1
  39. package/dist/{chunk-UMXZTB3W-97iS1iEl.js → chunk-UMXZTB3W-D7uwvNjd.js} +1 -1
  40. package/dist/{classDiagram-2ON5EDUG--Yh__LHb.js → classDiagram-2ON5EDUG-QjoAcuFE.js} +10 -10
  41. package/dist/{classDiagram-v2-WZHVMYZB-BC7X7Xtc.js → classDiagram-v2-WZHVMYZB-bUCv4gu2.js} +10 -10
  42. package/dist/{clone-BuIIsfA8.js → clone-Q4Fqwn6q.js} +1 -1
  43. package/dist/{code-block-37QAKDTI-BsGy1AOJ.js → code-block-37QAKDTI-m92Yc8pv.js} +2 -2
  44. package/dist/{code-visibility-Dt0Aq6-t.js → code-visibility-k3JE3fvP.js} +8425 -8595
  45. package/dist/{constants-D0gkYoE2.js → constants-T20xxyNf.js} +2 -2
  46. package/dist/{copy-DLf4aN7I.js → copy-BuQpJEzp.js} +2 -2
  47. package/dist/{dagre-6UL2VRFP-DRBWoQUw.js → dagre-6UL2VRFP-J0JKgwOt.js} +11 -11
  48. package/dist/{dagre-VYEPqXIV.js → dagre-By_QsQgc.js} +11 -11
  49. package/dist/{data-grid-overlay-editor-efe5ZagF.js → data-grid-overlay-editor-mfEJ5475.js} +2 -2
  50. package/dist/{diagram-PSM6KHXK-H66ATWP2.js → diagram-PSM6KHXK-DYgJuNk9.js} +18 -18
  51. package/dist/{diagram-QEK2KX5R-DItl5Wns.js → diagram-QEK2KX5R-CKdBR2sb.js} +14 -14
  52. package/dist/{diagram-S2PKOQOG-CtuW_ZuL.js → diagram-S2PKOQOG-Dpi7mo5W.js} +14 -14
  53. package/dist/dist-0Fif7jnk.js +5 -0
  54. package/dist/{dist-Dh3wkoyH.js → dist-4j4c7bjm.js} +2 -2
  55. package/dist/{dist-CDFZi-QD.js → dist-B3P2fFpz.js} +1 -1
  56. package/dist/{dist-BNyrZfqT.js → dist-B3pZ0Ab6.js} +2 -2
  57. package/dist/dist-B5h_9sHB.js +6 -0
  58. package/dist/dist-B9M6R5ye.js +5 -0
  59. package/dist/dist-BCt3tnck.js +8 -0
  60. package/dist/{dist-BrBucRXs.js → dist-BTfv03uy.js} +2 -2
  61. package/dist/dist-BUIJwMwn.js +8 -0
  62. package/dist/{dist-CYEylvZA.js → dist-BbbIBDiQ.js} +1 -1
  63. package/dist/{dist-KnujRhFL.js → dist-BcuoonNH.js} +4 -4
  64. package/dist/{dist-DJ6zJQZ4.js → dist-Bde4a2kU.js} +2 -2
  65. package/dist/{dist-t_qL7eB8.js → dist-Bfwsv11D.js} +2 -2
  66. package/dist/{dist-CNtV21T_.js → dist-BhM8gdSO.js} +4 -4
  67. package/dist/{dist-nuW5EDYT.js → dist-BotSqB48.js} +2 -2
  68. package/dist/dist-BpquMd3k.js +5 -0
  69. package/dist/dist-BzJsqYfz.js +5 -0
  70. package/dist/{dist-D029TiHd.js → dist-Bz_sYWbr.js} +2 -2
  71. package/dist/{dist-D3ZI9nhS.js → dist-C1BYNeCR.js} +4 -4
  72. package/dist/{dist-Bc5pmZIw.js → dist-C5VC_yzu.js} +1 -1
  73. package/dist/dist-CA5ELXAf.js +6 -0
  74. package/dist/dist-CLBRs6Uv.js +5 -0
  75. package/dist/{dist-Dhk6FMb0.js → dist-CLJWPTX2.js} +3 -3
  76. package/dist/{dist-C34oIrQ9.js → dist-CLUtPrdy.js} +1 -1
  77. package/dist/dist-CStVCMbq.js +5 -0
  78. package/dist/{dist-B8RaFTRF.js → dist-CUCNs1ja.js} +2 -2
  79. package/dist/dist-CZRIEY3Y.js +8 -0
  80. package/dist/{dist-UcOPnRMa.js → dist-CcXxepx6.js} +3 -3
  81. package/dist/dist-CuUHbFD0.js +5 -0
  82. package/dist/{dist-B8BjrFUE.js → dist-Cy1WxgBD.js} +5 -5
  83. package/dist/{dist-WdPUFc56.js → dist-D4CewLk6.js} +1 -1
  84. package/dist/{dist-DMZNjfX4.js → dist-DRfcqpxJ.js} +2 -2
  85. package/dist/dist-DV7Iabxb.js +8 -0
  86. package/dist/{dist-usPCDYx8.js → dist-D_bzzWBm.js} +1 -1
  87. package/dist/{dist-BvCfQQQE.js → dist-DgnE8F-r.js} +1 -1
  88. package/dist/{dist-JEhxD_cn.js → dist-DhHh0jLg.js} +1 -1
  89. package/dist/{dist-DGAfI2rB.js → dist-DqAWR3CS.js} +2 -2
  90. package/dist/{dist--sWVZwjW.js → dist-Du8WkPuU.js} +1 -1
  91. package/dist/dist-DuEeHMvL.js +5 -0
  92. package/dist/{dist-BTyJtnNg.js → dist-DxvORzUR.js} +1 -1
  93. package/dist/{dist-B507mf_I.js → dist-RqXTaiir.js} +2 -2
  94. package/dist/{dist-Yrfc6L0I.js → dist-fQ0ViXGs.js} +3 -3
  95. package/dist/{dist-B4LJpMEg.js → dist-h2c8sZvT.js} +1 -1
  96. package/dist/{dist-C2ej4eOH.js → dist-luvabDEB.js} +2 -2
  97. package/dist/{dist-B52GXZbd.js → dist-p2qyWijU.js} +2 -2
  98. package/dist/{erDiagram-Q2GNP2WA--19X2kU5.js → erDiagram-Q2GNP2WA-BU-m41EQ.js} +10 -10
  99. package/dist/{error-banner-CVkfBUT3.js → error-banner-5bz0L9hS.js} +3 -3
  100. package/dist/{esm-CWp0KQeK.js → esm-BfhQmZjp.js} +4 -4
  101. package/dist/{esm-DjNnlmpf.js → esm-Duie8iU-.js} +23 -23
  102. package/dist/{extends-vAi97cpa.js → extends-BgdxCfYu.js} +6 -6
  103. package/dist/{flatten-CzBvFdvC.js → flatten-Bbw7g6-K.js} +1 -1
  104. package/dist/{flowDiagram-NV44I4VS-DQmWlo7f.js → flowDiagram-NV44I4VS-CRoXKjGq.js} +10 -10
  105. package/dist/{formats-Dsy9kkZu.js → formats-BiH6HX1V.js} +4 -4
  106. package/dist/{ganttDiagram-JELNMOA3-BOGXJ8Lk.js → ganttDiagram-JELNMOA3-7mq5f9cO.js} +7 -7
  107. package/dist/{gitGraph-G5XIXVHT-DGlbae5m.js → gitGraph-G5XIXVHT-DiniR35k.js} +3 -3
  108. package/dist/{gitGraphDiagram-V2S2FVAM-DjzxfF0P.js → gitGraphDiagram-V2S2FVAM-Dfuokq6w.js} +13 -13
  109. package/dist/{glide-data-editor-DucgdjRo.js → glide-data-editor-Ck-MRdns.js} +557 -557
  110. package/dist/{graphlib-CVPKjKCS.js → graphlib-Ns7y5crs.js} +5 -5
  111. package/dist/{hasIn-COs6vImh.js → hasIn-Deg7jl_j.js} +3 -3
  112. package/dist/{html-to-image-CpggM7u1.js → html-to-image-Bi7maU1p.js} +115 -110
  113. package/dist/{info-VBDWY6EO-D2lvLLw5.js → info-VBDWY6EO-DVZvGhkQ.js} +3 -3
  114. package/dist/{infoDiagram-HS3SLOUP-ChNufFsP.js → infoDiagram-HS3SLOUP-CEnzWruK.js} +13 -13
  115. package/dist/{input-D4kjoQUB.js → input-BwcGY_X1.js} +70 -67
  116. package/dist/{isEmpty-Dd8mx_WL.js → isEmpty-CJJMn-QP.js} +1 -1
  117. package/dist/{isSymbol-BvIfMnn6.js → isSymbol-CoUCgMCM.js} +1 -1
  118. package/dist/{journeyDiagram-XKPGCS4Q-BO_O4Ij1.js → journeyDiagram-XKPGCS4Q-8XYSU1GI.js} +3 -3
  119. package/dist/{kanban-definition-3W4ZIXB7-CPpiiiWk.js → kanban-definition-3W4ZIXB7--9pT9z1R.js} +7 -7
  120. package/dist/{label-BLqV33b1.js → label-LWtdw5i8.js} +3 -3
  121. package/dist/{linear-2NnK4cxi.js → linear-B5-AFRiR.js} +2 -2
  122. package/dist/{loader-Dr8Qem8p.js → loader-BWLPpjKK.js} +2 -2
  123. package/dist/main.js +1688 -1569
  124. package/dist/{memoize-C9ltv0Cw.js → memoize-BOtf2yFf.js} +1 -1
  125. package/dist/{merge-CHn7Yx0N.js → merge-Be1CqGnU.js} +1 -1
  126. package/dist/mermaid-4DMBBIKO-DIdL224_.js +6 -0
  127. package/dist/{mermaid-DO-Daq7u.js → mermaid-YK4c8MNC.js} +44 -44
  128. package/dist/{mermaid-parser.core-DreccfmS.js → mermaid-parser.core-C3XRsazI.js} +8 -8
  129. package/dist/{min-BNz2lZfk.js → min-Dtgc8txR.js} +4 -4
  130. package/dist/{mindmap-definition-VGOIOE7T-CC1_Vl0f.js → mindmap-definition-VGOIOE7T-B-4mnfFG.js} +9 -9
  131. package/dist/{now-Sgq5m3D-.js → now-Ch98bJO_.js} +2 -2
  132. package/dist/{number-overlay-editor-CpKi64Fy.js → number-overlay-editor-D-a0qCT8.js} +1 -1
  133. package/dist/{once-rJImu7SE.js → once-DPuqGUeo.js} +1 -1
  134. package/dist/{packet-DYOGHKS2-CmWtF3uO.js → packet-DYOGHKS2-34raHOiB.js} +3 -3
  135. package/dist/{pick-CRAXxDYn.js → pick-D1Qo8s2C.js} +4 -4
  136. package/dist/{pie-VRWISCQL-B6u8vus8.js → pie-VRWISCQL-BaLlzZa3.js} +3 -3
  137. package/dist/{pieDiagram-ADFJNKIX-Di34MOFQ.js → pieDiagram-ADFJNKIX-Cr3cNpZY.js} +15 -15
  138. package/dist/{precisionRound-CnHPY_5v.js → precisionRound-Tqb4mg-H.js} +1 -1
  139. package/dist/{process-output-X8TR20AK.js → process-output-BimQ_hG4.js} +36 -28
  140. package/dist/{quadrantDiagram-AYHSOK5B-B9kVk1ny.js → quadrantDiagram-AYHSOK5B-BuNL8Q93.js} +4 -4
  141. package/dist/{radar-ZZBFDIW7-XAmXSa8s.js → radar-ZZBFDIW7-Ci7bfoZa.js} +3 -3
  142. package/dist/{react-vega-Dh6-UKKe.js → react-vega-B0sAlDTL.js} +9 -9
  143. package/dist/react-vega-B6ncY2Tp.js +9 -0
  144. package/dist/{requirementDiagram-UZGBJVZJ-BxGfGYEx.js → requirementDiagram-UZGBJVZJ-BG2lLUN1.js} +9 -9
  145. package/dist/{reveal-component-Cj2fUG1Q.js → reveal-component-BykBckM-.js} +31 -31
  146. package/dist/{sankeyDiagram-TZEHDZUN-D09PBJ-n.js → sankeyDiagram-TZEHDZUN-DMal8sps.js} +3 -3
  147. package/dist/{sequenceDiagram-WL72ISMW-t_Dpemj0.js → sequenceDiagram-WL72ISMW-DT6Tk-Eo.js} +4 -4
  148. package/dist/{spec-hVaaZsY5.js → spec-CyLiCjSf.js} +4 -4
  149. package/dist/{stateDiagram-FKZM4ZOC-B18gTP_j.js → stateDiagram-FKZM4ZOC-CB_lodq3.js} +12 -12
  150. package/dist/{stateDiagram-v2-4FDKWEC3-B6e_t14A.js → stateDiagram-v2-4FDKWEC3-E0RGjKsm.js} +10 -10
  151. package/dist/stex-KfRnSHzF.js +4 -0
  152. package/dist/{strings-BiIhGaI8.js → strings-Bu3vlb6W.js} +7 -7
  153. package/dist/style.css +1 -1
  154. package/dist/{swiper-component-DlD2GU2g.js → swiper-component-B2t5sN1q.js} +3 -3
  155. package/dist/{time-C1SGcFMH.js → time-CsmIF9YZ.js} +3 -3
  156. package/dist/{timeline-definition-IT6M3QCI-DJnh1ks5.js → timeline-definition-IT6M3QCI-NfSKRvH0.js} +2 -2
  157. package/dist/{toDate-CIpC_34u.js → toDate-DNWCUEQp.js} +5 -5
  158. package/dist/{tooltip-DRaMBu06.js → tooltip-C5FYOpQc.js} +4 -4
  159. package/dist/{treemap-GDKQZRPO-Du95DV6u.js → treemap-GDKQZRPO-Cl6OQh8D.js} +3 -3
  160. package/dist/{types-Dzuoc3LN.js → types-CVvp1fKr.js} +2 -9
  161. package/dist/{useAsyncData-C56Khv_R.js → useAsyncData-xWFWzCee.js} +2 -2
  162. package/dist/{useDateFormatter-B_9k85Ex.js → useDateFormatter-BA4FCquG.js} +2 -2
  163. package/dist/{useDeepCompareMemoize-Dt98v2ua.js → useDeepCompareMemoize-DSChED4g.js} +1 -1
  164. package/dist/{useIframeCapabilities-BkYHTrss.js → useIframeCapabilities-C4JTXTIh.js} +1 -1
  165. package/dist/{useLifecycle-BF6-z62y.js → useLifecycle-B81PFEja.js} +4 -4
  166. package/dist/{useTheme-DykuNHR2.js → useTheme-EmVyK9N9.js} +23 -21
  167. package/dist/{vega-component-cSdqoAxe.js → vega-component-BCunE3-9.js} +18 -18
  168. package/dist/{vega-loader.browser-3_z8GoFC.js → vega-loader.browser-CZ-J8Py3.js} +3 -3
  169. package/dist/{xychartDiagram-PRI3JC2R-Dk2d_bX0.js → xychartDiagram-PRI3JC2R-BvwftqMA.js} +9 -9
  170. package/dist/{zod-BWkcDORu.js → zod-CoBiJ5v4.js} +3 -3
  171. package/package.json +1 -1
  172. package/src/components/app-config/user-config-form.tsx +36 -0
  173. package/src/components/chat/__tests__/chat-utils.test.ts +269 -0
  174. package/src/components/chat/chat-utils.ts +14 -58
  175. package/src/components/data-table/TableBottomBar.tsx +27 -6
  176. package/src/components/data-table/TableTopBar.tsx +7 -1
  177. package/src/components/data-table/__tests__/TableBottomBar.test.tsx +73 -0
  178. package/src/components/data-table/__tests__/column-explorer.test.tsx +128 -0
  179. package/src/components/data-table/__tests__/column-header.test.tsx +110 -277
  180. package/src/components/data-table/__tests__/data-table.test.tsx +52 -1
  181. package/src/components/data-table/__tests__/date-filter-inputs.test.tsx +33 -0
  182. package/src/components/data-table/__tests__/filter-pill-editor.test.tsx +75 -38
  183. package/src/components/data-table/__tests__/filter-pills.test.tsx +287 -0
  184. package/src/components/data-table/__tests__/filter-test-utils.ts +47 -0
  185. package/src/components/data-table/__tests__/filters.test.ts +5 -5
  186. package/src/components/data-table/__tests__/header-items.test.tsx +47 -1
  187. package/src/components/data-table/__tests__/useColumnVisibility.test.ts +42 -0
  188. package/src/components/data-table/add-filter-button.tsx +85 -0
  189. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +98 -26
  190. package/src/components/data-table/column-header.tsx +94 -691
  191. package/src/components/data-table/columns.tsx +3 -4
  192. package/src/components/data-table/context-menu.tsx +26 -12
  193. package/src/components/data-table/data-table.tsx +125 -56
  194. package/src/components/data-table/date-filter-inputs.tsx +13 -10
  195. package/src/components/data-table/export-actions.tsx +17 -6
  196. package/src/components/data-table/filter-by-values-picker.tsx +13 -19
  197. package/src/components/data-table/filter-editor-context.tsx +34 -0
  198. package/src/components/data-table/filter-pill-editor.tsx +152 -175
  199. package/src/components/data-table/filter-pills.tsx +190 -153
  200. package/src/components/data-table/filters/builders.ts +102 -0
  201. package/src/components/data-table/filters/defaults.ts +31 -0
  202. package/src/components/data-table/filters/format.ts +131 -0
  203. package/src/components/data-table/filters/guards.ts +51 -0
  204. package/src/components/data-table/filters/index.ts +7 -0
  205. package/src/components/data-table/filters/operators.ts +76 -0
  206. package/src/components/data-table/filters/serialize.ts +186 -0
  207. package/src/components/data-table/filters/types.ts +33 -0
  208. package/src/components/data-table/header-items.tsx +25 -85
  209. package/src/components/data-table/hooks/use-column-visibility.ts +56 -0
  210. package/src/components/data-table/pagination.tsx +16 -3
  211. package/src/components/data-table/table-explorer-panel/table-explorer-panel.tsx +16 -6
  212. package/src/components/data-table/value-chips.tsx +52 -0
  213. package/src/components/databases/display.tsx +2 -0
  214. package/src/components/datasources/__tests__/utils.test.ts +82 -0
  215. package/src/components/datasources/utils.ts +16 -15
  216. package/src/components/dependency-graph/minimap-content.tsx +2 -2
  217. package/src/components/editor/errors/mangled-local-chip.tsx +50 -0
  218. package/src/components/editor/output/MarimoErrorOutput.tsx +110 -27
  219. package/src/components/editor/output/MarimoTracebackOutput.tsx +51 -34
  220. package/src/components/ui/number-field.tsx +13 -1
  221. package/src/core/cells/__tests__/actions.test.ts +48 -0
  222. package/src/core/cells/actions.ts +5 -6
  223. package/src/core/codemirror/__tests__/setup.test.ts +29 -0
  224. package/src/core/codemirror/cells/traceback-decorations.ts +1 -1
  225. package/src/core/codemirror/cm.ts +3 -2
  226. package/src/core/codemirror/format.ts +1 -0
  227. package/src/core/codemirror/language/languages/sql/sql.ts +1 -0
  228. package/src/core/codemirror/language/languages/sql/utils.ts +2 -0
  229. package/src/core/config/__tests__/config-schema.test.ts +2 -0
  230. package/src/core/config/config-schema.ts +1 -0
  231. package/src/css/app/Cell.css +0 -1
  232. package/src/plugins/impl/DataTablePlugin.tsx +94 -33
  233. package/src/plugins/impl/__tests__/DataTablePlugin.test.tsx +1 -0
  234. package/src/plugins/impl/chat/ChatPlugin.tsx +7 -1
  235. package/src/plugins/impl/chat/__tests__/chat-ui.test.ts +278 -0
  236. package/src/plugins/impl/chat/chat-ui.tsx +106 -59
  237. package/src/plugins/impl/chat/types.ts +5 -0
  238. package/src/plugins/impl/data-frames/DataFramePlugin.tsx +8 -6
  239. package/src/stories/dataframe.stories.tsx +1 -0
  240. package/src/utils/__tests__/local-variables.test.ts +132 -0
  241. package/src/utils/dates.ts +39 -0
  242. package/src/utils/local-variables.ts +67 -0
  243. package/dist/ErrorBoundary-D3wrPNma.js +0 -167
  244. package/dist/architecture-7HQA4BMR-CS9jOrqM.js +0 -6
  245. package/dist/assets/__vite-browser-external-CAdMKBac.js +0 -1
  246. package/dist/dist-21ButRCu.js +0 -8
  247. package/dist/dist-B--tLnAP.js +0 -5
  248. package/dist/dist-BoHGySTM.js +0 -5
  249. package/dist/dist-ByAz19Qc.js +0 -5
  250. package/dist/dist-C1Ap5CYU.js +0 -5
  251. package/dist/dist-C93EysN4.js +0 -5
  252. package/dist/dist-CY-lVor6.js +0 -8
  253. package/dist/dist-CYDuv4bR.js +0 -8
  254. package/dist/dist-Cfo5EE2t.js +0 -6
  255. package/dist/dist-CjivSDvN.js +0 -5
  256. package/dist/dist-Cqwx-MH7.js +0 -5
  257. package/dist/dist-DbpcoFAV.js +0 -6
  258. package/dist/dist-FUNenbiQ.js +0 -5
  259. package/dist/dist-zhSud5X3.js +0 -8
  260. package/dist/mermaid-4DMBBIKO-B7VQMwJx.js +0 -6
  261. package/dist/react-vega-Cavbrg4l.js +0 -9
  262. package/dist/stex-ChDHQs3R.js +0 -4
  263. package/src/components/data-table/__tests__/column-header.test.ts +0 -65
  264. package/src/components/data-table/filters.ts +0 -386
  265. /package/dist/{_baseFor-BGiY-cm1.js → _baseFor-4jw-lnCC.js} +0 -0
  266. /package/dist/{clsx-CyyyQ8Ue.js → clsx-CIWA5tNO.js} +0 -0
  267. /package/dist/{defaultLocale-DoeErsX2.js → defaultLocale-BoHTsDG6.js} +0 -0
  268. /package/dist/{defaultLocale-BpsHxBd7.js → defaultLocale-u-3osm0P.js} +0 -0
  269. /package/dist/{dist-CCADb07R.js → dist-DNdhYsgW.js} +0 -0
  270. /package/dist/{emotion-is-prop-valid.esm-DtW2o230.js → emotion-is-prop-valid.esm-DzSb5hsH.js} +0 -0
  271. /package/dist/{invariant-UcGKQEhF.js → invariant-wRzNXIsJ.js} +0 -0
  272. /package/dist/{jsx-runtime-COBk7ree.js → jsx-runtime-DebpN0FN.js} +0 -0
  273. /package/dist/{main-CThhXnXU.js → main-Tj_-QTyF.js} +0 -0
  274. /package/dist/{micromark-factory-space-CwHmg6iz.js → micromark-factory-space-DF2w36zS.js} +0 -0
  275. /package/dist/{ordinal-B43ZeR68.js → ordinal-ArJavP1Q.js} +0 -0
  276. /package/dist/{purify.es-DT70lfR0.js → purify.es-H92eMd9-.js} +0 -0
  277. /package/dist/{range-BOiA8qqU.js → range-C-rmrM1O.js} +0 -0
  278. /package/dist/{react-dom-BWRJ_g_k.js → react-dom-BTJzcVJ9.js} +0 -0
  279. /package/dist/{stex-DrxP7bb3.js → stex-BIsgBmK4.js} +0 -0
@@ -44,9 +44,10 @@ import { detectSentinel, splitLeadingTrailingWhitespace } from "./utils";
44
44
  import { uniformSample } from "./uniformSample";
45
45
  import { MarkdownUrlDetector, UrlDetector } from "./url-detector";
46
46
 
47
+ export const NAMELESS_COLUMN_PREFIX = "__m_column__";
47
48
  // Artificial limit to display long strings
49
+ export const SELECT_ID = "__select__";
48
50
  const MAX_STRING_LENGTH = 50;
49
- const SELECT_ID = "__select__";
50
51
 
51
52
  function inferDataType(value: unknown): [type: DataType, displayType: string] {
52
53
  if (typeof value === "string") {
@@ -106,8 +107,6 @@ export function inferFieldTypes<T>(items: T[]): FieldTypesWithExternalType {
106
107
  return Objects.entries(fieldTypes);
107
108
  }
108
109
 
109
- export const NAMELESS_COLUMN_PREFIX = "__m_column__";
110
-
111
110
  export function generateColumns<T>({
112
111
  rowHeaders,
113
112
  selection,
@@ -192,7 +191,7 @@ export function generateColumns<T>({
192
191
  accessorFn: (row) => {
193
192
  return row[key as keyof T];
194
193
  },
195
-
194
+ enableHiding: !rowHeadersSet.has(key) && key !== "",
196
195
  header: ({ column, table }) => {
197
196
  const stats = chartSpecModel?.getColumnStats(key);
198
197
  const dtype = column.columnDef.meta?.dtype;
@@ -16,7 +16,11 @@ import {
16
16
  ContextMenuTrigger,
17
17
  } from "../ui/context-menu";
18
18
  import { DATA_CELL_ID } from "./cell-utils";
19
- import { Filter } from "./filters";
19
+ import {
20
+ Filter,
21
+ isMembershipFilterType,
22
+ type MembershipFilterType,
23
+ } from "./filters";
20
24
  import { selectedCellsAtom } from "./range-focus/atoms";
21
25
  import { getClipboardContent, getRawValue } from "./utils";
22
26
 
@@ -97,15 +101,21 @@ export const CellContextMenu = <TData,>({
97
101
  };
98
102
 
99
103
  const column = cell.column;
100
- const canFilter = column.getCanFilter() && column.columnDef.meta?.filterType;
104
+ const filterType = column.columnDef.meta?.filterType;
105
+ const membershipFilterType: MembershipFilterType | undefined =
106
+ column.getCanFilter() && filterType && isMembershipFilterType(filterType)
107
+ ? filterType
108
+ : undefined;
101
109
 
102
- const handleFilterCell = (operator: "in" | "not_in") => {
103
- column.setFilterValue(
104
- Filter.select({
105
- options: [rawValue],
106
- operator,
107
- }),
108
- );
110
+ const handleFilterCell = (
111
+ type: MembershipFilterType,
112
+ operator: "in" | "not_in",
113
+ ) => {
114
+ const filter =
115
+ type === "number"
116
+ ? Filter.number({ operator, values: [rawValue] })
117
+ : Filter.text({ operator, values: [rawValue] });
118
+ column.setFilterValue(filter);
109
119
  };
110
120
 
111
121
  return (
@@ -120,14 +130,18 @@ export const CellContextMenu = <TData,>({
120
130
  Copy selected cells
121
131
  </ContextMenuItem>
122
132
  )}
123
- {canFilter && (
133
+ {membershipFilterType && (
124
134
  <>
125
135
  <ContextMenuSeparator />
126
- <ContextMenuItem onClick={() => handleFilterCell("in")}>
136
+ <ContextMenuItem
137
+ onClick={() => handleFilterCell(membershipFilterType, "in")}
138
+ >
127
139
  <FilterIcon className="mo-dropdown-icon h-3 w-3" />
128
140
  Filter by this value
129
141
  </ContextMenuItem>
130
- <ContextMenuItem onClick={() => handleFilterCell("not_in")}>
142
+ <ContextMenuItem
143
+ onClick={() => handleFilterCell(membershipFilterType, "not_in")}
144
+ >
131
145
  <FilterIcon className="mo-dropdown-icon h-3 w-3" />
132
146
  Remove rows with this value
133
147
  </ContextMenuItem>
@@ -5,6 +5,7 @@
5
5
  // https://github.com/TanStack/table/issues/5567
6
6
 
7
7
  import {
8
+ type Column,
8
9
  type ColumnDef,
9
10
  type ColumnFiltersState,
10
11
  ColumnPinning,
@@ -16,12 +17,15 @@ import {
16
17
  type PaginationState,
17
18
  type RowSelectionState,
18
19
  type SortingState,
20
+ type Table as TanstackTable,
19
21
  useReactTable,
20
22
  } from "@tanstack/react-table";
21
23
  import React, { memo } from "react";
22
24
  import { useLocale } from "react-aria";
23
25
 
26
+ import { Button } from "@/components/ui/button";
24
27
  import { Table } from "@/components/ui/table";
28
+ import { Banner } from "@/plugins/impl/common/error-banner";
25
29
  import type {
26
30
  CalculateTopKRows,
27
31
  GetRowIds,
@@ -41,7 +45,13 @@ import { ColumnFormattingFeature } from "./column-formatting/feature";
41
45
  import { ColumnWrappingFeature } from "./column-wrapping/feature";
42
46
  import { CopyColumnFeature } from "./copy-column/feature";
43
47
  import type { ExportActionProps } from "./export-actions";
48
+ import {
49
+ type AddFilterRequest,
50
+ FilterEditorProvider,
51
+ } from "./filter-editor-context";
52
+ import { buildEditorSnapshot } from "./filter-pill-editor";
44
53
  import { FilterPills } from "./filter-pills";
54
+ import type { Snapshot } from "./filters";
45
55
  import { FocusRowFeature } from "./focus-row/feature";
46
56
  import { useColumnPinning } from "./hooks/use-column-pinning";
47
57
  import { useScrollContainerHeight } from "./hooks/use-scroll-container-height";
@@ -56,6 +66,10 @@ import {
56
66
  type TooManyRows,
57
67
  } from "./types";
58
68
  import { getStableRowId } from "./utils";
69
+ import {
70
+ getUserColumnVisibilityCounts,
71
+ useColumnVisibility,
72
+ } from "./hooks/use-column-visibility";
59
73
 
60
74
  interface DataTableProps<TData> extends Partial<ExportActionProps> {
61
75
  wrapperClassName?: string;
@@ -73,6 +87,7 @@ interface DataTableProps<TData> extends Partial<ExportActionProps> {
73
87
  // JSON-serialized size of the currently-rendered data. Forwarded to
74
88
  // ExportMenu so hosts can size-gate the Export button via downloadSizeLimitAtom.
75
89
  sizeBytes?: number | null;
90
+ sizeBytesIsLoading?: boolean;
76
91
  totalColumns: number;
77
92
  pagination?: boolean;
78
93
  manualPagination?: boolean; // server-side pagination
@@ -100,6 +115,7 @@ interface DataTableProps<TData> extends Partial<ExportActionProps> {
100
115
  // Columns
101
116
  freezeColumnsLeft?: string[];
102
117
  freezeColumnsRight?: string[];
118
+ hiddenColumns?: string[];
103
119
  toggleDisplayHeader?: () => void;
104
120
  // Row viewer panel
105
121
  viewedRowIdx?: number;
@@ -112,6 +128,7 @@ interface DataTableProps<TData> extends Partial<ExportActionProps> {
112
128
  togglePanel?: (panelType: PanelType) => void;
113
129
  isPanelOpen?: (panelType: PanelType) => boolean;
114
130
  isAnyPanelOpen?: boolean;
131
+ renderTableExplorerPanel?: (table: TanstackTable<TData>) => React.ReactNode;
115
132
  }
116
133
 
117
134
  const DataTableInternal = <TData,>({
@@ -125,6 +142,7 @@ const DataTableInternal = <TData,>({
125
142
  totalColumns,
126
143
  totalRows,
127
144
  sizeBytes,
145
+ sizeBytesIsLoading,
128
146
  manualSorting = false,
129
147
  sorting,
130
148
  setSorting,
@@ -151,6 +169,7 @@ const DataTableInternal = <TData,>({
151
169
  reloading,
152
170
  freezeColumnsLeft,
153
171
  freezeColumnsRight,
172
+ hiddenColumns,
154
173
  toggleDisplayHeader,
155
174
  showChartBuilder,
156
175
  isChartBuilderOpen,
@@ -161,6 +180,7 @@ const DataTableInternal = <TData,>({
161
180
  isAnyPanelOpen,
162
181
  viewedRowIdx,
163
182
  onViewedRowChange,
183
+ renderTableExplorerPanel,
164
184
  }: DataTableProps<TData>) => {
165
185
  const [showLoadingBar, setShowLoadingBar] = React.useState<boolean>(false);
166
186
  const { locale } = useLocale();
@@ -169,6 +189,8 @@ const DataTableInternal = <TData,>({
169
189
  freezeColumnsLeft,
170
190
  freezeColumnsRight,
171
191
  );
192
+ const { columnVisibility, setColumnVisibility } =
193
+ useColumnVisibility(hiddenColumns);
172
194
 
173
195
  // Show loading bar only after a short delay to prevent flickering
174
196
  React.useEffect(() => {
@@ -260,6 +282,8 @@ const DataTableInternal = <TData,>({
260
282
  enableMultiCellSelection: selection === "multi-cell",
261
283
  // pinning
262
284
  onColumnPinningChange: setColumnPinning,
285
+ // col visibility
286
+ onColumnVisibilityChange: setColumnVisibility,
263
287
  // focus row
264
288
  enableFocusRow: true,
265
289
  onFocusRowChange: onViewedRowChange,
@@ -277,6 +301,7 @@ const DataTableInternal = <TData,>({
277
301
  { pagination: { pageIndex: 0, pageSize: data.length } }),
278
302
  rowSelection: rowSelection ?? {},
279
303
  cellSelection: cellSelection ?? [],
304
+ columnVisibility,
280
305
  cellStyling,
281
306
  columnPinning: columnPinning,
282
307
  cellHoverTemplate: hoverTemplate,
@@ -289,67 +314,111 @@ const DataTableInternal = <TData,>({
289
314
 
290
315
  const tableRef = useScrollContainerHeight({ maxHeight, virtualize });
291
316
 
317
+ const [addFilterSnapshot, setAddFilterSnapshot] =
318
+ React.useState<Snapshot | null>(null);
319
+
320
+ // useMemo instead of useCallback because need to pass it as object
321
+ const filterEditor = React.useMemo(
322
+ () => ({
323
+ requestAddFilter: (request: AddFilterRequest) => {
324
+ const column = table.getColumn(request.columnId);
325
+ if (!column) {
326
+ return;
327
+ }
328
+ setAddFilterSnapshot(
329
+ buildEditorSnapshot(column as Column<unknown, unknown>, {
330
+ operator: request.operator,
331
+ }),
332
+ );
333
+ },
334
+ }),
335
+ [table],
336
+ );
337
+
338
+ const visibilityCounts = getUserColumnVisibilityCounts(table);
339
+ const allUserColumnsHidden =
340
+ visibilityCounts.total > 0 && visibilityCounts.visible === 0;
341
+
292
342
  return (
293
- <div className={cn(wrapperClassName, "flex flex-col space-y-1")}>
294
- <FilterPills
295
- filters={filters}
296
- table={table}
297
- calculateTopKRows={calculateTopKRows}
298
- />
299
- <CellSelectionProvider>
300
- <div
301
- part="table-wrapper"
302
- className={cn(className || "rounded-md border overflow-hidden")}
303
- >
304
- <TableTopBar
305
- enableSearch={enableSearch}
306
- searchQuery={searchQuery}
307
- onSearchQueryChange={onSearchQueryChange}
308
- reloading={reloading}
309
- showChartBuilder={showChartBuilder}
310
- isChartBuilderOpen={isChartBuilderOpen}
311
- toggleDisplayHeader={toggleDisplayHeader}
312
- showTableExplorer={showTableExplorer}
313
- togglePanel={togglePanel}
314
- isAnyPanelOpen={isAnyPanelOpen}
315
- downloadAs={downloadAs}
316
- sizeBytes={sizeBytes}
317
- />
318
- <Table
319
- className={cn(
320
- "relative",
321
- columns.length <= AUTO_WIDTH_MAX_COLUMNS ? "w-auto" : "w-full",
322
- )}
323
- ref={tableRef}
343
+ <FilterEditorProvider value={filterEditor}>
344
+ <div className={cn(wrapperClassName, "flex flex-col space-y-1")}>
345
+ <FilterPills
346
+ filters={filters}
347
+ table={table}
348
+ calculateTopKRows={calculateTopKRows}
349
+ addFilterSnapshot={addFilterSnapshot}
350
+ onAddFilterSnapshotChange={setAddFilterSnapshot}
351
+ />
352
+ {renderTableExplorerPanel?.(table)}
353
+ <CellSelectionProvider>
354
+ <div
355
+ part="table-wrapper"
356
+ className={cn(className || "rounded-md border overflow-hidden")}
324
357
  >
325
- {showLoadingBar && (
326
- <thead className="absolute top-0 left-0 h-[3px] w-1/2 bg-primary animate-slide" />
358
+ <TableTopBar
359
+ enableSearch={enableSearch}
360
+ searchQuery={searchQuery}
361
+ onSearchQueryChange={onSearchQueryChange}
362
+ reloading={reloading}
363
+ showChartBuilder={showChartBuilder}
364
+ isChartBuilderOpen={isChartBuilderOpen}
365
+ toggleDisplayHeader={toggleDisplayHeader}
366
+ showTableExplorer={showTableExplorer}
367
+ togglePanel={togglePanel}
368
+ isAnyPanelOpen={isAnyPanelOpen}
369
+ downloadAs={downloadAs}
370
+ sizeBytes={sizeBytes}
371
+ sizeBytesIsLoading={sizeBytesIsLoading}
372
+ />
373
+ {allUserColumnsHidden && (
374
+ <Banner className="mb-1 mx-2 rounded flex items-center justify-between">
375
+ <span>All columns are hidden.</span>
376
+ <Button
377
+ variant="link"
378
+ size="xs"
379
+ onClick={() => table.resetColumnVisibility(true)}
380
+ >
381
+ Unhide all
382
+ </Button>
383
+ </Banner>
327
384
  )}
328
- {renderTableHeader(table, virtualize || Boolean(maxHeight))}
329
- <DataTableBody
385
+ <Table
386
+ className={cn(
387
+ "relative",
388
+ columns.length <= AUTO_WIDTH_MAX_COLUMNS ? "w-auto" : "w-full",
389
+ )}
390
+ ref={tableRef}
391
+ >
392
+ {showLoadingBar && (
393
+ <thead className="absolute top-0 left-0 h-[3px] w-1/2 bg-primary animate-slide" />
394
+ )}
395
+ {renderTableHeader(table, virtualize || Boolean(maxHeight))}
396
+ <DataTableBody
397
+ table={table}
398
+ columns={columns}
399
+ rowViewerPanelOpen={rowViewerPanelOpen}
400
+ getRowIndex={getPaginatedRowIndex}
401
+ viewedRowIdx={viewedRowIdx}
402
+ virtualize={virtualize}
403
+ />
404
+ </Table>
405
+ <TableBottomBar
406
+ part="table-footer"
407
+ className="pt-1.5 pb-0.5 border-t border-border"
408
+ totalColumns={totalColumns}
409
+ pagination={pagination}
410
+ selection={selection}
411
+ onRowSelectionChange={onRowSelectionChange}
330
412
  table={table}
331
- columns={columns}
332
- rowViewerPanelOpen={rowViewerPanelOpen}
333
- getRowIndex={getPaginatedRowIndex}
334
- viewedRowIdx={viewedRowIdx}
335
- virtualize={virtualize}
413
+ getRowIds={getRowIds}
414
+ showPageSizeSelector={showPageSizeSelector}
415
+ tableLoading={reloading}
416
+ togglePanel={togglePanel}
336
417
  />
337
- </Table>
338
- <TableBottomBar
339
- part="table-footer"
340
- className="pt-1.5 pb-0.5 border-t border-border"
341
- totalColumns={totalColumns}
342
- pagination={pagination}
343
- selection={selection}
344
- onRowSelectionChange={onRowSelectionChange}
345
- table={table}
346
- getRowIds={getRowIds}
347
- showPageSizeSelector={showPageSizeSelector}
348
- tableLoading={reloading}
349
- />
350
- </div>
351
- </CellSelectionProvider>
352
- </div>
418
+ </div>
419
+ </CellSelectionProvider>
420
+ </div>
421
+ </FilterEditorProvider>
353
422
  );
354
423
  };
355
424
 
@@ -11,11 +11,11 @@ import type { DateValue, TimeValue } from "react-aria-components";
11
11
  import { TimeField } from "@/components/ui/date-input";
12
12
  import { DatePicker, DateRangePicker } from "@/components/ui/date-picker";
13
13
  import {
14
- dateToISODate,
15
- dateToISODateTime,
16
- dateToISOTime,
17
- type FilterType,
18
- } from "./filters";
14
+ dateToLocalISODate,
15
+ dateToLocalISODateTime,
16
+ dateToLocalISOTime,
17
+ } from "@/utils/dates";
18
+ import type { FilterType } from "./filters";
19
19
 
20
20
  export type DateLikeFilterType = Extract<
21
21
  FilterType,
@@ -28,11 +28,11 @@ function dateToAria(
28
28
  ): DateValue | TimeValue {
29
29
  switch (filterType) {
30
30
  case "date":
31
- return parseDate(dateToISODate(d));
31
+ return parseDate(dateToLocalISODate(d));
32
32
  case "datetime":
33
- return parseDateTime(dateToISODateTime(d));
33
+ return parseDateTime(dateToLocalISODateTime(d));
34
34
  case "time":
35
- return parseTime(dateToISOTime(d));
35
+ return parseTime(dateToLocalISOTime(d));
36
36
  }
37
37
  }
38
38
 
@@ -128,11 +128,11 @@ export function parsePastedDate(
128
128
  return parsed;
129
129
  }
130
130
 
131
- function parsePastedRange(
131
+ export function parsePastedRange(
132
132
  filterType: DateLikeFilterType,
133
133
  text: string,
134
134
  ): { min: Date; max: Date } | undefined {
135
- const parts = text.split(/\s+(?:-|–|—|to)\s+/i);
135
+ const parts = text.split(/\s+(?:-|–|—|to|and)\s+/i);
136
136
  if (parts.length === 2) {
137
137
  const min = parsePastedDate(filterType, parts[0]);
138
138
  const max = parsePastedDate(filterType, parts[1]);
@@ -194,6 +194,7 @@ export const DateLikeInput = ({
194
194
  key={seedKey}
195
195
  aria-label={ariaLabel}
196
196
  defaultValue={seedValue as Time | undefined}
197
+ hourCycle={24}
197
198
  onChange={handleChange}
198
199
  className={className}
199
200
  />
@@ -211,6 +212,7 @@ export const DateLikeInput = ({
211
212
  aria-label={ariaLabel}
212
213
  defaultValue={seedValue as CalendarDateTime | undefined}
213
214
  granularity="second"
215
+ hourCycle={24}
214
216
  onChange={handleChange}
215
217
  className={className}
216
218
  />
@@ -316,6 +318,7 @@ export const DateLikeRangeInput = ({
316
318
  | undefined
317
319
  }
318
320
  granularity="second"
321
+ hourCycle={24}
319
322
  onChange={handleChange}
320
323
  className={className}
321
324
  />
@@ -91,6 +91,7 @@ export interface ExportActionProps {
91
91
  // marimo-lsp inside VS Code) declares a download size cap. Null/undefined
92
92
  // means "no info" and the gate stays disabled (fail-open).
93
93
  sizeBytes?: number | null;
94
+ sizeBytesIsLoading?: boolean;
94
95
  }
95
96
 
96
97
  const labelForDownloadFormat = (format: DownloadFormat): string =>
@@ -100,13 +101,19 @@ const labelForCopyFormat = (format: CopyFormat): string =>
100
101
 
101
102
  export const ExportMenu: React.FC<ExportActionProps> = (props) => {
102
103
  const { locale } = useLocale();
103
- const [open, setOpen] = React.useState(false);
104
+ const [downloadMenuOpen, setDownloadMenuOpen] = React.useState(false);
104
105
  const policy = useAtomValue(downloadSizeLimitAtom);
105
- const disabled = !!(
106
+ const overLimit = !!(
106
107
  policy &&
107
108
  props.sizeBytes != null &&
108
109
  props.sizeBytes > policy.limitBytes
109
110
  );
111
+ const disabled = !!(policy && (props.sizeBytesIsLoading || overLimit));
112
+ const tooltipContent = !disabled
113
+ ? "Export"
114
+ : props.sizeBytesIsLoading
115
+ ? "Checking download size…"
116
+ : policy?.unavailableMessage;
110
117
 
111
118
  const button = (
112
119
  <Button
@@ -116,7 +123,7 @@ export const ExportMenu: React.FC<ExportActionProps> = (props) => {
116
123
  disabled={disabled}
117
124
  className={cn(
118
125
  "print:hidden text-xs gap-1",
119
- open ? "text-primary" : "text-muted-foreground",
126
+ downloadMenuOpen ? "text-primary" : "text-muted-foreground",
120
127
  )}
121
128
  >
122
129
  <DownloadIcon className="w-3.5 h-3.5" />
@@ -248,10 +255,14 @@ export const ExportMenu: React.FC<ExportActionProps> = (props) => {
248
255
  };
249
256
 
250
257
  return (
251
- <DropdownMenu modal={false} open={open} onOpenChange={setOpen}>
258
+ <DropdownMenu
259
+ modal={false}
260
+ open={downloadMenuOpen}
261
+ onOpenChange={setDownloadMenuOpen}
262
+ >
252
263
  <Tooltip
253
- content={disabled ? policy?.unavailableMessage : "Export"}
254
- open={open ? false : undefined}
264
+ content={tooltipContent}
265
+ open={downloadMenuOpen ? false : undefined}
255
266
  >
256
267
  <DropdownMenuTrigger asChild={true} disabled={disabled}>
257
268
  <span tabIndex={disabled ? 0 : -1} className="inline-flex">
@@ -7,7 +7,6 @@ import { useMemo, useState } from "react";
7
7
  import { useAsyncData } from "@/hooks/useAsyncData";
8
8
  import { ErrorBanner } from "@/plugins/impl/common/error-banner";
9
9
  import type { CalculateTopKRows } from "@/plugins/impl/DataTablePlugin";
10
- import { cn } from "@/utils/cn";
11
10
  import { Logger } from "@/utils/Logger";
12
11
  import { Sets } from "@/utils/sets";
13
12
  import { smartMatch } from "@/utils/smartMatch";
@@ -24,6 +23,7 @@ import {
24
23
  import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
25
24
  import { SentinelCell } from "./sentinel-cell";
26
25
  import { detectSentinel, stringifyUnknownValue } from "./utils";
26
+ import { CompactChipRow } from "./value-chips";
27
27
 
28
28
  const TOP_K_ROWS = 30;
29
29
 
@@ -42,19 +42,14 @@ export const FilterByValuesPicker = <TData, TValue>({
42
42
  onChange,
43
43
  creatable = false,
44
44
  }: Props<TData, TValue>) => {
45
- const [open, setOpen] = useState(false);
45
+ const [open, setOpen] = useState(chosenValues.length === 0);
46
46
 
47
47
  const chosenValuesSet = useMemo(() => new Set(chosenValues), [chosenValues]);
48
48
 
49
- const selectedValuesStr = useMemo(() => {
50
- if (chosenValuesSet.size === 0) {
51
- return "Select values…";
52
- }
53
- const items = [...chosenValuesSet].map((v) =>
54
- stringifyUnknownValue({ value: v }),
55
- );
56
- return `[${items.join(", ")}]`;
57
- }, [chosenValuesSet]);
49
+ const displayItems = useMemo(
50
+ () => [...chosenValuesSet].map((v) => stringifyUnknownValue({ value: v })),
51
+ [chosenValuesSet],
52
+ );
58
53
 
59
54
  return (
60
55
  <Popover open={open} onOpenChange={setOpen}>
@@ -65,14 +60,13 @@ export const FilterByValuesPicker = <TData, TValue>({
65
60
  size="xs"
66
61
  className="h-6 mb-1 w-full justify-between font-normal"
67
62
  >
68
- <span
69
- className={cn(
70
- "truncate",
71
- chosenValuesSet.size === 0 && "text-muted-foreground",
72
- )}
73
- >
74
- {selectedValuesStr}
75
- </span>
63
+ {displayItems.length === 0 ? (
64
+ <span className="truncate text-muted-foreground">
65
+ Select values…
66
+ </span>
67
+ ) : (
68
+ <CompactChipRow items={displayItems} max={3} />
69
+ )}
76
70
  <ChevronDownIcon className="h-4 w-4 opacity-50 shrink-0" />
77
71
  </Button>
78
72
  </PopoverTrigger>
@@ -0,0 +1,34 @@
1
+ /* Copyright 2026 Marimo. All rights reserved. */
2
+
3
+ /**
4
+ * Lets descendants of `DataTable` (column headers, etc.) ask the table to open
5
+ * the filter pill editor for a given column. The table owns the pending
6
+ * snapshot state and renders the editor anchored under the pills strip's
7
+ * `+` button; consumers only fire intent via `requestAddFilter`.
8
+ *
9
+ * `useFilterEditor()` returns `null` outside a provider, which callers treat as
10
+ * "filter editor not available" and hide the corresponding menu items.
11
+ */
12
+
13
+ import { createContext, useContext } from "react";
14
+ import type { OperatorType } from "@/plugins/impl/data-frames/utils/operators";
15
+
16
+ export interface AddFilterRequest {
17
+ columnId: string;
18
+ /** Pre-select an operator (e.g. `"in"` for "Filter by values"); defaults to the column dtype's default. */
19
+ operator?: OperatorType;
20
+ }
21
+
22
+ interface FilterEditorContextValue {
23
+ requestAddFilter: (request: AddFilterRequest) => void;
24
+ }
25
+
26
+ const FilterEditorContext = createContext<FilterEditorContextValue | null>(
27
+ null,
28
+ );
29
+
30
+ export const FilterEditorProvider = FilterEditorContext.Provider;
31
+
32
+ export function useFilterEditor(): FilterEditorContextValue | null {
33
+ return useContext(FilterEditorContext);
34
+ }