@marimo-team/islands 0.23.9-dev3 → 0.23.9-dev5

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 (242) hide show
  1. package/dist/{ConnectedDataExplorerComponent-2lBNiUv6.js → ConnectedDataExplorerComponent-OzrfMM5L.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-BDI3FMI8.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-BKxrBMod.js → code-visibility-DY2PjKMU.js} +7200 -7488
  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-DQ5qjo_Q.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-DqRY9naW.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-CiSinpSR.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-CZD2z6X2.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 +1145 -989
  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-IU93XzmY.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-5qJjMRKh.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-BMyi2UMr.js → reveal-component-Bq1iwOTq.js} +28 -28
  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-a6DaqW__.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-ZVVIBmdk.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-C008zUPi.js} +2 -2
  160. package/dist/{useDateFormatter-B_9k85Ex.js → useDateFormatter-BA4FCquG.js} +2 -2
  161. package/dist/{useDeepCompareMemoize-Dt98v2ua.js → useDeepCompareMemoize-BrA3_n61.js} +1 -1
  162. package/dist/{useIframeCapabilities-BkYHTrss.js → useIframeCapabilities-C4JTXTIh.js} +1 -1
  163. package/dist/{useLifecycle-BF6-z62y.js → useLifecycle-BNaoJ5a4.js} +4 -4
  164. package/dist/{useTheme-DykuNHR2.js → useTheme-7O0YWlE5.js} +3 -3
  165. package/dist/{vega-component-cSdqoAxe.js → vega-component-DJNmOdUj.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 +30 -6
  171. package/src/components/data-table/__tests__/TableBottomBar.test.tsx +73 -0
  172. package/src/components/data-table/__tests__/column-header.test.tsx +110 -277
  173. package/src/components/data-table/__tests__/data-table.test.tsx +52 -1
  174. package/src/components/data-table/__tests__/date-filter-inputs.test.tsx +33 -0
  175. package/src/components/data-table/__tests__/filter-pill-editor.test.tsx +75 -38
  176. package/src/components/data-table/__tests__/filter-pills.test.tsx +287 -0
  177. package/src/components/data-table/__tests__/filter-test-utils.ts +47 -0
  178. package/src/components/data-table/__tests__/filters.test.ts +5 -5
  179. package/src/components/data-table/__tests__/header-items.test.tsx +47 -1
  180. package/src/components/data-table/__tests__/useColumnVisibility.test.ts +42 -0
  181. package/src/components/data-table/add-filter-button.tsx +85 -0
  182. package/src/components/data-table/column-explorer-panel/column-explorer.tsx +7 -1
  183. package/src/components/data-table/column-header.tsx +94 -691
  184. package/src/components/data-table/columns.tsx +3 -4
  185. package/src/components/data-table/context-menu.tsx +26 -12
  186. package/src/components/data-table/data-table.tsx +118 -56
  187. package/src/components/data-table/date-filter-inputs.tsx +13 -10
  188. package/src/components/data-table/filter-by-values-picker.tsx +13 -19
  189. package/src/components/data-table/filter-editor-context.tsx +34 -0
  190. package/src/components/data-table/filter-pill-editor.tsx +152 -175
  191. package/src/components/data-table/filter-pills.tsx +190 -153
  192. package/src/components/data-table/filters/builders.ts +102 -0
  193. package/src/components/data-table/filters/defaults.ts +31 -0
  194. package/src/components/data-table/filters/format.ts +131 -0
  195. package/src/components/data-table/filters/guards.ts +51 -0
  196. package/src/components/data-table/filters/index.ts +7 -0
  197. package/src/components/data-table/filters/operators.ts +76 -0
  198. package/src/components/data-table/filters/serialize.ts +186 -0
  199. package/src/components/data-table/filters/types.ts +33 -0
  200. package/src/components/data-table/header-items.tsx +25 -85
  201. package/src/components/data-table/hooks/use-column-visibility.ts +42 -0
  202. package/src/components/data-table/pagination.tsx +16 -3
  203. package/src/components/data-table/value-chips.tsx +52 -0
  204. package/src/components/ui/number-field.tsx +13 -1
  205. package/src/plugins/impl/DataTablePlugin.tsx +4 -0
  206. package/src/utils/dates.ts +39 -0
  207. package/dist/ErrorBoundary-D3wrPNma.js +0 -167
  208. package/dist/architecture-7HQA4BMR-CS9jOrqM.js +0 -6
  209. package/dist/dist-21ButRCu.js +0 -8
  210. package/dist/dist-B--tLnAP.js +0 -5
  211. package/dist/dist-BoHGySTM.js +0 -5
  212. package/dist/dist-ByAz19Qc.js +0 -5
  213. package/dist/dist-C1Ap5CYU.js +0 -5
  214. package/dist/dist-C93EysN4.js +0 -5
  215. package/dist/dist-CY-lVor6.js +0 -8
  216. package/dist/dist-CYDuv4bR.js +0 -8
  217. package/dist/dist-Cfo5EE2t.js +0 -6
  218. package/dist/dist-CjivSDvN.js +0 -5
  219. package/dist/dist-Cqwx-MH7.js +0 -5
  220. package/dist/dist-DbpcoFAV.js +0 -6
  221. package/dist/dist-FUNenbiQ.js +0 -5
  222. package/dist/dist-zhSud5X3.js +0 -8
  223. package/dist/mermaid-4DMBBIKO-B7VQMwJx.js +0 -6
  224. package/dist/react-vega-Cavbrg4l.js +0 -9
  225. package/dist/stex-ChDHQs3R.js +0 -4
  226. package/src/components/data-table/__tests__/column-header.test.ts +0 -65
  227. package/src/components/data-table/filters.ts +0 -386
  228. /package/dist/{_baseFor-BGiY-cm1.js → _baseFor-4jw-lnCC.js} +0 -0
  229. /package/dist/{clsx-CyyyQ8Ue.js → clsx-CIWA5tNO.js} +0 -0
  230. /package/dist/{defaultLocale-DoeErsX2.js → defaultLocale-BoHTsDG6.js} +0 -0
  231. /package/dist/{defaultLocale-BpsHxBd7.js → defaultLocale-u-3osm0P.js} +0 -0
  232. /package/dist/{dist-CCADb07R.js → dist-DNdhYsgW.js} +0 -0
  233. /package/dist/{emotion-is-prop-valid.esm-DtW2o230.js → emotion-is-prop-valid.esm-DzSb5hsH.js} +0 -0
  234. /package/dist/{invariant-UcGKQEhF.js → invariant-wRzNXIsJ.js} +0 -0
  235. /package/dist/{jsx-runtime-COBk7ree.js → jsx-runtime-DebpN0FN.js} +0 -0
  236. /package/dist/{main-CThhXnXU.js → main-Tj_-QTyF.js} +0 -0
  237. /package/dist/{micromark-factory-space-CwHmg6iz.js → micromark-factory-space-DF2w36zS.js} +0 -0
  238. /package/dist/{ordinal-B43ZeR68.js → ordinal-ArJavP1Q.js} +0 -0
  239. /package/dist/{purify.es-DT70lfR0.js → purify.es-H92eMd9-.js} +0 -0
  240. /package/dist/{range-BOiA8qqU.js → range-C-rmrM1O.js} +0 -0
  241. /package/dist/{react-dom-BWRJ_g_k.js → react-dom-BTJzcVJ9.js} +0 -0
  242. /package/dist/{stex-DrxP7bb3.js → stex-BIsgBmK4.js} +0 -0
@@ -2,71 +2,28 @@
2
2
  "use no memo";
3
3
 
4
4
  import type { Column, Table } from "@tanstack/react-table";
5
- import {
6
- EllipsisIcon,
7
- FilterIcon,
8
- MinusIcon,
9
- TextIcon,
10
- XIcon,
11
- } from "lucide-react";
12
- import { useState } from "react";
5
+ import { EllipsisIcon, FilterIcon, ListFilterIcon } from "lucide-react";
13
6
  import { useLocale } from "react-aria";
14
7
  import {
15
8
  DropdownMenu,
16
9
  DropdownMenuContent,
17
10
  DropdownMenuItem,
18
- DropdownMenuPortal,
19
11
  DropdownMenuSeparator,
20
- DropdownMenuSub,
21
- DropdownMenuSubContent,
22
- DropdownMenuSubTrigger,
23
12
  DropdownMenuTrigger,
24
13
  } from "@/components/ui/dropdown-menu";
25
14
  import type { CalculateTopKRows } from "@/plugins/impl/DataTablePlugin";
26
- import type { OperatorType } from "@/plugins/impl/data-frames/utils/operators";
27
- import { logNever } from "@/utils/assertNever";
28
15
  import { cn } from "@/utils/cn";
29
- import { Button } from "../ui/button";
30
- import { DraggablePopover } from "../ui/draggable-popover";
31
- import { Input } from "../ui/input";
32
- import { RegexInput } from "./regex-input";
33
- import { NumberField } from "../ui/number-field";
34
- import { PopoverClose } from "../ui/popover";
35
- import {
36
- Select,
37
- SelectContent,
38
- SelectItem,
39
- SelectTrigger,
40
- SelectValue,
41
- } from "../ui/select";
42
- import { FilterByValuesList } from "./filter-by-values-picker";
43
- import { OPERATOR_LABELS } from "./operator-labels";
44
- import {
45
- type ColumnFilterForType,
46
- type ColumnFilterValue,
47
- DATETIME_OPS,
48
- Filter,
49
- isDatetimeComparisonOp,
50
- isNumberComparisonOp,
51
- isTextScalarOp,
52
- NUMBER_OPS,
53
- TEXT_OPS,
54
- } from "./filters";
55
- import {
56
- type DateLikeFilterType,
57
- DateLikeInput,
58
- DateLikeRangeInput,
59
- } from "./date-filter-inputs";
16
+ import { useFilterEditor } from "./filter-editor-context";
17
+ import { EDITABLE_FILTER_TYPES, isMembershipFilterType } from "./filters";
60
18
  import {
61
19
  ClearFilterMenuItem,
62
- FilterButtons,
20
+ HideColumn,
63
21
  renderColumnPinning,
64
22
  renderColumnWrapping,
65
23
  renderCopyColumn,
66
24
  renderDataType,
67
- renderFilterByValues,
68
25
  renderFormatOptions,
69
- renderSortFilterIcon,
26
+ renderSortIcon,
70
27
  renderSorts,
71
28
  } from "./header-items";
72
29
 
@@ -88,11 +45,10 @@ export const DataTableColumnHeader = <TData, TValue>({
88
45
  subheader,
89
46
  justify,
90
47
  className,
91
- calculateTopKRows,
92
48
  table,
93
49
  }: DataTableColumnHeaderProps<TData, TValue>) => {
94
- const [isFilterValueOpen, setIsFilterValueOpen] = useState(false);
95
50
  const { locale } = useLocale();
51
+ const editor = useFilterEditor();
96
52
 
97
53
  // No header
98
54
  if (!header) {
@@ -116,68 +72,102 @@ export const DataTableColumnHeader = <TData, TValue>({
116
72
  }
117
73
 
118
74
  const hasFilter = column.getFilterValue() !== undefined;
75
+ const filterType = column.columnDef.meta?.filterType;
76
+ const canEditFilter =
77
+ editor !== null &&
78
+ column.getCanFilter() &&
79
+ filterType !== undefined &&
80
+ EDITABLE_FILTER_TYPES.has(filterType);
81
+ const canFilterByValues =
82
+ canEditFilter &&
83
+ filterType !== undefined &&
84
+ isMembershipFilterType(filterType);
119
85
 
120
86
  return (
121
- <>
87
+ <div
88
+ className={cn("group flex flex-col my-1 w-full select-none", className)}
89
+ >
122
90
  <div
123
- className={cn("group flex flex-col my-1 w-full select-none", className)}
91
+ className={cn(
92
+ "flex items-center gap-1",
93
+ justify === "right" && "flex-row-reverse",
94
+ justify === "center" && "mx-auto",
95
+ )}
124
96
  >
125
- <div
126
- className={cn(
127
- "flex items-center gap-1",
128
- justify === "right" && "flex-row-reverse",
129
- justify === "center" && "mx-auto",
130
- )}
131
- >
132
- {justify === "center" ? (
133
- <>
134
- {column.getCanSort() && <SortButton column={column} />}
135
- <span>{header}</span>
136
- </>
137
- ) : (
138
- <>
139
- <span>{header}</span>
140
- {column.getCanSort() && <SortButton column={column} />}
141
- </>
142
- )}
143
- <DropdownMenu modal={false}>
144
- <DropdownMenuTrigger asChild={true}>
145
- <button
146
- type="button"
147
- className="inline-flex items-center justify-center h-5 w-5 rounded hover:bg-(--slate-4) text-muted-foreground opacity-0 group-hover:opacity-100 focus:opacity-100 group-focus-within:opacity-100 data-[state=open]:opacity-100 data-[state=open]:text-accent-foreground"
148
- aria-label="Column options"
149
- data-testid="data-table-column-menu-button"
97
+ {justify === "center" ? (
98
+ <>
99
+ {column.getCanSort() && <SortButton column={column} />}
100
+ {hasFilter && <FilterIndicator />}
101
+ <span>{header}</span>
102
+ </>
103
+ ) : (
104
+ <>
105
+ <span>{header}</span>
106
+ {hasFilter && <FilterIndicator />}
107
+ {column.getCanSort() && <SortButton column={column} />}
108
+ </>
109
+ )}
110
+ <DropdownMenu modal={false}>
111
+ <DropdownMenuTrigger asChild={true}>
112
+ <button
113
+ type="button"
114
+ className="inline-flex items-center justify-center h-5 w-5 rounded hover:bg-(--slate-4) text-muted-foreground opacity-0 group-hover:opacity-100 focus:opacity-100 group-focus-within:opacity-100 data-[state=open]:opacity-100 data-[state=open]:text-accent-foreground"
115
+ aria-label="Column options"
116
+ data-testid="data-table-column-menu-button"
117
+ >
118
+ <EllipsisIcon className="h-3.5 w-3.5" />
119
+ </button>
120
+ </DropdownMenuTrigger>
121
+ <DropdownMenuContent align="start">
122
+ {renderDataType(column)}
123
+ {renderSorts(column, table)}
124
+ {renderCopyColumn(column)}
125
+ {renderColumnPinning(column)}
126
+ {renderColumnWrapping(column)}
127
+ {renderFormatOptions(column, locale)}
128
+ <HideColumn column={column} />
129
+ {canEditFilter && <DropdownMenuSeparator />}
130
+ {canEditFilter && (
131
+ <DropdownMenuItem
132
+ onSelect={() =>
133
+ editor.requestAddFilter({ columnId: column.id })
134
+ }
150
135
  >
151
- <EllipsisIcon className="h-3.5 w-3.5" />
152
- </button>
153
- </DropdownMenuTrigger>
154
- <DropdownMenuContent align="start">
155
- {renderDataType(column)}
156
- {renderSorts(column, table)}
157
- {renderCopyColumn(column)}
158
- {renderColumnPinning(column)}
159
- {renderColumnWrapping(column)}
160
- {renderFormatOptions(column, locale)}
161
- <DropdownMenuSeparator />
162
- {renderMenuItemFilter(column, calculateTopKRows)}
163
- {renderFilterByValues(column, setIsFilterValueOpen)}
164
- {hasFilter && <ClearFilterMenuItem column={column} />}
165
- </DropdownMenuContent>
166
- </DropdownMenu>
167
- </div>
168
- {subheader}
136
+ <FilterIcon className="mo-dropdown-icon" />
137
+ Filter
138
+ </DropdownMenuItem>
139
+ )}
140
+ {canFilterByValues && (
141
+ <DropdownMenuItem
142
+ onSelect={() =>
143
+ editor.requestAddFilter({
144
+ columnId: column.id,
145
+ operator: "in",
146
+ })
147
+ }
148
+ >
149
+ <ListFilterIcon className="mo-dropdown-icon" />
150
+ Filter by values
151
+ </DropdownMenuItem>
152
+ )}
153
+ {hasFilter && <ClearFilterMenuItem column={column} />}
154
+ </DropdownMenuContent>
155
+ </DropdownMenu>
169
156
  </div>
170
- {isFilterValueOpen && (
171
- <PopoverFilterByValues
172
- setIsFilterValueOpen={setIsFilterValueOpen}
173
- calculateTopKRows={calculateTopKRows}
174
- column={column}
175
- />
176
- )}
177
- </>
157
+ {subheader}
158
+ </div>
178
159
  );
179
160
  };
180
161
 
162
+ const FilterIndicator = () => (
163
+ <span
164
+ className="inline-flex items-center justify-center h-5 w-5 text-primary"
165
+ aria-label="Column is filtered"
166
+ >
167
+ <FilterIcon className="h-3 w-3" aria-hidden={true} />
168
+ </span>
169
+ );
170
+
181
171
  const SortButton = <TData, TValue>({
182
172
  column,
183
173
  }: {
@@ -215,594 +205,7 @@ const SortButton = <TData, TValue>({
215
205
  }
216
206
  data-testid="data-table-sort-button"
217
207
  >
218
- {renderSortFilterIcon(column)}
208
+ {renderSortIcon(column)}
219
209
  </button>
220
210
  );
221
211
  };
222
-
223
- export function renderMenuItemFilter<TData, TValue>(
224
- column: Column<TData, TValue>,
225
- calculateTopKRows?: CalculateTopKRows,
226
- ) {
227
- const canFilter = column.getCanFilter();
228
- if (!canFilter) {
229
- return null;
230
- }
231
-
232
- const filterType = column.columnDef.meta?.filterType;
233
- if (!filterType) {
234
- return null;
235
- }
236
-
237
- const filterMenuItem = (
238
- <DropdownMenuSubTrigger>
239
- <FilterIcon className="mo-dropdown-icon" />
240
- Filter
241
- </DropdownMenuSubTrigger>
242
- );
243
-
244
- if (filterType === "boolean") {
245
- return (
246
- <DropdownMenuSub>
247
- {filterMenuItem}
248
- <DropdownMenuPortal>
249
- <DropdownMenuSubContent>
250
- <BooleanFilter column={column} />
251
- </DropdownMenuSubContent>
252
- </DropdownMenuPortal>
253
- </DropdownMenuSub>
254
- );
255
- }
256
-
257
- if (filterType === "text") {
258
- return (
259
- <DropdownMenuSub>
260
- {filterMenuItem}
261
- <DropdownMenuPortal>
262
- <DropdownMenuSubContent>
263
- <TextFilterMenu
264
- column={column}
265
- calculateTopKRows={calculateTopKRows}
266
- />
267
- </DropdownMenuSubContent>
268
- </DropdownMenuPortal>
269
- </DropdownMenuSub>
270
- );
271
- }
272
-
273
- if (filterType === "number") {
274
- return (
275
- <DropdownMenuSub>
276
- {filterMenuItem}
277
- <DropdownMenuPortal>
278
- <DropdownMenuSubContent>
279
- <NumberFilterMenu column={column} />
280
- </DropdownMenuSubContent>
281
- </DropdownMenuPortal>
282
- </DropdownMenuSub>
283
- );
284
- }
285
-
286
- if (filterType === "select") {
287
- // Not implemented
288
- return null;
289
- }
290
-
291
- if (
292
- filterType === "date" ||
293
- filterType === "datetime" ||
294
- filterType === "time"
295
- ) {
296
- return (
297
- <DropdownMenuSub>
298
- {filterMenuItem}
299
- <DropdownMenuPortal>
300
- <DropdownMenuSubContent>
301
- <DateFilterMenu column={column} filterType={filterType} />
302
- </DropdownMenuSubContent>
303
- </DropdownMenuPortal>
304
- </DropdownMenuSub>
305
- );
306
- }
307
-
308
- logNever(filterType);
309
- return null;
310
- }
311
-
312
- const OperatorSelect = ({
313
- operator,
314
- options,
315
- onChange,
316
- }: {
317
- operator: OperatorType;
318
- options: readonly OperatorType[];
319
- onChange: (next: OperatorType) => void;
320
- }) => (
321
- <Select value={operator} onValueChange={(v) => onChange(v as OperatorType)}>
322
- <SelectTrigger className="border-border shadow-none! ring-0! w-full mb-0.5">
323
- <SelectValue />
324
- </SelectTrigger>
325
- <SelectContent>
326
- {options.map((op) => (
327
- <SelectItem key={op} value={op}>
328
- {OPERATOR_LABELS[op]}
329
- </SelectItem>
330
- ))}
331
- </SelectContent>
332
- </Select>
333
- );
334
-
335
- const BooleanFilter = <TData, TValue>({
336
- column,
337
- }: {
338
- column: Column<TData, TValue>;
339
- }) => {
340
- return (
341
- <>
342
- <DropdownMenuItem
343
- onClick={() =>
344
- column.setFilterValue(
345
- Filter.boolean({ value: true, operator: "is_true" }),
346
- )
347
- }
348
- >
349
- True
350
- </DropdownMenuItem>
351
- <DropdownMenuItem
352
- onClick={() =>
353
- column.setFilterValue(
354
- Filter.boolean({ value: false, operator: "is_false" }),
355
- )
356
- }
357
- >
358
- False
359
- </DropdownMenuItem>
360
- <DropdownMenuSeparator />
361
- <DropdownMenuItem
362
- onClick={() =>
363
- column.setFilterValue(Filter.boolean({ operator: "is_null" }))
364
- }
365
- >
366
- Is null
367
- </DropdownMenuItem>
368
- <DropdownMenuItem
369
- onClick={() =>
370
- column.setFilterValue(Filter.boolean({ operator: "is_not_null" }))
371
- }
372
- >
373
- Is not null
374
- </DropdownMenuItem>
375
- </>
376
- );
377
- };
378
-
379
- type NumberComparisonFilter = Extract<
380
- ColumnFilterForType<"number">,
381
- { value: number }
382
- >;
383
- const isNumberComparisonFilter = (
384
- filter: ColumnFilterForType<"number">,
385
- ): filter is NumberComparisonFilter => isNumberComparisonOp(filter.operator);
386
-
387
- export const NumberFilterMenu = <TData, TValue>({
388
- column,
389
- }: {
390
- column: Column<TData, TValue>;
391
- }) => {
392
- const currentFilter = column.getFilterValue() as
393
- | ColumnFilterForType<"number">
394
- | undefined;
395
- const hasFilter = currentFilter !== undefined;
396
-
397
- const [operator, setOperator] = useState<OperatorType>(
398
- currentFilter?.operator ?? "between",
399
- );
400
- const [min, setMin] = useState<number | undefined>(
401
- currentFilter?.operator === "between" ? currentFilter.min : undefined,
402
- );
403
- const [max, setMax] = useState<number | undefined>(
404
- currentFilter?.operator === "between" ? currentFilter.max : undefined,
405
- );
406
- const [value, setValue] = useState<number | undefined>(
407
- currentFilter !== undefined && isNumberComparisonFilter(currentFilter)
408
- ? currentFilter.value
409
- : undefined,
410
- );
411
-
412
- const isComparison = isNumberComparisonOp(operator);
413
- const isNullish = operator === "is_null" || operator === "is_not_null";
414
-
415
- const applyDisabled =
416
- (operator === "between" && (min === undefined || max === undefined)) ||
417
- (isComparison && value === undefined);
418
-
419
- const handleApply = () => {
420
- if (isNullish) {
421
- column.setFilterValue(Filter.number({ operator }));
422
- return;
423
- }
424
- if (operator === "between" && min !== undefined && max !== undefined) {
425
- column.setFilterValue(Filter.number({ operator: "between", min, max }));
426
- return;
427
- }
428
- if (isComparison && value !== undefined) {
429
- column.setFilterValue(Filter.number({ operator, value }));
430
- }
431
- };
432
-
433
- const handleClear = () => {
434
- setMin(undefined);
435
- setMax(undefined);
436
- setValue(undefined);
437
- column.setFilterValue(undefined);
438
- };
439
-
440
- const handleOperatorChange = (next: OperatorType) => {
441
- setOperator(next);
442
- };
443
-
444
- return (
445
- <div className="flex flex-col gap-1 pt-3 px-2">
446
- <OperatorSelect
447
- operator={operator}
448
- options={NUMBER_OPS}
449
- onChange={handleOperatorChange}
450
- />
451
- {operator === "between" && (
452
- <div className="flex gap-1 items-center">
453
- <NumberField
454
- value={min}
455
- onChange={setMin}
456
- aria-label="min"
457
- placeholder="min"
458
- className="shadow-none! border-border hover:shadow-none!"
459
- />
460
- <MinusIcon className="h-5 w-5 text-muted-foreground" />
461
- <NumberField
462
- value={max}
463
- onChange={setMax}
464
- aria-label="max"
465
- placeholder="max"
466
- className="shadow-none! border-border hover:shadow-none!"
467
- />
468
- </div>
469
- )}
470
- {isComparison && (
471
- <NumberField
472
- value={value}
473
- onChange={setValue}
474
- aria-label="value"
475
- placeholder="value"
476
- className="shadow-none! border-border hover:shadow-none!"
477
- />
478
- )}
479
- <FilterButtons
480
- onApply={handleApply}
481
- onClear={handleClear}
482
- clearButtonDisabled={!hasFilter}
483
- applyButtonDisabled={applyDisabled}
484
- />
485
- </div>
486
- );
487
- };
488
-
489
- type DateComparisonFilter = Extract<
490
- ColumnFilterForType<DateLikeFilterType>,
491
- { value: Date }
492
- >;
493
- const isDateComparisonFilter = (
494
- filter: ColumnFilterForType<DateLikeFilterType>,
495
- ): filter is DateComparisonFilter => isDatetimeComparisonOp(filter.operator);
496
-
497
- export const DateFilterMenu = <TData, TValue>({
498
- column,
499
- filterType,
500
- }: {
501
- column: Column<TData, TValue>;
502
- filterType: DateLikeFilterType;
503
- }) => {
504
- const currentFilter = column.getFilterValue() as
505
- | ColumnFilterForType<DateLikeFilterType>
506
- | undefined;
507
- const hasFilter = currentFilter !== undefined;
508
-
509
- const [operator, setOperator] = useState<OperatorType>(
510
- currentFilter?.operator ?? "between",
511
- );
512
- const [min, setMin] = useState<Date | undefined>(
513
- currentFilter?.operator === "between" ? currentFilter.min : undefined,
514
- );
515
- const [max, setMax] = useState<Date | undefined>(
516
- currentFilter?.operator === "between" ? currentFilter.max : undefined,
517
- );
518
- const [value, setValue] = useState<Date | undefined>(
519
- currentFilter !== undefined && isDateComparisonFilter(currentFilter)
520
- ? currentFilter.value
521
- : undefined,
522
- );
523
-
524
- const isComparison = isDatetimeComparisonOp(operator);
525
- const isNullish = operator === "is_null" || operator === "is_not_null";
526
-
527
- const applyDisabled =
528
- (operator === "between" && (min === undefined || max === undefined)) ||
529
- (isComparison && value === undefined);
530
-
531
- const buildFilter = (
532
- opts: Parameters<typeof Filter.date>[0],
533
- ): ColumnFilterForType<DateLikeFilterType> => {
534
- switch (filterType) {
535
- case "date":
536
- return Filter.date(opts);
537
- case "datetime":
538
- return Filter.datetime(opts);
539
- case "time":
540
- return Filter.time(opts);
541
- }
542
- };
543
-
544
- const handleApply = () => {
545
- if (isNullish) {
546
- column.setFilterValue(buildFilter({ operator }));
547
- return;
548
- }
549
- if (operator === "between" && min !== undefined && max !== undefined) {
550
- column.setFilterValue(buildFilter({ operator: "between", min, max }));
551
- return;
552
- }
553
- if (isComparison && value !== undefined) {
554
- column.setFilterValue(buildFilter({ operator, value }));
555
- }
556
- };
557
-
558
- const [resetKey, setResetKey] = useState(0);
559
- const handleClear = () => {
560
- setMin(undefined);
561
- setMax(undefined);
562
- setValue(undefined);
563
- setResetKey((k) => k + 1);
564
- column.setFilterValue(undefined);
565
- };
566
-
567
- const handleOperatorChange = (next: OperatorType) => {
568
- setOperator(next);
569
- };
570
-
571
- return (
572
- <div
573
- className="flex flex-col gap-1 pt-3 px-2"
574
- onKeyDownCapture={(e) => {
575
- if (e.key === "Tab") {
576
- e.stopPropagation();
577
- }
578
- }}
579
- >
580
- <OperatorSelect
581
- operator={operator}
582
- options={DATETIME_OPS}
583
- onChange={handleOperatorChange}
584
- />
585
- {operator === "between" && (
586
- <DateLikeRangeInput
587
- key={`${filterType}-${resetKey}`}
588
- filterType={filterType}
589
- min={min}
590
- max={max}
591
- onRangeChange={(nextMin, nextMax) => {
592
- setMin(nextMin);
593
- setMax(nextMax);
594
- }}
595
- className="shadow-none! border-border hover:shadow-none!"
596
- />
597
- )}
598
- {isComparison && (
599
- <DateLikeInput
600
- key={`${filterType}-${resetKey}`}
601
- filterType={filterType}
602
- value={value}
603
- onChange={setValue}
604
- aria-label="value"
605
- className="shadow-none! border-border hover:shadow-none!"
606
- />
607
- )}
608
- <FilterButtons
609
- onApply={handleApply}
610
- onClear={handleClear}
611
- clearButtonDisabled={!hasFilter}
612
- applyButtonDisabled={applyDisabled}
613
- />
614
- </div>
615
- );
616
- };
617
-
618
- export const TextFilterMenu = <TData, TValue>({
619
- column,
620
- calculateTopKRows,
621
- }: {
622
- column: Column<TData, TValue>;
623
- calculateTopKRows?: CalculateTopKRows;
624
- }) => {
625
- const currentFilter = column.getFilterValue() as
626
- | ColumnFilterForType<"text">
627
- | undefined;
628
- const hasFilter = currentFilter !== undefined;
629
-
630
- const [operator, setOperator] = useState<OperatorType>(
631
- currentFilter?.operator ?? "contains",
632
- );
633
- const [text, setText] = useState<string>(
634
- currentFilter && "text" in currentFilter ? currentFilter.text : "",
635
- );
636
- const [values, setValues] = useState<string[]>(
637
- currentFilter && "values" in currentFilter ? [...currentFilter.values] : [],
638
- );
639
-
640
- const isScalar = isTextScalarOp(operator);
641
- const isMulti = operator === "in" || operator === "not_in";
642
- const isNullish =
643
- operator === "is_null" ||
644
- operator === "is_not_null" ||
645
- operator === "is_empty";
646
-
647
- const applyDisabled =
648
- (isScalar && text === "") || (isMulti && values.length === 0);
649
-
650
- const handleApply = () => {
651
- if (isNullish) {
652
- column.setFilterValue(Filter.text({ operator }));
653
- return;
654
- }
655
- if (isScalar && text !== "") {
656
- column.setFilterValue(Filter.text({ operator, text }));
657
- return;
658
- }
659
- if (isMulti && values.length > 0) {
660
- column.setFilterValue(Filter.text({ operator, values }));
661
- }
662
- };
663
-
664
- const handleClear = () => {
665
- setText("");
666
- setValues([]);
667
- column.setFilterValue(undefined);
668
- };
669
-
670
- const handleOperatorChange = (next: OperatorType) => {
671
- setOperator(next);
672
- };
673
-
674
- return (
675
- <div className="flex flex-col gap-1 pt-3 px-2">
676
- <OperatorSelect
677
- operator={operator}
678
- options={TEXT_OPS}
679
- onChange={handleOperatorChange}
680
- />
681
- {isScalar && operator === "regex" && (
682
- <RegexInput
683
- value={text}
684
- onChange={setText}
685
- onKeyDown={(e) => {
686
- e.stopPropagation();
687
- if (e.key === "Enter") {
688
- handleApply();
689
- }
690
- }}
691
- />
692
- )}
693
- {isScalar && operator !== "regex" && (
694
- <Input
695
- type="text"
696
- icon={<TextIcon className="h-3 w-3 text-muted-foreground mb-1" />}
697
- value={text}
698
- onChange={(e) => setText(e.target.value)}
699
- placeholder="Text..."
700
- onKeyDown={(e) => {
701
- e.stopPropagation();
702
- if (e.key === "Enter") {
703
- handleApply();
704
- }
705
- }}
706
- className="shadow-none! border-border hover:shadow-none!"
707
- />
708
- )}
709
- {isMulti && (
710
- <FilterByValuesList
711
- column={column}
712
- calculateTopKRows={calculateTopKRows}
713
- chosenValues={new Set(values)}
714
- onChange={(next) => setValues(next.map(String))}
715
- creatable={true}
716
- />
717
- )}
718
- <FilterButtons
719
- onApply={handleApply}
720
- onClear={handleClear}
721
- clearButtonDisabled={!hasFilter}
722
- applyButtonDisabled={applyDisabled}
723
- />
724
- </div>
725
- );
726
- };
727
-
728
- /**
729
- * Seed the filter-by-values picker from a column's existing filter value.
730
- *
731
- * Reopening the picker should reflect what's already applied. Only `select`
732
- * filters carry checkbox-style values; other filter shapes (number, text,
733
- * etc.) seed an empty list.
734
- */
735
- export function seedFromFilter(value: ColumnFilterValue | undefined): {
736
- values: unknown[];
737
- operator: Extract<OperatorType, "in" | "not_in">;
738
- } {
739
- if (value && "type" in value && value.type === "select") {
740
- return {
741
- values: [...value.options],
742
- operator: value.operator === "not_in" ? "not_in" : "in",
743
- };
744
- }
745
- return { values: [], operator: "in" };
746
- }
747
-
748
- const PopoverFilterByValues = <TData, TValue>({
749
- setIsFilterValueOpen,
750
- calculateTopKRows,
751
- column,
752
- }: {
753
- setIsFilterValueOpen: (open: boolean) => void;
754
- calculateTopKRows?: CalculateTopKRows;
755
- column: Column<TData, TValue>;
756
- }) => {
757
- const seed = seedFromFilter(
758
- column.getFilterValue() as ColumnFilterValue | undefined,
759
- );
760
-
761
- const [chosenValues, setChosenValues] = useState<Set<unknown>>(
762
- () => new Set(seed.values),
763
- );
764
-
765
- const handleApply = () => {
766
- if (chosenValues.size === 0) {
767
- column.setFilterValue(undefined);
768
- return;
769
- }
770
- column.setFilterValue(
771
- Filter.select({
772
- options: [...chosenValues],
773
- operator: seed.operator,
774
- }),
775
- );
776
- };
777
-
778
- return (
779
- <DraggablePopover
780
- open={true}
781
- onOpenChange={(open) => !open && setIsFilterValueOpen(false)}
782
- className="w-80 p-0"
783
- >
784
- <PopoverClose className="absolute top-2 right-2">
785
- <Button
786
- variant="link"
787
- size="sm"
788
- onClick={() => setIsFilterValueOpen(false)}
789
- >
790
- <XIcon className="h-4 w-4" />
791
- </Button>
792
- </PopoverClose>
793
- <div className="flex flex-col gap-1.5 py-2">
794
- <FilterByValuesList
795
- column={column}
796
- calculateTopKRows={calculateTopKRows}
797
- chosenValues={chosenValues}
798
- onChange={(values) => setChosenValues(new Set(values))}
799
- />
800
- <FilterButtons
801
- onApply={handleApply}
802
- onClear={() => setChosenValues(new Set())}
803
- clearButtonDisabled={chosenValues.size === 0}
804
- />
805
- </div>
806
- </DraggablePopover>
807
- );
808
- };