@marimo-team/islands 0.23.9-dev2 → 0.23.9-dev4
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.
- package/dist/{ConnectedDataExplorerComponent-2lBNiUv6.js → ConnectedDataExplorerComponent-OzrfMM5L.js} +20 -20
- package/dist/ErrorBoundary-rULOrC_p.js +175 -0
- package/dist/{ImageComparisonComponent-CNHIsPDj.js → ImageComparisonComponent-CHrI72em.js} +1 -1
- package/dist/{Plot-4wn-lMVn.js → Plot-CAYS29h9.js} +1 -1
- package/dist/{_baseUniq-CxZRxRRo.js → _baseUniq-B_2Hw7zG.js} +3 -3
- package/dist/{any-language-editor-VWs_7v27.js → any-language-editor-DfdpyDv_.js} +23 -23
- package/dist/architecture-7HQA4BMR-Kyc44TmC.js +6 -0
- package/dist/{architectureDiagram-VXUJARFQ-CXVJxFhH.js → architectureDiagram-VXUJARFQ-CT2SuxNw.js} +15 -15
- package/dist/{arrays-CldYf7p7.js → arrays-sEtDRoG4.js} +1 -1
- package/dist/{blockDiagram-VD42YOAC-DGDaxR8I.js → blockDiagram-VD42YOAC-Dy7hlFla.js} +7 -7
- package/dist/{button-Dj4BTre0.js → button-C5K9fIPF.js} +2 -2
- package/dist/{c4Diagram-YG6GDRKO-C2hc6ne8.js → c4Diagram-YG6GDRKO-BXlAmZ8Z.js} +4 -4
- package/dist/{capabilities-C9rrYCzf.js → capabilities-BceAxrAW.js} +2 -2
- package/dist/{channel-BBoIVUrJ.js → channel-D_PHgcig.js} +1 -1
- package/dist/{chat-ui-D3XBept8.js → chat-ui-BDI3FMI8.js} +29 -29
- package/dist/{check-BcUIXnUT.js → check-DTbrK0zt.js} +1 -1
- package/dist/{chunk-4F5CHEZ2-BZq7Kom7.js → chunk-4F5CHEZ2-D9nGEHV8.js} +1 -1
- package/dist/{chunk-5FQGJX7Z-BOg95xG5.js → chunk-5FQGJX7Z-BNjes6Yx.js} +5 -5
- package/dist/{chunk-ABZYJK2D-D0cLy8Bb.js → chunk-ABZYJK2D-Dz0-H2B5.js} +1 -1
- package/dist/{chunk-ATLVNIR6-BXsEjlHF.js → chunk-ATLVNIR6-o0Z5MZLd.js} +1 -1
- package/dist/{chunk-B2363JML-D9-XOau1.js → chunk-B2363JML-KEJpLGGP.js} +1 -1
- package/dist/{chunk-B4BG7PRW-Q1usn6T3.js → chunk-B4BG7PRW-BL98U9B4.js} +4 -4
- package/dist/{chunk-DI55MBZ5-D1qLYNrb.js → chunk-DI55MBZ5-Dwkn0LWm.js} +4 -4
- package/dist/{chunk-EXTU4WIE-BKNXdLmD.js → chunk-EXTU4WIE-9sNjmQrB.js} +1 -1
- package/dist/{chunk-FRFDVMJY-BSBUAX7r.js → chunk-FRFDVMJY-DzQqMWrl.js} +1 -1
- package/dist/{chunk-JA3XYJ7Z-D6c6cOBG.js → chunk-JA3XYJ7Z-C32Y7Epf.js} +2 -2
- package/dist/{chunk-JZLCHNYA-BvsPHJmL.js → chunk-JZLCHNYA-C6ftyVMN.js} +4 -4
- package/dist/{chunk-N4CR4FBY-8ycT-O9a.js → chunk-N4CR4FBY-DUhGZhZs.js} +5 -5
- package/dist/{chunk-PL6DKKU2-B0MTXvyc.js → chunk-PL6DKKU2-D7km-08O.js} +1 -1
- package/dist/{chunk-QN33PNHL-Bb-eUBW3.js → chunk-QN33PNHL-0K6SDYn3.js} +1 -1
- package/dist/{chunk-QXUST7PY-DV8yRwBd.js → chunk-QXUST7PY-DMhsRpYK.js} +5 -5
- package/dist/{chunk-S3R3BYOJ-mQeCz5CE.js → chunk-S3R3BYOJ-oAe3dEbO.js} +3 -3
- package/dist/{chunk-SJTYNZTY-CEG4F0pB.js → chunk-SJTYNZTY-BkJrPRFC.js} +1 -1
- package/dist/{chunk-TCCFYFTB-d3HOqL2I.js → chunk-TCCFYFTB-D58KeXnC.js} +6 -6
- package/dist/{chunk-TQ3KTPDO-DiCtqVSi.js → chunk-TQ3KTPDO-D_yA_wAb.js} +1 -1
- package/dist/{chunk-TZMSLE5B-BqW10dHe.js → chunk-TZMSLE5B-yBKS_DQU.js} +1 -1
- package/dist/{chunk-UMXZTB3W-97iS1iEl.js → chunk-UMXZTB3W-D7uwvNjd.js} +1 -1
- package/dist/{classDiagram-2ON5EDUG--Yh__LHb.js → classDiagram-2ON5EDUG-QjoAcuFE.js} +10 -10
- package/dist/{classDiagram-v2-WZHVMYZB-BC7X7Xtc.js → classDiagram-v2-WZHVMYZB-bUCv4gu2.js} +10 -10
- package/dist/{clone-BuIIsfA8.js → clone-Q4Fqwn6q.js} +1 -1
- package/dist/{code-block-37QAKDTI-BsGy1AOJ.js → code-block-37QAKDTI-m92Yc8pv.js} +2 -2
- package/dist/{code-visibility-Dt0Aq6-t.js → code-visibility-VZebNmSs.js} +7073 -7439
- package/dist/{constants-D0gkYoE2.js → constants-T20xxyNf.js} +2 -2
- package/dist/{copy-DLf4aN7I.js → copy-BuQpJEzp.js} +2 -2
- package/dist/{dagre-6UL2VRFP-DRBWoQUw.js → dagre-6UL2VRFP-J0JKgwOt.js} +11 -11
- package/dist/{dagre-VYEPqXIV.js → dagre-By_QsQgc.js} +11 -11
- package/dist/{data-grid-overlay-editor-efe5ZagF.js → data-grid-overlay-editor-mfEJ5475.js} +2 -2
- package/dist/{diagram-PSM6KHXK-H66ATWP2.js → diagram-PSM6KHXK-DYgJuNk9.js} +18 -18
- package/dist/{diagram-QEK2KX5R-DItl5Wns.js → diagram-QEK2KX5R-CKdBR2sb.js} +14 -14
- package/dist/{diagram-S2PKOQOG-CtuW_ZuL.js → diagram-S2PKOQOG-Dpi7mo5W.js} +14 -14
- package/dist/dist-0Fif7jnk.js +5 -0
- package/dist/{dist-Dh3wkoyH.js → dist-4j4c7bjm.js} +2 -2
- package/dist/{dist-CDFZi-QD.js → dist-B3P2fFpz.js} +1 -1
- package/dist/{dist-BNyrZfqT.js → dist-B3pZ0Ab6.js} +2 -2
- package/dist/dist-B5h_9sHB.js +6 -0
- package/dist/dist-B9M6R5ye.js +5 -0
- package/dist/dist-BCt3tnck.js +8 -0
- package/dist/{dist-BrBucRXs.js → dist-BTfv03uy.js} +2 -2
- package/dist/dist-BUIJwMwn.js +8 -0
- package/dist/{dist-CYEylvZA.js → dist-BbbIBDiQ.js} +1 -1
- package/dist/{dist-KnujRhFL.js → dist-BcuoonNH.js} +4 -4
- package/dist/{dist-DJ6zJQZ4.js → dist-Bde4a2kU.js} +2 -2
- package/dist/{dist-t_qL7eB8.js → dist-Bfwsv11D.js} +2 -2
- package/dist/{dist-CNtV21T_.js → dist-BhM8gdSO.js} +4 -4
- package/dist/{dist-nuW5EDYT.js → dist-BotSqB48.js} +2 -2
- package/dist/dist-BpquMd3k.js +5 -0
- package/dist/dist-BzJsqYfz.js +5 -0
- package/dist/{dist-D029TiHd.js → dist-Bz_sYWbr.js} +2 -2
- package/dist/{dist-D3ZI9nhS.js → dist-C1BYNeCR.js} +4 -4
- package/dist/{dist-Bc5pmZIw.js → dist-C5VC_yzu.js} +1 -1
- package/dist/dist-CA5ELXAf.js +6 -0
- package/dist/dist-CLBRs6Uv.js +5 -0
- package/dist/{dist-Dhk6FMb0.js → dist-CLJWPTX2.js} +3 -3
- package/dist/{dist-C34oIrQ9.js → dist-CLUtPrdy.js} +1 -1
- package/dist/dist-CStVCMbq.js +5 -0
- package/dist/{dist-B8RaFTRF.js → dist-CUCNs1ja.js} +2 -2
- package/dist/dist-CZRIEY3Y.js +8 -0
- package/dist/{dist-UcOPnRMa.js → dist-CcXxepx6.js} +3 -3
- package/dist/dist-CuUHbFD0.js +5 -0
- package/dist/{dist-B8BjrFUE.js → dist-Cy1WxgBD.js} +5 -5
- package/dist/{dist-WdPUFc56.js → dist-D4CewLk6.js} +1 -1
- package/dist/{dist-DMZNjfX4.js → dist-DRfcqpxJ.js} +2 -2
- package/dist/dist-DV7Iabxb.js +8 -0
- package/dist/{dist-usPCDYx8.js → dist-D_bzzWBm.js} +1 -1
- package/dist/{dist-BvCfQQQE.js → dist-DgnE8F-r.js} +1 -1
- package/dist/{dist-JEhxD_cn.js → dist-DhHh0jLg.js} +1 -1
- package/dist/{dist-DGAfI2rB.js → dist-DqAWR3CS.js} +2 -2
- package/dist/{dist--sWVZwjW.js → dist-Du8WkPuU.js} +1 -1
- package/dist/dist-DuEeHMvL.js +5 -0
- package/dist/{dist-BTyJtnNg.js → dist-DxvORzUR.js} +1 -1
- package/dist/{dist-B507mf_I.js → dist-RqXTaiir.js} +2 -2
- package/dist/{dist-Yrfc6L0I.js → dist-fQ0ViXGs.js} +3 -3
- package/dist/{dist-B4LJpMEg.js → dist-h2c8sZvT.js} +1 -1
- package/dist/{dist-C2ej4eOH.js → dist-luvabDEB.js} +2 -2
- package/dist/{dist-B52GXZbd.js → dist-p2qyWijU.js} +2 -2
- package/dist/{erDiagram-Q2GNP2WA--19X2kU5.js → erDiagram-Q2GNP2WA-BU-m41EQ.js} +10 -10
- package/dist/{error-banner-CVkfBUT3.js → error-banner-5bz0L9hS.js} +3 -3
- package/dist/{esm-CWp0KQeK.js → esm-BfhQmZjp.js} +4 -4
- package/dist/{esm-DjNnlmpf.js → esm-Duie8iU-.js} +23 -23
- package/dist/{extends-vAi97cpa.js → extends-BgdxCfYu.js} +6 -6
- package/dist/{flatten-CzBvFdvC.js → flatten-Bbw7g6-K.js} +1 -1
- package/dist/{flowDiagram-NV44I4VS-DQmWlo7f.js → flowDiagram-NV44I4VS-CRoXKjGq.js} +10 -10
- package/dist/{formats-Dsy9kkZu.js → formats-DQ5qjo_Q.js} +4 -4
- package/dist/{ganttDiagram-JELNMOA3-BOGXJ8Lk.js → ganttDiagram-JELNMOA3-7mq5f9cO.js} +7 -7
- package/dist/{gitGraph-G5XIXVHT-DGlbae5m.js → gitGraph-G5XIXVHT-DiniR35k.js} +3 -3
- package/dist/{gitGraphDiagram-V2S2FVAM-DjzxfF0P.js → gitGraphDiagram-V2S2FVAM-Dfuokq6w.js} +13 -13
- package/dist/{glide-data-editor-DucgdjRo.js → glide-data-editor-DqRY9naW.js} +557 -557
- package/dist/{graphlib-CVPKjKCS.js → graphlib-Ns7y5crs.js} +5 -5
- package/dist/{hasIn-COs6vImh.js → hasIn-Deg7jl_j.js} +3 -3
- package/dist/{html-to-image-CpggM7u1.js → html-to-image-CiSinpSR.js} +109 -109
- package/dist/{info-VBDWY6EO-D2lvLLw5.js → info-VBDWY6EO-DVZvGhkQ.js} +3 -3
- package/dist/{infoDiagram-HS3SLOUP-ChNufFsP.js → infoDiagram-HS3SLOUP-CEnzWruK.js} +13 -13
- package/dist/{input-D4kjoQUB.js → input-CZD2z6X2.js} +70 -67
- package/dist/{isEmpty-Dd8mx_WL.js → isEmpty-CJJMn-QP.js} +1 -1
- package/dist/{isSymbol-BvIfMnn6.js → isSymbol-CoUCgMCM.js} +1 -1
- package/dist/{journeyDiagram-XKPGCS4Q-BO_O4Ij1.js → journeyDiagram-XKPGCS4Q-8XYSU1GI.js} +3 -3
- package/dist/{kanban-definition-3W4ZIXB7-CPpiiiWk.js → kanban-definition-3W4ZIXB7--9pT9z1R.js} +7 -7
- package/dist/{label-BLqV33b1.js → label-LWtdw5i8.js} +3 -3
- package/dist/{linear-2NnK4cxi.js → linear-B5-AFRiR.js} +2 -2
- package/dist/{loader-Dr8Qem8p.js → loader-BWLPpjKK.js} +2 -2
- package/dist/main.js +1141 -987
- package/dist/{memoize-C9ltv0Cw.js → memoize-BOtf2yFf.js} +1 -1
- package/dist/{merge-CHn7Yx0N.js → merge-Be1CqGnU.js} +1 -1
- package/dist/mermaid-4DMBBIKO-DIdL224_.js +6 -0
- package/dist/{mermaid-DO-Daq7u.js → mermaid-IU93XzmY.js} +44 -44
- package/dist/{mermaid-parser.core-DreccfmS.js → mermaid-parser.core-C3XRsazI.js} +8 -8
- package/dist/{min-BNz2lZfk.js → min-Dtgc8txR.js} +4 -4
- package/dist/{mindmap-definition-VGOIOE7T-CC1_Vl0f.js → mindmap-definition-VGOIOE7T-B-4mnfFG.js} +9 -9
- package/dist/{now-Sgq5m3D-.js → now-Ch98bJO_.js} +2 -2
- package/dist/{number-overlay-editor-CpKi64Fy.js → number-overlay-editor-D-a0qCT8.js} +1 -1
- package/dist/{once-rJImu7SE.js → once-DPuqGUeo.js} +1 -1
- package/dist/{packet-DYOGHKS2-CmWtF3uO.js → packet-DYOGHKS2-34raHOiB.js} +3 -3
- package/dist/{pick-CRAXxDYn.js → pick-D1Qo8s2C.js} +4 -4
- package/dist/{pie-VRWISCQL-B6u8vus8.js → pie-VRWISCQL-BaLlzZa3.js} +3 -3
- package/dist/{pieDiagram-ADFJNKIX-Di34MOFQ.js → pieDiagram-ADFJNKIX-Cr3cNpZY.js} +15 -15
- package/dist/{precisionRound-CnHPY_5v.js → precisionRound-Tqb4mg-H.js} +1 -1
- package/dist/{process-output-X8TR20AK.js → process-output-5qJjMRKh.js} +4 -4
- package/dist/{quadrantDiagram-AYHSOK5B-B9kVk1ny.js → quadrantDiagram-AYHSOK5B-BuNL8Q93.js} +4 -4
- package/dist/{radar-ZZBFDIW7-XAmXSa8s.js → radar-ZZBFDIW7-Ci7bfoZa.js} +3 -3
- package/dist/{react-vega-Dh6-UKKe.js → react-vega-B0sAlDTL.js} +9 -9
- package/dist/react-vega-B6ncY2Tp.js +9 -0
- package/dist/{requirementDiagram-UZGBJVZJ-BxGfGYEx.js → requirementDiagram-UZGBJVZJ-BG2lLUN1.js} +9 -9
- package/dist/{reveal-component-Cj2fUG1Q.js → reveal-component-DZtPMEoM.js} +28 -28
- package/dist/{sankeyDiagram-TZEHDZUN-D09PBJ-n.js → sankeyDiagram-TZEHDZUN-DMal8sps.js} +3 -3
- package/dist/{sequenceDiagram-WL72ISMW-t_Dpemj0.js → sequenceDiagram-WL72ISMW-DT6Tk-Eo.js} +4 -4
- package/dist/{spec-hVaaZsY5.js → spec-a6DaqW__.js} +4 -4
- package/dist/{stateDiagram-FKZM4ZOC-B18gTP_j.js → stateDiagram-FKZM4ZOC-CB_lodq3.js} +12 -12
- package/dist/{stateDiagram-v2-4FDKWEC3-B6e_t14A.js → stateDiagram-v2-4FDKWEC3-E0RGjKsm.js} +10 -10
- package/dist/stex-KfRnSHzF.js +4 -0
- package/dist/{strings-BiIhGaI8.js → strings-Bu3vlb6W.js} +7 -7
- package/dist/style.css +1 -1
- package/dist/{swiper-component-DlD2GU2g.js → swiper-component-B2t5sN1q.js} +3 -3
- package/dist/{time-C1SGcFMH.js → time-CsmIF9YZ.js} +3 -3
- package/dist/{timeline-definition-IT6M3QCI-DJnh1ks5.js → timeline-definition-IT6M3QCI-NfSKRvH0.js} +2 -2
- package/dist/{toDate-CIpC_34u.js → toDate-ZVVIBmdk.js} +5 -5
- package/dist/{tooltip-DRaMBu06.js → tooltip-C5FYOpQc.js} +4 -4
- package/dist/{treemap-GDKQZRPO-Du95DV6u.js → treemap-GDKQZRPO-Cl6OQh8D.js} +3 -3
- package/dist/{types-Dzuoc3LN.js → types-CVvp1fKr.js} +2 -9
- package/dist/{useAsyncData-C56Khv_R.js → useAsyncData-C008zUPi.js} +2 -2
- package/dist/{useDateFormatter-B_9k85Ex.js → useDateFormatter-BA4FCquG.js} +2 -2
- package/dist/{useDeepCompareMemoize-Dt98v2ua.js → useDeepCompareMemoize-BrA3_n61.js} +1 -1
- package/dist/{useIframeCapabilities-BkYHTrss.js → useIframeCapabilities-C4JTXTIh.js} +1 -1
- package/dist/{useLifecycle-BF6-z62y.js → useLifecycle-BNaoJ5a4.js} +4 -4
- package/dist/{useTheme-DykuNHR2.js → useTheme-7O0YWlE5.js} +3 -3
- package/dist/{vega-component-cSdqoAxe.js → vega-component-DJNmOdUj.js} +18 -18
- package/dist/{vega-loader.browser-3_z8GoFC.js → vega-loader.browser-CZ-J8Py3.js} +3 -3
- package/dist/{xychartDiagram-PRI3JC2R-Dk2d_bX0.js → xychartDiagram-PRI3JC2R-BvwftqMA.js} +9 -9
- package/dist/{zod-BWkcDORu.js → zod-CoBiJ5v4.js} +3 -3
- package/package.json +1 -1
- package/src/components/data-table/__tests__/column-header.test.tsx +110 -277
- package/src/components/data-table/__tests__/date-filter-inputs.test.tsx +33 -0
- package/src/components/data-table/__tests__/filter-pill-editor.test.tsx +75 -38
- package/src/components/data-table/__tests__/filter-pills.test.tsx +287 -0
- package/src/components/data-table/__tests__/filter-test-utils.ts +47 -0
- package/src/components/data-table/__tests__/filters.test.ts +5 -5
- package/src/components/data-table/add-filter-button.tsx +85 -0
- package/src/components/data-table/column-header.tsx +92 -691
- package/src/components/data-table/context-menu.tsx +26 -12
- package/src/components/data-table/data-table.tsx +89 -57
- package/src/components/data-table/date-filter-inputs.tsx +13 -10
- package/src/components/data-table/filter-by-values-picker.tsx +13 -19
- package/src/components/data-table/filter-editor-context.tsx +34 -0
- package/src/components/data-table/filter-pill-editor.tsx +152 -175
- package/src/components/data-table/filter-pills.tsx +190 -153
- package/src/components/data-table/filters/builders.ts +102 -0
- package/src/components/data-table/filters/defaults.ts +31 -0
- package/src/components/data-table/filters/format.ts +131 -0
- package/src/components/data-table/filters/guards.ts +51 -0
- package/src/components/data-table/filters/index.ts +7 -0
- package/src/components/data-table/filters/operators.ts +76 -0
- package/src/components/data-table/filters/serialize.ts +186 -0
- package/src/components/data-table/filters/types.ts +33 -0
- package/src/components/data-table/header-items.tsx +6 -83
- package/src/components/data-table/value-chips.tsx +52 -0
- package/src/components/dependency-graph/minimap-content.tsx +2 -2
- package/src/components/ui/number-field.tsx +13 -1
- package/src/utils/dates.ts +39 -0
- package/dist/ErrorBoundary-D3wrPNma.js +0 -167
- package/dist/architecture-7HQA4BMR-CS9jOrqM.js +0 -6
- package/dist/dist-21ButRCu.js +0 -8
- package/dist/dist-B--tLnAP.js +0 -5
- package/dist/dist-BoHGySTM.js +0 -5
- package/dist/dist-ByAz19Qc.js +0 -5
- package/dist/dist-C1Ap5CYU.js +0 -5
- package/dist/dist-C93EysN4.js +0 -5
- package/dist/dist-CY-lVor6.js +0 -8
- package/dist/dist-CYDuv4bR.js +0 -8
- package/dist/dist-Cfo5EE2t.js +0 -6
- package/dist/dist-CjivSDvN.js +0 -5
- package/dist/dist-Cqwx-MH7.js +0 -5
- package/dist/dist-DbpcoFAV.js +0 -6
- package/dist/dist-FUNenbiQ.js +0 -5
- package/dist/dist-zhSud5X3.js +0 -8
- package/dist/mermaid-4DMBBIKO-B7VQMwJx.js +0 -6
- package/dist/react-vega-Cavbrg4l.js +0 -9
- package/dist/stex-ChDHQs3R.js +0 -4
- package/src/components/data-table/__tests__/column-header.test.ts +0 -65
- package/src/components/data-table/filters.ts +0 -386
- /package/dist/{_baseFor-BGiY-cm1.js → _baseFor-4jw-lnCC.js} +0 -0
- /package/dist/{clsx-CyyyQ8Ue.js → clsx-CIWA5tNO.js} +0 -0
- /package/dist/{defaultLocale-DoeErsX2.js → defaultLocale-BoHTsDG6.js} +0 -0
- /package/dist/{defaultLocale-BpsHxBd7.js → defaultLocale-u-3osm0P.js} +0 -0
- /package/dist/{dist-CCADb07R.js → dist-DNdhYsgW.js} +0 -0
- /package/dist/{emotion-is-prop-valid.esm-DtW2o230.js → emotion-is-prop-valid.esm-DzSb5hsH.js} +0 -0
- /package/dist/{invariant-UcGKQEhF.js → invariant-wRzNXIsJ.js} +0 -0
- /package/dist/{jsx-runtime-COBk7ree.js → jsx-runtime-DebpN0FN.js} +0 -0
- /package/dist/{main-CThhXnXU.js → main-Tj_-QTyF.js} +0 -0
- /package/dist/{micromark-factory-space-CwHmg6iz.js → micromark-factory-space-DF2w36zS.js} +0 -0
- /package/dist/{ordinal-B43ZeR68.js → ordinal-ArJavP1Q.js} +0 -0
- /package/dist/{purify.es-DT70lfR0.js → purify.es-H92eMd9-.js} +0 -0
- /package/dist/{range-BOiA8qqU.js → range-C-rmrM1O.js} +0 -0
- /package/dist/{react-dom-BWRJ_g_k.js → react-dom-BTJzcVJ9.js} +0 -0
- /package/dist/{stex-DrxP7bb3.js → stex-BIsgBmK4.js} +0 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import type { OperatorType } from "@/plugins/impl/data-frames/utils/operators";
|
|
4
|
+
import type { ColumnFilterValue, MembershipFilterType } from "./builders";
|
|
5
|
+
import {
|
|
6
|
+
COMPARISON_OPS,
|
|
7
|
+
type MembershipOp,
|
|
8
|
+
type NullishOp,
|
|
9
|
+
OPERATORS_BY_TYPE,
|
|
10
|
+
TEXT_SCALAR_OPS,
|
|
11
|
+
} from "./operators";
|
|
12
|
+
import type { FilterType } from "./types";
|
|
13
|
+
|
|
14
|
+
const makeOpGuard = <T extends OperatorType>(ops: readonly T[]) => {
|
|
15
|
+
const set = new Set<OperatorType>(ops);
|
|
16
|
+
return (op: OperatorType): op is T => set.has(op);
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export const isComparisonOp = makeOpGuard(COMPARISON_OPS);
|
|
20
|
+
export const isTextScalarOp = makeOpGuard(TEXT_SCALAR_OPS);
|
|
21
|
+
|
|
22
|
+
export function isMembershipOp(op: OperatorType): op is MembershipOp {
|
|
23
|
+
return op === "in" || op === "not_in";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function isNullishFilter(
|
|
27
|
+
filter: ColumnFilterValue,
|
|
28
|
+
): filter is Extract<ColumnFilterValue, { operator: NullishOp }> {
|
|
29
|
+
return filter.operator === "is_null" || filter.operator === "is_not_null";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export type DateLikeFilterType = Extract<
|
|
33
|
+
FilterType,
|
|
34
|
+
"date" | "datetime" | "time"
|
|
35
|
+
>;
|
|
36
|
+
|
|
37
|
+
const DATE_LIKE_TYPES: ReadonlySet<FilterType> = new Set([
|
|
38
|
+
"date",
|
|
39
|
+
"datetime",
|
|
40
|
+
"time",
|
|
41
|
+
]);
|
|
42
|
+
|
|
43
|
+
export const isDateLikeType = (type: FilterType): type is DateLikeFilterType =>
|
|
44
|
+
DATE_LIKE_TYPES.has(type);
|
|
45
|
+
|
|
46
|
+
export function isMembershipFilterType(
|
|
47
|
+
type: FilterType,
|
|
48
|
+
): type is MembershipFilterType {
|
|
49
|
+
const ops = OPERATORS_BY_TYPE[type];
|
|
50
|
+
return ops.includes("in") || ops.includes("not_in");
|
|
51
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import type { OperatorType } from "@/plugins/impl/data-frames/utils/operators";
|
|
4
|
+
import type { FilterType } from "./types";
|
|
5
|
+
|
|
6
|
+
// Primitive operator groups — each describes one shape of filter value.
|
|
7
|
+
export const NULLISH_OPS = ["is_null", "is_not_null"] as const;
|
|
8
|
+
export const MEMBERSHIP_OPS = ["in", "not_in"] as const;
|
|
9
|
+
export const COMPARISON_OPS = ["==", "!=", ">", ">=", "<", "<="] as const;
|
|
10
|
+
export const TEXT_SCALAR_OPS = [
|
|
11
|
+
"contains",
|
|
12
|
+
"equals",
|
|
13
|
+
"does_not_equal",
|
|
14
|
+
"regex",
|
|
15
|
+
"starts_with",
|
|
16
|
+
"ends_with",
|
|
17
|
+
] as const;
|
|
18
|
+
export const BOOLEAN_VALUE_OPS = ["is_true", "is_false"] as const;
|
|
19
|
+
export const EMPTY_OPS = ["is_empty"] as const;
|
|
20
|
+
|
|
21
|
+
// Operators that carry no payload — `{ operator }` with no other field.
|
|
22
|
+
export const UNARY_OPS = [
|
|
23
|
+
...NULLISH_OPS,
|
|
24
|
+
...BOOLEAN_VALUE_OPS,
|
|
25
|
+
...EMPTY_OPS,
|
|
26
|
+
] as const;
|
|
27
|
+
|
|
28
|
+
// Per-type op lists used by the editor and validators.
|
|
29
|
+
export const BOOLEAN_OPS = [...BOOLEAN_VALUE_OPS, ...NULLISH_OPS] as const;
|
|
30
|
+
export const NUMBER_OPS = [
|
|
31
|
+
"between",
|
|
32
|
+
...COMPARISON_OPS,
|
|
33
|
+
...MEMBERSHIP_OPS,
|
|
34
|
+
...NULLISH_OPS,
|
|
35
|
+
] as const;
|
|
36
|
+
export const TEXT_OPS = [
|
|
37
|
+
...TEXT_SCALAR_OPS,
|
|
38
|
+
...MEMBERSHIP_OPS,
|
|
39
|
+
...EMPTY_OPS,
|
|
40
|
+
...NULLISH_OPS,
|
|
41
|
+
] as const;
|
|
42
|
+
export const DATETIME_OPS = [
|
|
43
|
+
"between",
|
|
44
|
+
...COMPARISON_OPS,
|
|
45
|
+
...NULLISH_OPS,
|
|
46
|
+
] as const;
|
|
47
|
+
|
|
48
|
+
export type NullishOp = (typeof NULLISH_OPS)[number];
|
|
49
|
+
export type MembershipOp = (typeof MEMBERSHIP_OPS)[number];
|
|
50
|
+
export type ComparisonOp = (typeof COMPARISON_OPS)[number];
|
|
51
|
+
export type TextScalarOp = (typeof TEXT_SCALAR_OPS)[number];
|
|
52
|
+
export type BooleanValueOp = (typeof BOOLEAN_VALUE_OPS)[number];
|
|
53
|
+
export type BooleanOp = (typeof BOOLEAN_OPS)[number];
|
|
54
|
+
|
|
55
|
+
export const OPERATORS_BY_TYPE: Record<
|
|
56
|
+
FilterType,
|
|
57
|
+
ReadonlyArray<OperatorType>
|
|
58
|
+
> = {
|
|
59
|
+
number: NUMBER_OPS,
|
|
60
|
+
text: TEXT_OPS,
|
|
61
|
+
boolean: BOOLEAN_OPS,
|
|
62
|
+
date: DATETIME_OPS,
|
|
63
|
+
datetime: DATETIME_OPS,
|
|
64
|
+
time: DATETIME_OPS,
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export const DEFAULT_OPERATOR_FOR_TYPE: Record<FilterType, OperatorType> = {
|
|
68
|
+
number: "between",
|
|
69
|
+
text: "contains",
|
|
70
|
+
boolean: "is_true",
|
|
71
|
+
date: "==",
|
|
72
|
+
datetime: "==",
|
|
73
|
+
time: "between",
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export const OPERATORS_WITHOUT_VALUE = new Set<OperatorType>(UNARY_OPS);
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import type { ColumnFiltersState } from "@tanstack/react-table";
|
|
4
|
+
import type {
|
|
5
|
+
FilterConditionType,
|
|
6
|
+
FilterGroupType,
|
|
7
|
+
} from "@/plugins/impl/data-frames/schema";
|
|
8
|
+
import type { ColumnId } from "@/plugins/impl/data-frames/types";
|
|
9
|
+
import { assertNever } from "@/utils/assertNever";
|
|
10
|
+
import {
|
|
11
|
+
dateToLocalISODate,
|
|
12
|
+
dateToLocalISODateTime,
|
|
13
|
+
dateToLocalISOTime,
|
|
14
|
+
} from "@/utils/dates";
|
|
15
|
+
import type { ColumnFilterValue } from "./builders";
|
|
16
|
+
import { isNullishFilter } from "./guards";
|
|
17
|
+
|
|
18
|
+
export function filterToFilterCondition(
|
|
19
|
+
columnIdString: string,
|
|
20
|
+
filter: ColumnFilterValue | undefined,
|
|
21
|
+
): FilterConditionType[] {
|
|
22
|
+
if (!filter) {
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
const columnId = columnIdString as ColumnId;
|
|
26
|
+
|
|
27
|
+
if (isNullishFilter(filter)) {
|
|
28
|
+
return [
|
|
29
|
+
{
|
|
30
|
+
column_id: columnId,
|
|
31
|
+
operator: filter.operator,
|
|
32
|
+
type: "condition",
|
|
33
|
+
negate: false,
|
|
34
|
+
},
|
|
35
|
+
];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
switch (filter.type) {
|
|
39
|
+
case "number":
|
|
40
|
+
switch (filter.operator) {
|
|
41
|
+
case "between":
|
|
42
|
+
return [
|
|
43
|
+
{
|
|
44
|
+
column_id: columnId,
|
|
45
|
+
operator: "between",
|
|
46
|
+
value: { min: filter.min, max: filter.max },
|
|
47
|
+
type: "condition",
|
|
48
|
+
negate: false,
|
|
49
|
+
},
|
|
50
|
+
];
|
|
51
|
+
case "==":
|
|
52
|
+
case "!=":
|
|
53
|
+
case ">":
|
|
54
|
+
case ">=":
|
|
55
|
+
case "<":
|
|
56
|
+
case "<=":
|
|
57
|
+
return [
|
|
58
|
+
{
|
|
59
|
+
column_id: columnId,
|
|
60
|
+
operator: filter.operator,
|
|
61
|
+
value: filter.value,
|
|
62
|
+
type: "condition",
|
|
63
|
+
negate: false,
|
|
64
|
+
},
|
|
65
|
+
];
|
|
66
|
+
case "in":
|
|
67
|
+
case "not_in":
|
|
68
|
+
return [
|
|
69
|
+
{
|
|
70
|
+
column_id: columnId,
|
|
71
|
+
operator: filter.operator,
|
|
72
|
+
value: filter.values,
|
|
73
|
+
type: "condition",
|
|
74
|
+
negate: false,
|
|
75
|
+
},
|
|
76
|
+
];
|
|
77
|
+
default:
|
|
78
|
+
assertNever(filter);
|
|
79
|
+
}
|
|
80
|
+
case "text":
|
|
81
|
+
switch (filter.operator) {
|
|
82
|
+
case "contains":
|
|
83
|
+
case "equals":
|
|
84
|
+
case "does_not_equal":
|
|
85
|
+
case "regex":
|
|
86
|
+
case "starts_with":
|
|
87
|
+
case "ends_with":
|
|
88
|
+
return [
|
|
89
|
+
{
|
|
90
|
+
column_id: columnId,
|
|
91
|
+
operator: filter.operator,
|
|
92
|
+
value: filter.text,
|
|
93
|
+
type: "condition",
|
|
94
|
+
negate: false,
|
|
95
|
+
},
|
|
96
|
+
];
|
|
97
|
+
case "in":
|
|
98
|
+
case "not_in":
|
|
99
|
+
return [
|
|
100
|
+
{
|
|
101
|
+
column_id: columnId,
|
|
102
|
+
operator: filter.operator,
|
|
103
|
+
value: filter.values,
|
|
104
|
+
type: "condition",
|
|
105
|
+
negate: false,
|
|
106
|
+
},
|
|
107
|
+
];
|
|
108
|
+
case "is_empty":
|
|
109
|
+
return [
|
|
110
|
+
{
|
|
111
|
+
column_id: columnId,
|
|
112
|
+
operator: "is_empty",
|
|
113
|
+
type: "condition",
|
|
114
|
+
negate: false,
|
|
115
|
+
},
|
|
116
|
+
];
|
|
117
|
+
default:
|
|
118
|
+
assertNever(filter);
|
|
119
|
+
}
|
|
120
|
+
case "date":
|
|
121
|
+
case "datetime":
|
|
122
|
+
case "time": {
|
|
123
|
+
const encode =
|
|
124
|
+
filter.type === "date"
|
|
125
|
+
? dateToLocalISODate
|
|
126
|
+
: filter.type === "time"
|
|
127
|
+
? dateToLocalISOTime
|
|
128
|
+
: dateToLocalISODateTime;
|
|
129
|
+
switch (filter.operator) {
|
|
130
|
+
case "between":
|
|
131
|
+
return [
|
|
132
|
+
{
|
|
133
|
+
column_id: columnId,
|
|
134
|
+
operator: "between",
|
|
135
|
+
value: { min: encode(filter.min), max: encode(filter.max) },
|
|
136
|
+
type: "condition",
|
|
137
|
+
negate: false,
|
|
138
|
+
},
|
|
139
|
+
];
|
|
140
|
+
case "==":
|
|
141
|
+
case "!=":
|
|
142
|
+
case ">":
|
|
143
|
+
case ">=":
|
|
144
|
+
case "<":
|
|
145
|
+
case "<=":
|
|
146
|
+
return [
|
|
147
|
+
{
|
|
148
|
+
column_id: columnId,
|
|
149
|
+
operator: filter.operator,
|
|
150
|
+
value: encode(filter.value),
|
|
151
|
+
type: "condition",
|
|
152
|
+
negate: false,
|
|
153
|
+
},
|
|
154
|
+
];
|
|
155
|
+
default:
|
|
156
|
+
assertNever(filter);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
case "boolean":
|
|
160
|
+
return [
|
|
161
|
+
{
|
|
162
|
+
column_id: columnId,
|
|
163
|
+
operator: filter.operator,
|
|
164
|
+
type: "condition",
|
|
165
|
+
negate: false,
|
|
166
|
+
},
|
|
167
|
+
];
|
|
168
|
+
default:
|
|
169
|
+
assertNever(filter);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export function filtersToFilterGroup(
|
|
174
|
+
columnFilters: ColumnFiltersState,
|
|
175
|
+
): FilterGroupType {
|
|
176
|
+
const conditions = columnFilters.flatMap((filter) =>
|
|
177
|
+
filterToFilterCondition(filter.id, filter.value as ColumnFilterValue),
|
|
178
|
+
);
|
|
179
|
+
// To maintain existing behavior "and" all the conditions
|
|
180
|
+
return {
|
|
181
|
+
type: "group",
|
|
182
|
+
operator: "and",
|
|
183
|
+
children: conditions,
|
|
184
|
+
negate: false,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import type { RowData } from "@tanstack/react-table";
|
|
4
|
+
import type { DataType } from "@/core/kernel/messages";
|
|
5
|
+
|
|
6
|
+
declare module "@tanstack/react-table" {
|
|
7
|
+
//allows us to define custom properties for our columns
|
|
8
|
+
interface ColumnMeta<TData extends RowData, TValue> {
|
|
9
|
+
rowHeader?: boolean;
|
|
10
|
+
dtype?: string;
|
|
11
|
+
dataType?: DataType;
|
|
12
|
+
filterType?: FilterType;
|
|
13
|
+
minFractionDigits?: number;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const FILTER_TYPES = [
|
|
18
|
+
"text",
|
|
19
|
+
"number",
|
|
20
|
+
"date",
|
|
21
|
+
"datetime",
|
|
22
|
+
"time",
|
|
23
|
+
"boolean",
|
|
24
|
+
] as const;
|
|
25
|
+
export type FilterType = (typeof FILTER_TYPES)[number];
|
|
26
|
+
|
|
27
|
+
export const EDITABLE_FILTER_TYPES: ReadonlySet<FilterType> = new Set(
|
|
28
|
+
FILTER_TYPES,
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
export type FormattedFilter =
|
|
32
|
+
| { kind: "scalar"; operator: string; value?: string }
|
|
33
|
+
| { kind: "list"; operator: string; items: string[] };
|
|
@@ -9,9 +9,6 @@ import {
|
|
|
9
9
|
ChevronsUpDown,
|
|
10
10
|
CopyIcon,
|
|
11
11
|
FilterX,
|
|
12
|
-
FunnelPlusIcon,
|
|
13
|
-
ListFilterIcon,
|
|
14
|
-
ListFilterPlusIcon,
|
|
15
12
|
PinOffIcon,
|
|
16
13
|
WrapTextIcon,
|
|
17
14
|
} from "lucide-react";
|
|
@@ -27,7 +24,6 @@ import type { DataType } from "@/core/kernel/messages";
|
|
|
27
24
|
import { cn } from "@/utils/cn";
|
|
28
25
|
import { copyToClipboard } from "@/utils/copy";
|
|
29
26
|
import { DATA_TYPE_ICON } from "../datasets/icons";
|
|
30
|
-
import { Button } from "../ui/button";
|
|
31
27
|
import { formattingExample } from "./column-formatting/feature";
|
|
32
28
|
import { formatOptions } from "./column-formatting/types";
|
|
33
29
|
import { NAMELESS_COLUMN_PREFIX } from "./columns";
|
|
@@ -242,26 +238,18 @@ export function renderSorts<TData, TValue>(
|
|
|
242
238
|
);
|
|
243
239
|
}
|
|
244
240
|
|
|
245
|
-
export function
|
|
246
|
-
column: Column<TData, TValue>,
|
|
247
|
-
) {
|
|
241
|
+
export function renderSortIcon<TData, TValue>(column: Column<TData, TValue>) {
|
|
248
242
|
if (!column.getCanSort()) {
|
|
249
243
|
return null;
|
|
250
244
|
}
|
|
251
245
|
|
|
252
246
|
const isSorted = column.getIsSorted();
|
|
253
|
-
const isFiltered = column.getFilterValue() !== undefined;
|
|
254
247
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
} else if (isSorted) {
|
|
261
|
-
Icon = isSorted === "desc" ? DescIcon : AscIcon;
|
|
262
|
-
} else {
|
|
263
|
-
Icon = ChevronsUpDown;
|
|
264
|
-
}
|
|
248
|
+
const Icon: React.FC<React.SVGProps<SVGSVGElement>> = isSorted
|
|
249
|
+
? isSorted === "desc"
|
|
250
|
+
? DescIcon
|
|
251
|
+
: AscIcon
|
|
252
|
+
: ChevronsUpDown;
|
|
265
253
|
|
|
266
254
|
return <Icon className="h-3 w-3" />;
|
|
267
255
|
}
|
|
@@ -292,68 +280,3 @@ export const ClearFilterMenuItem = <TData, TValue>({
|
|
|
292
280
|
Clear filter
|
|
293
281
|
</DropdownMenuItem>
|
|
294
282
|
);
|
|
295
|
-
|
|
296
|
-
export function renderFilterByValues<TData, TValue>(
|
|
297
|
-
column: Column<TData, TValue>,
|
|
298
|
-
setIsFilterValueOpen: (open: boolean) => void,
|
|
299
|
-
) {
|
|
300
|
-
const canFilter = column.getCanFilter();
|
|
301
|
-
if (!canFilter) {
|
|
302
|
-
return null;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
const columnType = column.columnDef.meta?.dataType;
|
|
306
|
-
// skip boolean as this can be easily filtered through normal filters
|
|
307
|
-
if (columnType === "boolean") {
|
|
308
|
-
return null;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// there are some edge cases which do not support filtering (eg. dicts with None values)
|
|
312
|
-
const filterType = column.columnDef.meta?.filterType;
|
|
313
|
-
if (!filterType) {
|
|
314
|
-
return null;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
return (
|
|
318
|
-
<DropdownMenuSub>
|
|
319
|
-
<DropdownMenuItem onClick={() => setIsFilterValueOpen(true)}>
|
|
320
|
-
<ListFilterIcon className="mo-dropdown-icon" />
|
|
321
|
-
Filter by values
|
|
322
|
-
</DropdownMenuItem>
|
|
323
|
-
</DropdownMenuSub>
|
|
324
|
-
);
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
export const FilterButtons = ({
|
|
328
|
-
onApply,
|
|
329
|
-
onClear,
|
|
330
|
-
clearButtonDisabled,
|
|
331
|
-
applyButtonDisabled,
|
|
332
|
-
}: {
|
|
333
|
-
onApply: () => void;
|
|
334
|
-
onClear: () => void;
|
|
335
|
-
clearButtonDisabled?: boolean;
|
|
336
|
-
applyButtonDisabled?: boolean;
|
|
337
|
-
}) => {
|
|
338
|
-
return (
|
|
339
|
-
<div className="flex gap-2 px-2 justify-between">
|
|
340
|
-
<Button
|
|
341
|
-
variant="link"
|
|
342
|
-
size="sm"
|
|
343
|
-
onClick={onApply}
|
|
344
|
-
disabled={applyButtonDisabled}
|
|
345
|
-
>
|
|
346
|
-
Apply
|
|
347
|
-
</Button>
|
|
348
|
-
<Button
|
|
349
|
-
variant="linkDestructive"
|
|
350
|
-
size="sm"
|
|
351
|
-
className=""
|
|
352
|
-
onClick={onClear}
|
|
353
|
-
disabled={clearButtonDisabled}
|
|
354
|
-
>
|
|
355
|
-
Clear
|
|
356
|
-
</Button>
|
|
357
|
-
</div>
|
|
358
|
-
);
|
|
359
|
-
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import type React from "react";
|
|
4
|
+
|
|
5
|
+
export const Chip = ({ children }: { children: React.ReactNode }) => (
|
|
6
|
+
<span className="inline-flex items-center rounded-sm bg-muted/50 px-1 font-mono text-xs font-normal leading-tight text-foreground">
|
|
7
|
+
{children}
|
|
8
|
+
</span>
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
export const MoreChip = ({ count }: { count: number }) => (
|
|
12
|
+
<span className="inline-flex items-center px-1 text-xs italic text-muted-foreground">
|
|
13
|
+
+{count}
|
|
14
|
+
</span>
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
interface ChipWithCommaProps {
|
|
18
|
+
value: string;
|
|
19
|
+
showComma: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const ChipWithComma = ({ value, showComma }: ChipWithCommaProps) => (
|
|
23
|
+
<span className="inline-flex items-center">
|
|
24
|
+
<Chip>{value}</Chip>
|
|
25
|
+
{showComma && <span className="text-muted-foreground">,</span>}
|
|
26
|
+
</span>
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
interface CompactChipRowProps {
|
|
30
|
+
items: string[];
|
|
31
|
+
max?: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export const CompactChipRow = ({ items, max = 3 }: CompactChipRowProps) => {
|
|
35
|
+
if (items.length === 0) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
const visible = items.slice(0, max);
|
|
39
|
+
const hidden = Math.max(0, items.length - max);
|
|
40
|
+
return (
|
|
41
|
+
<span className="inline-flex items-center gap-1">
|
|
42
|
+
{visible.map((item, i) => (
|
|
43
|
+
<ChipWithComma
|
|
44
|
+
key={i}
|
|
45
|
+
value={item}
|
|
46
|
+
showComma={i < visible.length - 1}
|
|
47
|
+
/>
|
|
48
|
+
))}
|
|
49
|
+
{hidden > 0 && <MoreChip count={hidden} />}
|
|
50
|
+
</span>
|
|
51
|
+
);
|
|
52
|
+
};
|
|
@@ -68,7 +68,7 @@ const MinimapCell: React.FC<MinimapCellProps> = (props) => {
|
|
|
68
68
|
className={cn(
|
|
69
69
|
"group bg-transparent text-left w-full flex relative justify-between items-center",
|
|
70
70
|
"border-none rounded cursor-pointer",
|
|
71
|
-
"h-[21px] pl-[
|
|
71
|
+
"h-[21px] pl-[65px] font-inherit",
|
|
72
72
|
isSelected
|
|
73
73
|
? "text-primary-foreground"
|
|
74
74
|
: "text-(--gray-8) hover:text-(--gray-9)",
|
|
@@ -106,7 +106,7 @@ const MinimapCell: React.FC<MinimapCellProps> = (props) => {
|
|
|
106
106
|
</div>
|
|
107
107
|
<svg
|
|
108
108
|
className={cn(
|
|
109
|
-
"absolute overflow-visible top-[10.5px] left-[calc(var(--spacing-extra-small,8px)+
|
|
109
|
+
"absolute overflow-visible top-[10.5px] left-[calc(var(--spacing-extra-small,8px)+31px)] pointer-events-none",
|
|
110
110
|
isSelected ? "z-[1]" : "z-0",
|
|
111
111
|
getTextColor({ cell, selectedCell }),
|
|
112
112
|
)}
|
|
@@ -15,10 +15,17 @@ import { maxFractionalDigits } from "@/utils/numbers";
|
|
|
15
15
|
export interface NumberFieldProps extends AriaNumberFieldProps {
|
|
16
16
|
placeholder?: string;
|
|
17
17
|
variant?: "default" | "xs";
|
|
18
|
+
/**
|
|
19
|
+
* Fires on every keystroke with the raw text currently in the input.
|
|
20
|
+
* React-aria's `onChange` only fires on commit (blur/Enter/stepper); use this
|
|
21
|
+
* when callers need to peek at the in-progress value, e.g. to enable an Apply
|
|
22
|
+
* button while the user is still typing.
|
|
23
|
+
*/
|
|
24
|
+
onInputText?: (text: string) => void;
|
|
18
25
|
}
|
|
19
26
|
|
|
20
27
|
export const NumberField = React.forwardRef<HTMLInputElement, NumberFieldProps>(
|
|
21
|
-
({ placeholder, variant = "default", ...props }, ref) => {
|
|
28
|
+
({ placeholder, variant = "default", onInputText, ...props }, ref) => {
|
|
22
29
|
const { locale } = useLocale();
|
|
23
30
|
return (
|
|
24
31
|
<AriaNumberField
|
|
@@ -48,6 +55,11 @@ export const NumberField = React.forwardRef<HTMLInputElement, NumberFieldProps>(
|
|
|
48
55
|
e.stopPropagation();
|
|
49
56
|
}
|
|
50
57
|
}}
|
|
58
|
+
onInput={
|
|
59
|
+
onInputText
|
|
60
|
+
? (e) => onInputText(e.currentTarget.value)
|
|
61
|
+
: undefined
|
|
62
|
+
}
|
|
51
63
|
className={cn(
|
|
52
64
|
"flex-1",
|
|
53
65
|
"w-full",
|
package/src/utils/dates.ts
CHANGED
|
@@ -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
|
|