@hexclave/dashboard-ui-components 1.0.41 → 1.0.43
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/analytics-chart-BUxntwQ3.d.ts +553 -0
- package/dist/analytics-chart-BUxntwQ3.d.ts.map +1 -0
- package/dist/components/alert.d.ts +1 -3
- package/dist/components/alert.d.ts.map +1 -1
- package/dist/components/alert.js +4 -7
- package/dist/components/alert.js.map +1 -1
- package/dist/components/analytics-chart/analytics-chart-pie.d.ts +3 -4
- package/dist/components/analytics-chart/analytics-chart-pie.d.ts.map +1 -1
- package/dist/components/analytics-chart/analytics-chart-pie.js +2 -4
- package/dist/components/analytics-chart/analytics-chart-pie.js.map +1 -1
- package/dist/components/analytics-chart/analytics-chart.d.ts +2 -554
- package/dist/components/analytics-chart/analytics-chart.js +4 -7
- package/dist/components/analytics-chart/analytics-chart.js.map +1 -1
- package/dist/components/analytics-chart/default-analytics-chart-tooltip.d.ts +2 -66
- package/dist/components/analytics-chart/default-analytics-chart-tooltip.js +3 -5
- package/dist/components/analytics-chart/default-analytics-chart-tooltip.js.map +1 -1
- package/dist/components/analytics-chart/format.d.ts +2 -13
- package/dist/components/analytics-chart/format.js +2 -3
- package/dist/components/analytics-chart/format.js.map +1 -1
- package/dist/components/analytics-chart/index.d.ts +7 -7
- package/dist/components/analytics-chart/index.js +175 -177
- package/dist/components/analytics-chart/palette.d.ts +2 -15
- package/dist/components/analytics-chart/palette.js +2 -3
- package/dist/components/analytics-chart/palette.js.map +1 -1
- package/dist/components/analytics-chart/render-data-series.d.ts +1 -1
- package/dist/components/analytics-chart/render-data-series.d.ts.map +1 -1
- package/dist/components/analytics-chart/render-data-series.js +2 -4
- package/dist/components/analytics-chart/render-data-series.js.map +1 -1
- package/dist/components/analytics-chart/state.d.ts +2 -54
- package/dist/components/analytics-chart/state.js +2 -4
- package/dist/components/analytics-chart/state.js.map +1 -1
- package/dist/components/analytics-chart/strings.d.ts +2 -33
- package/dist/components/analytics-chart/strings.js +2 -3
- package/dist/components/analytics-chart/strings.js.map +1 -1
- package/dist/components/analytics-chart/types.d.ts +2 -158
- package/dist/components/analytics-chart/types.js +2 -3
- package/dist/components/analytics-chart/types.js.map +1 -1
- package/dist/components/badge.d.ts +1 -3
- package/dist/components/badge.d.ts.map +1 -1
- package/dist/components/badge.js +4 -10
- package/dist/components/badge.js.map +1 -1
- package/dist/components/button.d.ts +6 -7
- package/dist/components/button.d.ts.map +1 -1
- package/dist/components/button.js +4 -5
- package/dist/components/button.js.map +1 -1
- package/dist/components/card.d.ts +2 -3
- package/dist/components/card.d.ts.map +1 -1
- package/dist/components/card.js +6 -8
- package/dist/components/card.js.map +1 -1
- package/dist/components/chart-card.d.ts +1 -2
- package/dist/components/chart-card.d.ts.map +1 -1
- package/dist/components/chart-card.js +5 -7
- package/dist/components/chart-card.js.map +1 -1
- package/dist/components/chart-container.d.ts +1 -2
- package/dist/components/chart-container.d.ts.map +1 -1
- package/dist/components/chart-container.js +5 -7
- package/dist/components/chart-container.js.map +1 -1
- package/dist/components/chart-legend.d.ts +1 -1
- package/dist/components/chart-legend.js +4 -6
- package/dist/components/chart-legend.js.map +1 -1
- package/dist/components/chart-theme.d.ts.map +1 -1
- package/dist/components/chart-theme.js +3 -5
- package/dist/components/chart-theme.js.map +1 -1
- package/dist/components/chart-tooltip.d.ts +10 -14
- package/dist/components/chart-tooltip.d.ts.map +1 -1
- package/dist/components/chart-tooltip.js +6 -8
- package/dist/components/chart-tooltip.js.map +1 -1
- package/dist/components/cursor-blast-effect.d.ts +1 -3
- package/dist/components/cursor-blast-effect.d.ts.map +1 -1
- package/dist/components/cursor-blast-effect.js +2 -5
- package/dist/components/cursor-blast-effect.js.map +1 -1
- package/dist/components/data-grid/data-grid-export-dialog.d.ts +2 -3
- package/dist/components/data-grid/data-grid-export-dialog.d.ts.map +1 -1
- package/dist/components/data-grid/data-grid-export-dialog.js +4 -6
- package/dist/components/data-grid/data-grid-export-dialog.js.map +1 -1
- package/dist/components/data-grid/data-grid-sizing.d.ts +2 -13
- package/dist/components/data-grid/data-grid-sizing.js +3 -4
- package/dist/components/data-grid/data-grid-sizing.js.map +1 -1
- package/dist/components/data-grid/data-grid-toolbar.d.ts +2 -31
- package/dist/components/data-grid/data-grid-toolbar.js +5 -7
- package/dist/components/data-grid/data-grid-toolbar.js.map +1 -1
- package/dist/components/data-grid/data-grid.d.ts +2 -47
- package/dist/components/data-grid/data-grid.js +8 -10
- package/dist/components/data-grid/data-grid.js.map +1 -1
- package/dist/components/data-grid/data-grid.test.js +1 -3
- package/dist/components/data-grid/data-grid.test.js.map +1 -1
- package/dist/components/data-grid/index.d.ts +8 -8
- package/dist/components/data-grid/index.js +139 -141
- package/dist/components/data-grid/state.d.ts +2 -34
- package/dist/components/data-grid/state.js +2 -4
- package/dist/components/data-grid/state.js.map +1 -1
- package/dist/components/data-grid/strings.d.ts +2 -8
- package/dist/components/data-grid/strings.js +2 -3
- package/dist/components/data-grid/strings.js.map +1 -1
- package/dist/components/data-grid/types.d.ts +2 -308
- package/dist/components/data-grid/use-data-source.d.ts +2 -85
- package/dist/components/data-grid/use-data-source.js +2 -4
- package/dist/components/data-grid/use-data-source.js.map +1 -1
- package/dist/components/data-grid/use-url-state.d.ts +2 -38
- package/dist/components/data-grid/use-url-state.js +2 -5
- package/dist/components/data-grid/use-url-state.js.map +1 -1
- package/dist/components/data-grid/use-url-state.test.js +1 -3
- package/dist/components/data-grid/use-url-state.test.js.map +1 -1
- package/dist/components/dialog.d.ts +2 -71
- package/dist/components/dialog.js +6 -8
- package/dist/components/dialog.js.map +1 -1
- package/dist/components/edit-mode.d.ts +1 -3
- package/dist/components/edit-mode.d.ts.map +1 -1
- package/dist/components/edit-mode.js +2 -5
- package/dist/components/edit-mode.js.map +1 -1
- package/dist/components/empty-state.d.ts +1 -2
- package/dist/components/empty-state.d.ts.map +1 -1
- package/dist/components/empty-state.js +4 -6
- package/dist/components/empty-state.js.map +1 -1
- package/dist/components/input.js +4 -6
- package/dist/components/input.js.map +1 -1
- package/dist/components/metric-card.d.ts +1 -2
- package/dist/components/metric-card.d.ts.map +1 -1
- package/dist/components/metric-card.js +5 -7
- package/dist/components/metric-card.js.map +1 -1
- package/dist/components/pill-toggle.d.ts +1 -3
- package/dist/components/pill-toggle.d.ts.map +1 -1
- package/dist/components/pill-toggle.js +4 -7
- package/dist/components/pill-toggle.js.map +1 -1
- package/dist/components/progress-bar.d.ts +1 -3
- package/dist/components/progress-bar.d.ts.map +1 -1
- package/dist/components/progress-bar.js +3 -6
- package/dist/components/progress-bar.js.map +1 -1
- package/dist/components/separator.d.ts +1 -3
- package/dist/components/separator.d.ts.map +1 -1
- package/dist/components/separator.js +2 -5
- package/dist/components/separator.js.map +1 -1
- package/dist/components/skeleton.d.ts +1 -2
- package/dist/components/skeleton.d.ts.map +1 -1
- package/dist/components/skeleton.js +2 -5
- package/dist/components/skeleton.js.map +1 -1
- package/dist/components/table.js +4 -6
- package/dist/components/table.js.map +1 -1
- package/dist/components/tabs.d.ts +1 -2
- package/dist/components/tabs.d.ts.map +1 -1
- package/dist/components/tabs.js +4 -7
- package/dist/components/tabs.js.map +1 -1
- package/dist/dashboard-ui-components.global.js +247 -258
- package/dist/dashboard-ui-components.global.js.map +3 -3
- package/dist/data-grid-AJi1TNDa.d.ts +46 -0
- package/dist/data-grid-AJi1TNDa.d.ts.map +1 -0
- package/dist/data-grid-sizing-S1ixcZKo.d.ts +13 -0
- package/dist/data-grid-sizing-S1ixcZKo.d.ts.map +1 -0
- package/dist/data-grid-toolbar-BGSNGDpT.d.ts +30 -0
- package/dist/data-grid-toolbar-BGSNGDpT.d.ts.map +1 -0
- package/dist/default-analytics-chart-tooltip-PrLoMaC1.d.ts +65 -0
- package/dist/default-analytics-chart-tooltip-PrLoMaC1.d.ts.map +1 -0
- package/dist/dialog-CCtTH7s6.d.ts +131 -0
- package/dist/dialog-CCtTH7s6.d.ts.map +1 -0
- package/dist/esm/components/alert.d.ts +1 -3
- package/dist/esm/components/alert.d.ts.map +1 -1
- package/dist/esm/components/alert.js +3 -5
- package/dist/esm/components/alert.js.map +1 -1
- package/dist/esm/components/analytics-chart/analytics-chart-pie.d.ts +3 -4
- package/dist/esm/components/analytics-chart/analytics-chart-pie.d.ts.map +1 -1
- package/dist/esm/components/analytics-chart/analytics-chart-pie.js +1 -2
- package/dist/esm/components/analytics-chart/analytics-chart-pie.js.map +1 -1
- package/dist/esm/components/analytics-chart/analytics-chart.d.ts +4 -5
- package/dist/esm/components/analytics-chart/analytics-chart.d.ts.map +1 -1
- package/dist/esm/components/analytics-chart/analytics-chart.js +3 -5
- package/dist/esm/components/analytics-chart/analytics-chart.js.map +1 -1
- package/dist/esm/components/analytics-chart/default-analytics-chart-tooltip.d.ts +4 -5
- package/dist/esm/components/analytics-chart/default-analytics-chart-tooltip.d.ts.map +1 -1
- package/dist/esm/components/analytics-chart/default-analytics-chart-tooltip.js +2 -3
- package/dist/esm/components/analytics-chart/default-analytics-chart-tooltip.js.map +1 -1
- package/dist/esm/components/analytics-chart/format.d.ts +1 -1
- package/dist/esm/components/analytics-chart/format.d.ts.map +1 -1
- package/dist/esm/components/analytics-chart/format.js +1 -1
- package/dist/esm/components/analytics-chart/format.js.map +1 -1
- package/dist/esm/components/analytics-chart/index.d.ts +7 -7
- package/dist/esm/components/analytics-chart/index.js +1 -2
- package/dist/esm/components/analytics-chart/palette.d.ts +1 -1
- package/dist/esm/components/analytics-chart/palette.d.ts.map +1 -1
- package/dist/esm/components/analytics-chart/palette.js +1 -1
- package/dist/esm/components/analytics-chart/palette.js.map +1 -1
- package/dist/esm/components/analytics-chart/render-data-series.d.ts +1 -1
- package/dist/esm/components/analytics-chart/render-data-series.d.ts.map +1 -1
- package/dist/esm/components/analytics-chart/render-data-series.js +1 -2
- package/dist/esm/components/analytics-chart/render-data-series.js.map +1 -1
- package/dist/esm/components/analytics-chart/state.d.ts +1 -1
- package/dist/esm/components/analytics-chart/state.d.ts.map +1 -1
- package/dist/esm/components/analytics-chart/state.js +1 -2
- package/dist/esm/components/analytics-chart/state.js.map +1 -1
- package/dist/esm/components/analytics-chart/strings.d.ts.map +1 -1
- package/dist/esm/components/analytics-chart/strings.js +1 -1
- package/dist/esm/components/analytics-chart/strings.js.map +1 -1
- package/dist/esm/components/analytics-chart/types.d.ts.map +1 -1
- package/dist/esm/components/analytics-chart/types.js +1 -1
- package/dist/esm/components/analytics-chart/types.js.map +1 -1
- package/dist/esm/components/badge.d.ts +1 -3
- package/dist/esm/components/badge.d.ts.map +1 -1
- package/dist/esm/components/badge.js +3 -8
- package/dist/esm/components/badge.js.map +1 -1
- package/dist/esm/components/button.d.ts +6 -7
- package/dist/esm/components/button.d.ts.map +1 -1
- package/dist/esm/components/button.js +2 -3
- package/dist/esm/components/button.js.map +1 -1
- package/dist/esm/components/card.d.ts +2 -3
- package/dist/esm/components/card.d.ts.map +1 -1
- package/dist/esm/components/card.js +3 -5
- package/dist/esm/components/card.js.map +1 -1
- package/dist/esm/components/chart-card.d.ts +1 -2
- package/dist/esm/components/chart-card.d.ts.map +1 -1
- package/dist/esm/components/chart-card.js +3 -5
- package/dist/esm/components/chart-card.js.map +1 -1
- package/dist/esm/components/chart-container.d.ts +1 -2
- package/dist/esm/components/chart-container.d.ts.map +1 -1
- package/dist/esm/components/chart-container.js +1 -3
- package/dist/esm/components/chart-container.js.map +1 -1
- package/dist/esm/components/chart-legend.d.ts +1 -1
- package/dist/esm/components/chart-legend.js +1 -3
- package/dist/esm/components/chart-legend.js.map +1 -1
- package/dist/esm/components/chart-theme.d.ts.map +1 -1
- package/dist/esm/components/chart-theme.js +2 -3
- package/dist/esm/components/chart-theme.js.map +1 -1
- package/dist/esm/components/chart-tooltip.d.ts +10 -14
- package/dist/esm/components/chart-tooltip.d.ts.map +1 -1
- package/dist/esm/components/chart-tooltip.js +2 -4
- package/dist/esm/components/chart-tooltip.js.map +1 -1
- package/dist/esm/components/cursor-blast-effect.d.ts +1 -3
- package/dist/esm/components/cursor-blast-effect.d.ts.map +1 -1
- package/dist/esm/components/cursor-blast-effect.js +1 -3
- package/dist/esm/components/cursor-blast-effect.js.map +1 -1
- package/dist/esm/components/data-grid/data-grid-export-dialog.d.ts +2 -3
- package/dist/esm/components/data-grid/data-grid-export-dialog.d.ts.map +1 -1
- package/dist/esm/components/data-grid/data-grid-export-dialog.js +2 -4
- package/dist/esm/components/data-grid/data-grid-export-dialog.js.map +1 -1
- package/dist/esm/components/data-grid/data-grid-sizing.d.ts +1 -1
- package/dist/esm/components/data-grid/data-grid-sizing.d.ts.map +1 -1
- package/dist/esm/components/data-grid/data-grid-sizing.js +2 -2
- package/dist/esm/components/data-grid/data-grid-sizing.js.map +1 -1
- package/dist/esm/components/data-grid/data-grid-toolbar.d.ts +2 -3
- package/dist/esm/components/data-grid/data-grid-toolbar.d.ts.map +1 -1
- package/dist/esm/components/data-grid/data-grid-toolbar.js +2 -4
- package/dist/esm/components/data-grid/data-grid-toolbar.js.map +1 -1
- package/dist/esm/components/data-grid/data-grid.d.ts +2 -3
- package/dist/esm/components/data-grid/data-grid.d.ts.map +1 -1
- package/dist/esm/components/data-grid/data-grid.js +6 -8
- package/dist/esm/components/data-grid/data-grid.js.map +1 -1
- package/dist/esm/components/data-grid/data-grid.test.js +2 -3
- package/dist/esm/components/data-grid/data-grid.test.js.map +1 -1
- package/dist/esm/components/data-grid/index.d.ts +8 -8
- package/dist/esm/components/data-grid/index.js +1 -2
- package/dist/esm/components/data-grid/state.d.ts +1 -1
- package/dist/esm/components/data-grid/state.d.ts.map +1 -1
- package/dist/esm/components/data-grid/state.js +1 -2
- package/dist/esm/components/data-grid/state.js.map +1 -1
- package/dist/esm/components/data-grid/strings.d.ts +1 -1
- package/dist/esm/components/data-grid/strings.d.ts.map +1 -1
- package/dist/esm/components/data-grid/strings.js +1 -1
- package/dist/esm/components/data-grid/strings.js.map +1 -1
- package/dist/esm/components/data-grid/types.d.ts.map +1 -1
- package/dist/esm/components/data-grid/types.js +1 -1
- package/dist/esm/components/data-grid/use-data-source.d.ts +1 -1
- package/dist/esm/components/data-grid/use-data-source.d.ts.map +1 -1
- package/dist/esm/components/data-grid/use-data-source.js +1 -2
- package/dist/esm/components/data-grid/use-data-source.js.map +1 -1
- package/dist/esm/components/data-grid/use-url-state.d.ts +1 -1
- package/dist/esm/components/data-grid/use-url-state.d.ts.map +1 -1
- package/dist/esm/components/data-grid/use-url-state.js +1 -3
- package/dist/esm/components/data-grid/use-url-state.js.map +1 -1
- package/dist/esm/components/data-grid/use-url-state.test.js +2 -3
- package/dist/esm/components/data-grid/use-url-state.test.js.map +1 -1
- package/dist/esm/components/dialog.d.ts +6 -8
- package/dist/esm/components/dialog.d.ts.map +1 -1
- package/dist/esm/components/dialog.js +3 -5
- package/dist/esm/components/dialog.js.map +1 -1
- package/dist/esm/components/edit-mode.d.ts +1 -3
- package/dist/esm/components/edit-mode.d.ts.map +1 -1
- package/dist/esm/components/edit-mode.js +1 -3
- package/dist/esm/components/edit-mode.js.map +1 -1
- package/dist/esm/components/empty-state.d.ts +1 -2
- package/dist/esm/components/empty-state.d.ts.map +1 -1
- package/dist/esm/components/empty-state.js +2 -4
- package/dist/esm/components/empty-state.js.map +1 -1
- package/dist/esm/components/input.js +2 -4
- package/dist/esm/components/input.js.map +1 -1
- package/dist/esm/components/metric-card.d.ts +1 -2
- package/dist/esm/components/metric-card.d.ts.map +1 -1
- package/dist/esm/components/metric-card.js +3 -5
- package/dist/esm/components/metric-card.js.map +1 -1
- package/dist/esm/components/pill-toggle.d.ts +1 -3
- package/dist/esm/components/pill-toggle.d.ts.map +1 -1
- package/dist/esm/components/pill-toggle.js +3 -5
- package/dist/esm/components/pill-toggle.js.map +1 -1
- package/dist/esm/components/progress-bar.d.ts +1 -3
- package/dist/esm/components/progress-bar.d.ts.map +1 -1
- package/dist/esm/components/progress-bar.js +2 -4
- package/dist/esm/components/progress-bar.js.map +1 -1
- package/dist/esm/components/separator.d.ts +1 -3
- package/dist/esm/components/separator.d.ts.map +1 -1
- package/dist/esm/components/separator.js +1 -3
- package/dist/esm/components/separator.js.map +1 -1
- package/dist/esm/components/skeleton.d.ts +1 -2
- package/dist/esm/components/skeleton.d.ts.map +1 -1
- package/dist/esm/components/skeleton.js +1 -3
- package/dist/esm/components/skeleton.js.map +1 -1
- package/dist/esm/components/table.js +2 -4
- package/dist/esm/components/table.js.map +1 -1
- package/dist/esm/components/tabs.d.ts +1 -2
- package/dist/esm/components/tabs.d.ts.map +1 -1
- package/dist/esm/components/tabs.js +3 -5
- package/dist/esm/components/tabs.js.map +1 -1
- package/dist/esm/index.d.ts +23 -23
- package/dist/esm/index.js +3 -6
- package/dist/format-DdrrnMlc.d.ts +13 -0
- package/dist/format-DdrrnMlc.d.ts.map +1 -0
- package/dist/index.d.ts +17 -17
- package/dist/index.js +278 -277
- package/dist/palette-pqnuo5cq.d.ts +15 -0
- package/dist/palette-pqnuo5cq.d.ts.map +1 -0
- package/dist/{chunk-BE-pF4vm.js → rolldown-runtime-D6vf50IK.js} +12 -18
- package/dist/state-6LW8ACh5.d.ts +34 -0
- package/dist/state-6LW8ACh5.d.ts.map +1 -0
- package/dist/state-Hch3gYtt.d.ts +54 -0
- package/dist/state-Hch3gYtt.d.ts.map +1 -0
- package/dist/strings-CACVtKlq.d.ts +8 -0
- package/dist/strings-CACVtKlq.d.ts.map +1 -0
- package/dist/strings-D-t58Uol.d.ts +33 -0
- package/dist/strings-D-t58Uol.d.ts.map +1 -0
- package/dist/types-1-eOd1JF.d.ts +308 -0
- package/dist/types-1-eOd1JF.d.ts.map +1 -0
- package/dist/types-NyzRTEfi.d.ts +158 -0
- package/dist/types-NyzRTEfi.d.ts.map +1 -0
- package/dist/use-data-source-BVFynerX.d.ts +85 -0
- package/dist/use-data-source-BVFynerX.d.ts.map +1 -0
- package/dist/use-url-state-B4_wnBjm.d.ts +38 -0
- package/dist/use-url-state-B4_wnBjm.d.ts.map +1 -0
- package/package.json +3 -7
- package/src/components/analytics-chart/analytics-chart.tsx +2 -3
- package/src/components/analytics-chart/default-analytics-chart-tooltip.tsx +1 -1
- package/src/components/chart-tooltip.tsx +1 -1
- package/src/components/data-grid/data-grid-toolbar.tsx +1 -1
- package/src/components/data-grid/data-grid.tsx +2 -2
- package/dist/components/analytics-chart/analytics-chart.d.ts.map +0 -1
- package/dist/components/analytics-chart/default-analytics-chart-tooltip.d.ts.map +0 -1
- package/dist/components/analytics-chart/format.d.ts.map +0 -1
- package/dist/components/analytics-chart/palette.d.ts.map +0 -1
- package/dist/components/analytics-chart/state.d.ts.map +0 -1
- package/dist/components/analytics-chart/strings.d.ts.map +0 -1
- package/dist/components/analytics-chart/types.d.ts.map +0 -1
- package/dist/components/data-grid/data-grid-sizing.d.ts.map +0 -1
- package/dist/components/data-grid/data-grid-toolbar.d.ts.map +0 -1
- package/dist/components/data-grid/data-grid.d.ts.map +0 -1
- package/dist/components/data-grid/state.d.ts.map +0 -1
- package/dist/components/data-grid/strings.d.ts.map +0 -1
- package/dist/components/data-grid/types.d.ts.map +0 -1
- package/dist/components/data-grid/use-data-source.d.ts.map +0 -1
- package/dist/components/data-grid/use-url-state.d.ts.map +0 -1
- package/dist/components/dialog.d.ts.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cursor-blast-effect.js","names":[],"sources":["../../src/components/cursor-blast-effect.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\n\ntype Blast = {\n id: number,\n x: number,\n y: number,\n size: number,\n hue: number,\n};\n\nconst DEFAULT_BLAST_LIFETIME_MS = 720;\nconst DEFAULT_MAX_ACTIVE_BLASTS = 18;\n\n/** Minimum rapid clicks in the time window to count as a rage click */\nconst DEFAULT_RAGE_CLICK_THRESHOLD = 3;\n/** Time window (ms) in which clicks must occur to be considered rage clicking */\nconst DEFAULT_RAGE_CLICK_WINDOW_MS = 600;\n/** Max distance (px) between clicks to still count as same-spot rage clicking */\nconst DEFAULT_RAGE_CLICK_RADIUS_PX = 60;\n\ntype RecentClick = {\n time: number,\n x: number,\n y: number,\n};\n\nexport type CursorBlastEffectProps = {\n /** Lifetime of each blast animation in ms. Default: 720 */\n blastLifetimeMs?: number,\n /** Maximum number of concurrent active blasts. Default: 18 */\n maxActiveBlasts?: number,\n /** Minimum rapid clicks in the time window to trigger a blast. Default: 3 */\n rageClickThreshold?: number,\n /** Time window (ms) for counting rage clicks. Default: 600 */\n rageClickWindowMs?: number,\n /** Max distance (px) between clicks to count as same-spot rage clicking. Default: 60 */\n rageClickRadiusPx?: number,\n /**\n * When provided, the blast effect is scoped to this container element.\n * Clicks are only detected within the container and blasts are positioned\n * relative to the container rather than the viewport.\n */\n containerRef?: React.RefObject<HTMLElement | null>,\n};\n\nexport function CursorBlastEffect({\n blastLifetimeMs = DEFAULT_BLAST_LIFETIME_MS,\n maxActiveBlasts = DEFAULT_MAX_ACTIVE_BLASTS,\n rageClickThreshold = DEFAULT_RAGE_CLICK_THRESHOLD,\n rageClickWindowMs = DEFAULT_RAGE_CLICK_WINDOW_MS,\n rageClickRadiusPx = DEFAULT_RAGE_CLICK_RADIUS_PX,\n containerRef,\n}: CursorBlastEffectProps = {}) {\n const [blasts, setBlasts] = useState<Blast[]>([]);\n const [mounted, setMounted] = useState(false);\n const idCounterRef = useRef(0);\n const timeoutIdsRef = useRef<Map<number, number>>(new Map());\n const recentClicksRef = useRef<RecentClick[]>([]);\n\n // Store latest config in refs so the effect callback always reads current values\n const configRef = useRef({\n blastLifetimeMs,\n maxActiveBlasts,\n rageClickThreshold,\n rageClickWindowMs,\n rageClickRadiusPx,\n });\n configRef.current = {\n blastLifetimeMs,\n maxActiveBlasts,\n rageClickThreshold,\n rageClickWindowMs,\n rageClickRadiusPx,\n };\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n useEffect(() => {\n const removeBlast = (id: number) => {\n setBlasts((prev) => prev.filter((blast) => blast.id !== id));\n const timeoutId = timeoutIdsRef.current.get(id);\n if (timeoutId !== undefined) {\n window.clearTimeout(timeoutId);\n timeoutIdsRef.current.delete(id);\n }\n };\n\n const spawnBlast = (x: number, y: number) => {\n const cfg = configRef.current;\n const nextId = idCounterRef.current;\n idCounterRef.current += 1;\n\n const nextBlast: Blast = {\n id: nextId,\n x,\n y,\n size: 44 + Math.random() * 20,\n hue: 185 + Math.random() * 35,\n };\n\n setBlasts((prev) => {\n const next = [...prev, nextBlast];\n if (next.length <= cfg.maxActiveBlasts) {\n return next;\n }\n return next.slice(next.length - cfg.maxActiveBlasts);\n });\n\n const timeoutId = window.setTimeout(() => removeBlast(nextId), cfg.blastLifetimeMs);\n timeoutIdsRef.current.set(nextId, timeoutId);\n };\n\n const onClick = (event: MouseEvent) => {\n if (window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches) {\n return;\n }\n\n const cfg = configRef.current;\n const now = performance.now();\n\n let x: number;\n let y: number;\n\n if (containerRef?.current) {\n const rect = containerRef.current.getBoundingClientRect();\n x = event.clientX - rect.left;\n y = event.clientY - rect.top;\n } else {\n x = event.clientX;\n y = event.clientY;\n }\n\n // Prune clicks outside the time window\n recentClicksRef.current = recentClicksRef.current.filter(\n (click) => now - click.time < cfg.rageClickWindowMs,\n );\n\n recentClicksRef.current.push({ time: now, x, y });\n\n // Count how many recent clicks are within the radius of the current click\n const nearbyCount = recentClicksRef.current.filter((click) => {\n const dx = click.x - x;\n const dy = click.y - y;\n return Math.sqrt(dx * dx + dy * dy) <= cfg.rageClickRadiusPx;\n }).length;\n\n if (nearbyCount >= cfg.rageClickThreshold) {\n spawnBlast(x, y);\n }\n };\n\n const target = containerRef?.current ?? window;\n const timeoutIds = timeoutIdsRef.current;\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- EventTarget union requires cast\n (target as EventTarget).addEventListener(\"click\", onClick as EventListener);\n return () => {\n (target as EventTarget).removeEventListener(\"click\", onClick as EventListener);\n for (const timeoutId of timeoutIds.values()) {\n window.clearTimeout(timeoutId);\n }\n timeoutIds.clear();\n };\n }, [containerRef]);\n\n if (!mounted) {\n return null;\n }\n\n const blastElements = (\n <>\n {blasts.map((blast) => (\n <div\n key={blast.id}\n style={{\n position: \"absolute\",\n left: blast.x,\n top: blast.y,\n width: blast.size,\n height: blast.size,\n transform: \"translate(-50%, -50%)\",\n willChange: \"transform, opacity\",\n filter: `hue-rotate(${blast.hue}deg)`,\n }}\n >\n <span className=\"cursor-blast-ring\" />\n <span className=\"cursor-blast-core\" />\n {Array.from({ length: 10 }).map((_, index) => {\n const angle = (360 / 10) * index;\n return (\n <span\n key={`${blast.id}-${index}`}\n className=\"cursor-blast-shard-wrap\"\n style={{\n transform: `translate(-50%, -50%) rotate(${angle}deg)`,\n animationDelay: `${index * 16}ms`,\n }}\n >\n <span className=\"cursor-blast-shard\" />\n </span>\n );\n })}\n </div>\n ))}\n <style dangerouslySetInnerHTML={{ __html: `\n .cursor-blast-ring {\n position: absolute;\n inset: 0;\n border-radius: 999px;\n border: 2px solid hsl(197 98% 67% / 0.9);\n box-shadow:\n 0 0 22px hsl(191 100% 72% / 0.6),\n inset 0 0 12px hsl(204 100% 77% / 0.65);\n animation: blast-ring 560ms cubic-bezier(0.16, 1, 0.3, 1) forwards;\n }\n\n .cursor-blast-core {\n position: absolute;\n left: 50%;\n top: 50%;\n width: 10px;\n height: 10px;\n border-radius: 999px;\n transform: translate(-50%, -50%);\n background: hsl(196 100% 85%);\n box-shadow:\n 0 0 26px hsl(193 100% 72% / 0.9),\n 0 0 10px hsl(201 100% 85% / 0.9);\n animation: blast-core 420ms ease-out forwards;\n }\n\n .cursor-blast-shard-wrap {\n position: absolute;\n left: 50%;\n top: 50%;\n width: 0;\n height: 0;\n }\n\n .cursor-blast-shard {\n position: absolute;\n left: 0;\n top: -1.5px;\n width: 12px;\n height: 3px;\n border-radius: 999px;\n background: linear-gradient(90deg, hsl(190 100% 84%), hsl(197 98% 67%));\n box-shadow: 0 0 12px hsl(195 100% 70% / 0.8);\n animation: blast-shard 680ms cubic-bezier(0.22, 1, 0.36, 1) forwards;\n }\n\n @keyframes blast-ring {\n 0% {\n transform: scale(0.2);\n opacity: 0.95;\n }\n 100% {\n transform: scale(1.6);\n opacity: 0;\n }\n }\n\n @keyframes blast-core {\n 0% {\n transform: translate(-50%, -50%) scale(0.5);\n opacity: 1;\n }\n 100% {\n transform: translate(-50%, -50%) scale(2.2);\n opacity: 0;\n }\n }\n\n @keyframes blast-shard {\n 0% {\n transform: translateX(0) scaleX(0.7);\n opacity: 1;\n }\n 100% {\n transform: translateX(46px) scaleX(1.1);\n opacity: 0;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .cursor-blast-ring,\n .cursor-blast-core,\n .cursor-blast-shard {\n animation-duration: 1ms;\n }\n }\n ` }} />\n </>\n );\n\n // When scoped to a container, render inline (the container must have position: relative)\n if (containerRef) {\n return (\n <div\n aria-hidden\n style={{\n position: \"absolute\",\n inset: 0,\n zIndex: 2147483647,\n pointerEvents: \"none\",\n overflow: \"hidden\",\n borderRadius: \"inherit\",\n }}\n >\n {blastElements}\n </div>\n );\n }\n\n // Default: portal to body with fixed positioning (original behaviour)\n return createPortal(\n <div\n aria-hidden\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483647,\n pointerEvents: \"none\",\n }}\n >\n {blastElements}\n </div>,\n document.body,\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cursor-blast-effect.js","names":[],"sources":["../../src/components/cursor-blast-effect.tsx"],"sourcesContent":["\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { createPortal } from \"react-dom\";\n\ntype Blast = {\n id: number,\n x: number,\n y: number,\n size: number,\n hue: number,\n};\n\nconst DEFAULT_BLAST_LIFETIME_MS = 720;\nconst DEFAULT_MAX_ACTIVE_BLASTS = 18;\n\n/** Minimum rapid clicks in the time window to count as a rage click */\nconst DEFAULT_RAGE_CLICK_THRESHOLD = 3;\n/** Time window (ms) in which clicks must occur to be considered rage clicking */\nconst DEFAULT_RAGE_CLICK_WINDOW_MS = 600;\n/** Max distance (px) between clicks to still count as same-spot rage clicking */\nconst DEFAULT_RAGE_CLICK_RADIUS_PX = 60;\n\ntype RecentClick = {\n time: number,\n x: number,\n y: number,\n};\n\nexport type CursorBlastEffectProps = {\n /** Lifetime of each blast animation in ms. Default: 720 */\n blastLifetimeMs?: number,\n /** Maximum number of concurrent active blasts. Default: 18 */\n maxActiveBlasts?: number,\n /** Minimum rapid clicks in the time window to trigger a blast. Default: 3 */\n rageClickThreshold?: number,\n /** Time window (ms) for counting rage clicks. Default: 600 */\n rageClickWindowMs?: number,\n /** Max distance (px) between clicks to count as same-spot rage clicking. Default: 60 */\n rageClickRadiusPx?: number,\n /**\n * When provided, the blast effect is scoped to this container element.\n * Clicks are only detected within the container and blasts are positioned\n * relative to the container rather than the viewport.\n */\n containerRef?: React.RefObject<HTMLElement | null>,\n};\n\nexport function CursorBlastEffect({\n blastLifetimeMs = DEFAULT_BLAST_LIFETIME_MS,\n maxActiveBlasts = DEFAULT_MAX_ACTIVE_BLASTS,\n rageClickThreshold = DEFAULT_RAGE_CLICK_THRESHOLD,\n rageClickWindowMs = DEFAULT_RAGE_CLICK_WINDOW_MS,\n rageClickRadiusPx = DEFAULT_RAGE_CLICK_RADIUS_PX,\n containerRef,\n}: CursorBlastEffectProps = {}) {\n const [blasts, setBlasts] = useState<Blast[]>([]);\n const [mounted, setMounted] = useState(false);\n const idCounterRef = useRef(0);\n const timeoutIdsRef = useRef<Map<number, number>>(new Map());\n const recentClicksRef = useRef<RecentClick[]>([]);\n\n // Store latest config in refs so the effect callback always reads current values\n const configRef = useRef({\n blastLifetimeMs,\n maxActiveBlasts,\n rageClickThreshold,\n rageClickWindowMs,\n rageClickRadiusPx,\n });\n configRef.current = {\n blastLifetimeMs,\n maxActiveBlasts,\n rageClickThreshold,\n rageClickWindowMs,\n rageClickRadiusPx,\n };\n\n useEffect(() => {\n setMounted(true);\n }, []);\n\n useEffect(() => {\n const removeBlast = (id: number) => {\n setBlasts((prev) => prev.filter((blast) => blast.id !== id));\n const timeoutId = timeoutIdsRef.current.get(id);\n if (timeoutId !== undefined) {\n window.clearTimeout(timeoutId);\n timeoutIdsRef.current.delete(id);\n }\n };\n\n const spawnBlast = (x: number, y: number) => {\n const cfg = configRef.current;\n const nextId = idCounterRef.current;\n idCounterRef.current += 1;\n\n const nextBlast: Blast = {\n id: nextId,\n x,\n y,\n size: 44 + Math.random() * 20,\n hue: 185 + Math.random() * 35,\n };\n\n setBlasts((prev) => {\n const next = [...prev, nextBlast];\n if (next.length <= cfg.maxActiveBlasts) {\n return next;\n }\n return next.slice(next.length - cfg.maxActiveBlasts);\n });\n\n const timeoutId = window.setTimeout(() => removeBlast(nextId), cfg.blastLifetimeMs);\n timeoutIdsRef.current.set(nextId, timeoutId);\n };\n\n const onClick = (event: MouseEvent) => {\n if (window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches) {\n return;\n }\n\n const cfg = configRef.current;\n const now = performance.now();\n\n let x: number;\n let y: number;\n\n if (containerRef?.current) {\n const rect = containerRef.current.getBoundingClientRect();\n x = event.clientX - rect.left;\n y = event.clientY - rect.top;\n } else {\n x = event.clientX;\n y = event.clientY;\n }\n\n // Prune clicks outside the time window\n recentClicksRef.current = recentClicksRef.current.filter(\n (click) => now - click.time < cfg.rageClickWindowMs,\n );\n\n recentClicksRef.current.push({ time: now, x, y });\n\n // Count how many recent clicks are within the radius of the current click\n const nearbyCount = recentClicksRef.current.filter((click) => {\n const dx = click.x - x;\n const dy = click.y - y;\n return Math.sqrt(dx * dx + dy * dy) <= cfg.rageClickRadiusPx;\n }).length;\n\n if (nearbyCount >= cfg.rageClickThreshold) {\n spawnBlast(x, y);\n }\n };\n\n const target = containerRef?.current ?? window;\n const timeoutIds = timeoutIdsRef.current;\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- EventTarget union requires cast\n (target as EventTarget).addEventListener(\"click\", onClick as EventListener);\n return () => {\n (target as EventTarget).removeEventListener(\"click\", onClick as EventListener);\n for (const timeoutId of timeoutIds.values()) {\n window.clearTimeout(timeoutId);\n }\n timeoutIds.clear();\n };\n }, [containerRef]);\n\n if (!mounted) {\n return null;\n }\n\n const blastElements = (\n <>\n {blasts.map((blast) => (\n <div\n key={blast.id}\n style={{\n position: \"absolute\",\n left: blast.x,\n top: blast.y,\n width: blast.size,\n height: blast.size,\n transform: \"translate(-50%, -50%)\",\n willChange: \"transform, opacity\",\n filter: `hue-rotate(${blast.hue}deg)`,\n }}\n >\n <span className=\"cursor-blast-ring\" />\n <span className=\"cursor-blast-core\" />\n {Array.from({ length: 10 }).map((_, index) => {\n const angle = (360 / 10) * index;\n return (\n <span\n key={`${blast.id}-${index}`}\n className=\"cursor-blast-shard-wrap\"\n style={{\n transform: `translate(-50%, -50%) rotate(${angle}deg)`,\n animationDelay: `${index * 16}ms`,\n }}\n >\n <span className=\"cursor-blast-shard\" />\n </span>\n );\n })}\n </div>\n ))}\n <style dangerouslySetInnerHTML={{ __html: `\n .cursor-blast-ring {\n position: absolute;\n inset: 0;\n border-radius: 999px;\n border: 2px solid hsl(197 98% 67% / 0.9);\n box-shadow:\n 0 0 22px hsl(191 100% 72% / 0.6),\n inset 0 0 12px hsl(204 100% 77% / 0.65);\n animation: blast-ring 560ms cubic-bezier(0.16, 1, 0.3, 1) forwards;\n }\n\n .cursor-blast-core {\n position: absolute;\n left: 50%;\n top: 50%;\n width: 10px;\n height: 10px;\n border-radius: 999px;\n transform: translate(-50%, -50%);\n background: hsl(196 100% 85%);\n box-shadow:\n 0 0 26px hsl(193 100% 72% / 0.9),\n 0 0 10px hsl(201 100% 85% / 0.9);\n animation: blast-core 420ms ease-out forwards;\n }\n\n .cursor-blast-shard-wrap {\n position: absolute;\n left: 50%;\n top: 50%;\n width: 0;\n height: 0;\n }\n\n .cursor-blast-shard {\n position: absolute;\n left: 0;\n top: -1.5px;\n width: 12px;\n height: 3px;\n border-radius: 999px;\n background: linear-gradient(90deg, hsl(190 100% 84%), hsl(197 98% 67%));\n box-shadow: 0 0 12px hsl(195 100% 70% / 0.8);\n animation: blast-shard 680ms cubic-bezier(0.22, 1, 0.36, 1) forwards;\n }\n\n @keyframes blast-ring {\n 0% {\n transform: scale(0.2);\n opacity: 0.95;\n }\n 100% {\n transform: scale(1.6);\n opacity: 0;\n }\n }\n\n @keyframes blast-core {\n 0% {\n transform: translate(-50%, -50%) scale(0.5);\n opacity: 1;\n }\n 100% {\n transform: translate(-50%, -50%) scale(2.2);\n opacity: 0;\n }\n }\n\n @keyframes blast-shard {\n 0% {\n transform: translateX(0) scaleX(0.7);\n opacity: 1;\n }\n 100% {\n transform: translateX(46px) scaleX(1.1);\n opacity: 0;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .cursor-blast-ring,\n .cursor-blast-core,\n .cursor-blast-shard {\n animation-duration: 1ms;\n }\n }\n ` }} />\n </>\n );\n\n // When scoped to a container, render inline (the container must have position: relative)\n if (containerRef) {\n return (\n <div\n aria-hidden\n style={{\n position: \"absolute\",\n inset: 0,\n zIndex: 2147483647,\n pointerEvents: \"none\",\n overflow: \"hidden\",\n borderRadius: \"inherit\",\n }}\n >\n {blastElements}\n </div>\n );\n }\n\n // Default: portal to body with fixed positioning (original behaviour)\n return createPortal(\n <div\n aria-hidden\n style={{\n position: \"fixed\",\n inset: 0,\n zIndex: 2147483647,\n pointerEvents: \"none\",\n }}\n >\n {blastElements}\n </div>,\n document.body,\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
1
|
+
import { h as DataGridExportOptions, i as DataGridColumnDef } from "../../types-1-eOd1JF.js";
|
|
3
2
|
|
|
4
3
|
//#region src/components/data-grid/data-grid-export-dialog.d.ts
|
|
5
4
|
type DataGridExportDialogProps<TRow> = {
|
|
@@ -17,7 +16,7 @@ declare function DataGridExportDialog<TRow>({
|
|
|
17
16
|
columns,
|
|
18
17
|
exportFilename,
|
|
19
18
|
exportOptions
|
|
20
|
-
}: DataGridExportDialogProps<TRow>):
|
|
19
|
+
}: DataGridExportDialogProps<TRow>): import("react/jsx-runtime").JSX.Element;
|
|
21
20
|
//#endregion
|
|
22
21
|
export { DataGridExportDialog };
|
|
23
22
|
//# sourceMappingURL=data-grid-export-dialog.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-grid-export-dialog.d.ts","names":[],"sources":["../../../src/components/data-grid/data-grid-export-dialog.tsx"],"mappings":"
|
|
1
|
+
{"version":3,"file":"data-grid-export-dialog.d.ts","names":[],"sources":["../../../src/components/data-grid/data-grid-export-dialog.tsx"],"mappings":";;;KA4BK,yBAAA;EACH,IAAA;EACA,YAAA,GAAe,IAAA;EACf,IAAA,WAAe,IAAA;EACf,OAAA,WAAkB,iBAAA,CAAkB,IAAA;EACpC,cAAA;EACA,aAAA,GAAgB,qBAAA,CAAsB,IAAA;AAAA;AAAA,iBASxB,oBAAA;EACd,IAAA;EACA,YAAA;EACA,IAAA;EACA,OAAA;EACA,cAAA;EACA;AAAA,GACC,yBAAA,CAA0B,IAAA,gCAAK,GAAA,CAAA,OAAA"}
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const require_chunk = require('../../chunk-BE-pF4vm.js');
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const require_rolldown_runtime = require("../../rolldown-runtime-D6vf50IK.js");
|
|
5
4
|
let _phosphor_icons_react = require("@phosphor-icons/react");
|
|
6
5
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
7
6
|
let react = require("react");
|
|
8
|
-
react =
|
|
7
|
+
react = require_rolldown_runtime.__toESM(react);
|
|
9
8
|
let ___button_js = require("../button.js");
|
|
10
9
|
let __state_js = require("./state.js");
|
|
11
10
|
let ___dialog_js = require("../dialog.js");
|
|
12
|
-
|
|
13
11
|
//#region src/components/data-grid/data-grid-export-dialog.tsx
|
|
14
12
|
const idleExportProgress = {
|
|
15
13
|
phase: "idle",
|
|
@@ -406,7 +404,7 @@ function buildExportFilename(prefix) {
|
|
|
406
404
|
function titleCase(value) {
|
|
407
405
|
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
408
406
|
}
|
|
409
|
-
|
|
410
407
|
//#endregion
|
|
411
408
|
exports.DataGridExportDialog = DataGridExportDialog;
|
|
409
|
+
|
|
412
410
|
//# sourceMappingURL=data-grid-export-dialog.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-grid-export-dialog.js","names":["DesignDialog","DesignButton","DownloadSimpleIcon"],"sources":["../../../src/components/data-grid/data-grid-export-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { DownloadSimpleIcon } from \"@phosphor-icons/react\";\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\nimport { DesignButton } from \"../button\";\nimport { DesignDialog } from \"../dialog\";\nimport { formatGridDate, resolveColumnValue } from \"./state\";\nimport type {\n DataGridColumnDef,\n DataGridExportField,\n DataGridExportFormat,\n DataGridExportOptions,\n DataGridExportScope,\n} from \"./types\";\n\ntype ExportProgress = {\n phase: \"idle\" | \"fetching\" | \"generating\" | \"complete\";\n fetched: number;\n};\n\ntype ExportCellValue = string | number | boolean | null | undefined;\ntype ExportTable = {\n csvHeaders: string[];\n jsonKeys: string[];\n rows: ExportCellValue[][];\n};\n\ntype DataGridExportDialogProps<TRow> = {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n rows: readonly TRow[];\n columns: readonly DataGridColumnDef<TRow>[];\n exportFilename: string;\n exportOptions?: DataGridExportOptions<TRow>;\n};\n\nconst idleExportProgress: ExportProgress = {\n phase: \"idle\",\n fetched: 0,\n};\nconst exportCompletionDisplayMs = 800;\n\nexport function DataGridExportDialog<TRow>({\n open,\n onOpenChange,\n rows,\n columns,\n exportFilename,\n exportOptions,\n}: DataGridExportDialogProps<TRow>) {\n const hasServerExport = exportOptions?.fetchRows != null;\n const resolvedFields = useMemo(\n () => exportOptions?.fields ?? buildColumnExportFields(columns),\n [exportOptions?.fields, columns],\n );\n const [format, setFormat] = useState<DataGridExportFormat>(\"csv\");\n const [scope, setScope] = useState<DataGridExportScope>(exportOptions?.defaultScope ?? \"all\");\n const [fields, setFields] = useState<readonly DataGridExportField<TRow>[]>(resolvedFields);\n const [isExporting, setIsExporting] = useState(false);\n const [progress, setProgress] = useState<ExportProgress>(idleExportProgress);\n const [errorMessage, setErrorMessage] = useState<string | null>(null);\n\n useEffect(() => {\n if (!isExporting) {\n setFields(resolvedFields);\n }\n }, [isExporting, resolvedFields]);\n\n // Reset the scope to its default each time the dialog opens. The dialog stays\n // mounted between opens, so without this the scope would retain whatever the\n // user last picked instead of honoring `defaultScope` on every open. We track\n // the previous `open` value with a ref so the reset only fires on a genuine\n // closed->open transition -- not on every render that flips other state (e.g.\n // `isExporting` going false after a failed/empty export would otherwise wipe\n // the user's current selection while the dialog is still open).\n const defaultScope = exportOptions?.defaultScope ?? \"all\";\n const wasOpenRef = useRef(false);\n useEffect(() => {\n if (open && !wasOpenRef.current) {\n setScope(defaultScope);\n }\n wasOpenRef.current = open;\n }, [open, defaultScope]);\n\n const entityName = exportOptions?.entityName ?? \"row\";\n const entityNamePlural = exportOptions?.entityNamePlural ?? \"rows\";\n const filenamePrefix = exportOptions?.filenamePrefix ?? exportFilename;\n const title = exportOptions?.title ?? \"Export data\";\n const description = exportOptions?.description ?? (\n hasServerExport\n ? \"Configure and download data from this table\"\n : \"Configure and download the rows currently loaded in this table\"\n );\n const allScopeLabel = exportOptions?.allScopeLabel ?? `Export all ${entityNamePlural} in the project`;\n const filteredScopeLabel = exportOptions?.filteredScopeLabel ?? `Export only filtered/searched ${entityNamePlural}`;\n const progressSubjectLabel = exportOptions?.progressSubjectLabel ?? entityNamePlural;\n const progressTitle = progress.phase === \"complete\" ? \"Export complete\" : `Exporting ${progressSubjectLabel}`;\n const fetchExportRows = exportOptions?.fetchRows;\n\n const closeDialog = useCallback(() => {\n onOpenChange(false);\n setErrorMessage(null);\n }, [onOpenChange]);\n\n const handleOpenChange = useCallback((nextOpen: boolean) => {\n if (isExporting && !nextOpen) {\n return;\n }\n if (nextOpen) {\n onOpenChange(true);\n } else {\n closeDialog();\n }\n }, [closeDialog, isExporting, onOpenChange]);\n\n const toggleField = useCallback((key: string) => {\n setFields((prev) =>\n prev.map((field) =>\n field.key === key ? { ...field, enabled: !field.enabled } : field\n )\n );\n }, []);\n\n const selectAllFields = useCallback(() => {\n setFields((prev) => prev.map((field) => ({ ...field, enabled: true })));\n }, []);\n\n const deselectAllFields = useCallback(() => {\n setFields((prev) => prev.map((field) => ({ ...field, enabled: false })));\n }, []);\n\n const fetchRows = useCallback(async () => {\n if (fetchExportRows != null) {\n return await fetchExportRows({\n scope,\n onProgress: (fetched) => setProgress({ phase: \"fetching\", fetched }),\n });\n }\n\n setProgress({ phase: \"fetching\", fetched: rows.length });\n return rows;\n }, [fetchExportRows, rows, scope]);\n\n const handleExport = async () => {\n const enabledFields = fields.filter((field) => field.enabled);\n if (enabledFields.length === 0) {\n setErrorMessage(\"Select at least one field to export.\");\n return;\n }\n\n setErrorMessage(null);\n setIsExporting(true);\n setProgress({ phase: \"fetching\", fetched: 0 });\n try {\n const exportRows = await fetchRows();\n\n if (exportRows.length === 0) {\n setErrorMessage(\n exportOptions?.emptyExportDescription\n ?? `There are no ${entityNamePlural} to export.`,\n );\n setIsExporting(false);\n setProgress(idleExportProgress);\n return;\n }\n\n setProgress({ phase: \"generating\", fetched: exportRows.length });\n const transformedData = buildExportTable(exportRows, enabledFields);\n\n if (format === \"csv\") {\n exportToCsv(transformedData, filenamePrefix);\n } else {\n exportToJson(transformedData, filenamePrefix);\n }\n\n setProgress({ phase: \"complete\", fetched: exportRows.length });\n await new Promise<void>((resolve) => setTimeout(resolve, exportCompletionDisplayMs));\n closeDialog();\n } catch {\n setErrorMessage(\"Something went wrong while exporting. Please try again.\");\n } finally {\n setIsExporting(false);\n setProgress(idleExportProgress);\n }\n };\n\n return (\n <DesignDialog\n open={open}\n onOpenChange={handleOpenChange}\n title={isExporting ? progressTitle : title}\n description={isExporting ? `Preparing export for ${progressSubjectLabel}.` : description}\n size=\"2xl\"\n variant=\"plain\"\n headerClassName={isExporting ? \"sr-only\" : undefined}\n hideTopCloseButton={isExporting}\n >\n {isExporting ? (\n <ExportProgressContent\n progress={progress}\n format={format}\n subjectLabel={progressSubjectLabel}\n />\n ) : (\n <div className=\"space-y-6\">\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\" htmlFor={`${filenamePrefix}-export-format`}>\n Export Format\n </label>\n <select\n id={`${filenamePrefix}-export-format`}\n value={format}\n onChange={(event) => setFormat(event.currentTarget.value === \"json\" ? \"json\" : \"csv\")}\n className=\"h-9 w-full rounded-md border border-input bg-white px-3 text-sm dark:bg-background\"\n >\n <option value=\"csv\">CSV (Comma-separated values)</option>\n <option value=\"json\">JSON (JavaScript Object Notation)</option>\n </select>\n </div>\n\n {hasServerExport ? (\n <fieldset className=\"space-y-2\">\n <legend className=\"text-sm font-medium\">Export Scope</legend>\n <label className=\"flex cursor-pointer items-center gap-2 text-sm\">\n <input\n type=\"radio\"\n name={`${filenamePrefix}-export-scope`}\n value=\"all\"\n checked={scope === \"all\"}\n onChange={() => setScope(\"all\")}\n />\n <span>{allScopeLabel}</span>\n </label>\n <label className=\"flex cursor-pointer items-center gap-2 text-sm\">\n <input\n type=\"radio\"\n name={`${filenamePrefix}-export-scope`}\n value=\"filtered\"\n checked={scope === \"filtered\"}\n onChange={() => setScope(\"filtered\")}\n />\n <span>{filteredScopeLabel}</span>\n </label>\n </fieldset>\n ) : null}\n\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between gap-3\">\n <label className=\"text-sm font-medium\">Fields to Export</label>\n <div className=\"flex gap-2\">\n <DesignButton type=\"button\" variant=\"ghost\" size=\"sm\" onClick={selectAllFields} className=\"h-7 text-xs\">\n Select All\n </DesignButton>\n <DesignButton type=\"button\" variant=\"ghost\" size=\"sm\" onClick={deselectAllFields} className=\"h-7 text-xs\">\n Deselect All\n </DesignButton>\n </div>\n </div>\n <div className=\"grid max-h-[300px] grid-cols-1 gap-3 overflow-y-auto rounded-lg border border-border p-4 sm:grid-cols-2\">\n {fields.map((field) => (\n <label key={field.key} className=\"flex cursor-pointer items-center gap-2 text-sm font-normal\">\n <input\n type=\"checkbox\"\n checked={field.enabled}\n onChange={() => toggleField(field.key)}\n />\n <span>{field.label}</span>\n </label>\n ))}\n </div>\n </div>\n\n {errorMessage != null ? (\n <div className=\"rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n <div className=\"font-medium\">{exportOptions?.emptyExportTitle ?? \"Export unavailable\"}</div>\n <div>{errorMessage}</div>\n </div>\n ) : null}\n\n <div className=\"flex justify-end gap-3 pt-2\">\n <DesignButton variant=\"outline\" onClick={closeDialog}>\n Cancel\n </DesignButton>\n <DesignButton onClick={handleExport}>\n <DownloadSimpleIcon className=\"mr-2 h-4 w-4\" />\n Export {titleCase(entityNamePlural)}\n </DesignButton>\n </div>\n </div>\n )}\n </DesignDialog>\n );\n}\n\nfunction ExportProgressContent(props: {\n progress: ExportProgress;\n format: DataGridExportFormat;\n subjectLabel: string;\n}) {\n const { progress, format, subjectLabel } = props;\n const fileLabel = format.toUpperCase();\n const isComplete = progress.phase === \"complete\";\n const title = isComplete ? \"Export complete\" : `Exporting ${subjectLabel}`;\n const description = isComplete\n ? `Your ${fileLabel} is ready and the download should begin automatically.`\n : `Your ${fileLabel} is being prepared from matching ${subjectLabel}.`;\n const statusLabel = progress.phase === \"complete\"\n ? \"Download ready\"\n : progress.phase === \"generating\"\n ? `Preparing ${fileLabel}`\n : `Fetching ${subjectLabel}`;\n const countLabel = `${progress.fetched.toLocaleString()} ${isComplete ? \"exported\" : \"fetched\"}`;\n\n return (\n <div className=\"space-y-4\">\n <div className=\"space-y-1\">\n <h2 className=\"text-base font-semibold leading-snug\">{title}</h2>\n <p className=\"text-sm text-muted-foreground\">{description}</p>\n </div>\n\n <div className=\"rounded-xl border border-border bg-muted/35 p-4\">\n <div className=\"mb-3 flex items-center justify-between gap-4 text-sm\">\n <span className=\"font-medium text-foreground\">{statusLabel}</span>\n <span className=\"shrink-0 tabular-nums text-muted-foreground\">\n {countLabel}\n </span>\n </div>\n <div className=\"relative h-2 overflow-hidden rounded-full bg-foreground/10\">\n {isComplete ? (\n <div className=\"h-full w-full rounded-full bg-emerald-500/80\" />\n ) : (\n <div className=\"data-grid-export-progress-shimmer absolute inset-y-0 left-0 w-2/5 rounded-full bg-gradient-to-r from-transparent via-foreground/65 to-transparent\" />\n )}\n </div>\n </div>\n\n <div className=\"rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-900 dark:border-amber-500/30 dark:bg-amber-500/10 dark:text-amber-200\">\n Do not reload this page until the export finishes. The download will start automatically.\n </div>\n\n <div className=\"flex justify-end gap-3 pt-2\">\n <DesignButton variant=\"outline\" disabled>\n Cancel\n </DesignButton>\n </div>\n </div>\n );\n}\n\nfunction buildColumnExportFields<TRow>(\n columns: readonly DataGridColumnDef<TRow>[],\n): readonly DataGridExportField<TRow>[] {\n const fields: DataGridExportField<TRow>[] = [];\n\n for (const column of columns) {\n const label = typeof column.header === \"string\" ? column.header.trim() : column.id;\n if (label.length === 0) {\n continue;\n }\n\n fields.push({\n key: column.id,\n label,\n enabled: true,\n getValue: (row) => formatColumnExportValue(column, row),\n });\n }\n\n return fields;\n}\n\nfunction formatColumnExportValue<TRow>(\n column: DataGridColumnDef<TRow>,\n row: TRow,\n): unknown {\n const value = resolveColumnValue(column, row);\n if (column.formatValue != null) {\n return column.formatValue(value, row);\n }\n if (column.type === \"date\" || column.type === \"dateTime\") {\n return formatGridDate(value, \"absolute\", {\n parseValue: column.parseValue,\n dateFormat: column.dateFormat,\n }).display ?? \"\";\n }\n return value;\n}\n\nfunction buildExportTable<TRow>(\n rows: readonly TRow[],\n enabledFields: readonly DataGridExportField<TRow>[],\n): ExportTable {\n return {\n csvHeaders: enabledFields.map((field) => field.label),\n jsonKeys: buildJsonKeys(enabledFields),\n rows: rows.map((row) => enabledFields.map((field) => toExportCellValue(field.getValue(row)))),\n };\n}\n\nfunction buildJsonKeys<TRow>(\n fields: readonly DataGridExportField<TRow>[],\n): string[] {\n const labelCounts = new Map<string, number>();\n for (const field of fields) {\n labelCounts.set(field.label, (labelCounts.get(field.label) ?? 0) + 1);\n }\n\n const usedKeys = new Map<string, true>();\n const keys: string[] = [];\n for (const field of fields) {\n const baseKey = labelCounts.get(field.label) === 1 ? field.label : `${field.label} (${field.key})`;\n let key = baseKey;\n let suffix = 2;\n while (usedKeys.has(key)) {\n key = `${baseKey} ${suffix}`;\n suffix++;\n }\n usedKeys.set(key, true);\n keys.push(key);\n }\n\n return keys;\n}\n\nfunction toExportCellValue(value: unknown): ExportCellValue {\n if (value == null) {\n return \"\";\n }\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return value;\n }\n if (typeof value === \"bigint\") {\n return value.toString();\n }\n if (value instanceof Date) {\n return value.toISOString();\n }\n if (typeof value === \"object\") {\n return JSON.stringify(value);\n }\n return String(value);\n}\n\nfunction exportToCsv(data: ExportTable, filenamePrefix: string) {\n const csvContent = \"\\uFEFF\" + [\n data.csvHeaders.map(escapeCsvCell).join(\",\"),\n ...data.rows.map((row) => row.map(escapeCsvCell).join(\",\")),\n ].join(\"\\n\");\n downloadFile(csvContent, `${buildExportFilename(filenamePrefix)}.csv`, \"text/csv;charset=utf-8;\");\n}\n\nfunction escapeCsvCell(value: ExportCellValue): string {\n const rawText = String(value ?? \"\");\n const text = typeof value === \"string\" && /^[=+\\-@\\t\\r]/.test(rawText.trimStart()) ? `'${rawText}` : rawText;\n if (text.includes(\",\") || text.includes('\"') || text.includes(\"\\n\") || text.includes(\"\\r\")) {\n return `\"${text.replace(/\"/g, '\"\"')}\"`;\n }\n return text;\n}\n\nfunction exportToJson(data: ExportTable, filenamePrefix: string) {\n const rows = data.rows.map((row) => {\n const jsonRow: Record<string, ExportCellValue> = {};\n for (let i = 0; i < data.jsonKeys.length; i++) {\n jsonRow[data.jsonKeys[i]] = row[i] ?? \"\";\n }\n return jsonRow;\n });\n const jsonString = JSON.stringify(rows, null, 2);\n downloadFile(jsonString, `${buildExportFilename(filenamePrefix)}.json`, \"application/json\");\n}\n\nfunction downloadFile(content: string, filename: string, type: string) {\n const blob = new Blob([content], { type });\n const url = URL.createObjectURL(blob);\n const link = document.createElement(\"a\");\n link.href = url;\n link.download = filename;\n document.body.appendChild(link);\n try {\n link.click();\n } finally {\n link.remove();\n URL.revokeObjectURL(url);\n }\n}\n\nfunction buildExportFilename(prefix: string) {\n return `${prefix}-${new Date().toISOString().split(\"T\")[0]}`;\n}\n\nfunction titleCase(value: string) {\n return value.charAt(0).toUpperCase() + value.slice(1);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"data-grid-export-dialog.js","names":["DesignDialog","DesignButton","DownloadSimpleIcon"],"sources":["../../../src/components/data-grid/data-grid-export-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport { DownloadSimpleIcon } from \"@phosphor-icons/react\";\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\nimport { DesignButton } from \"../button\";\nimport { DesignDialog } from \"../dialog\";\nimport { formatGridDate, resolveColumnValue } from \"./state\";\nimport type {\n DataGridColumnDef,\n DataGridExportField,\n DataGridExportFormat,\n DataGridExportOptions,\n DataGridExportScope,\n} from \"./types\";\n\ntype ExportProgress = {\n phase: \"idle\" | \"fetching\" | \"generating\" | \"complete\";\n fetched: number;\n};\n\ntype ExportCellValue = string | number | boolean | null | undefined;\ntype ExportTable = {\n csvHeaders: string[];\n jsonKeys: string[];\n rows: ExportCellValue[][];\n};\n\ntype DataGridExportDialogProps<TRow> = {\n open: boolean;\n onOpenChange: (open: boolean) => void;\n rows: readonly TRow[];\n columns: readonly DataGridColumnDef<TRow>[];\n exportFilename: string;\n exportOptions?: DataGridExportOptions<TRow>;\n};\n\nconst idleExportProgress: ExportProgress = {\n phase: \"idle\",\n fetched: 0,\n};\nconst exportCompletionDisplayMs = 800;\n\nexport function DataGridExportDialog<TRow>({\n open,\n onOpenChange,\n rows,\n columns,\n exportFilename,\n exportOptions,\n}: DataGridExportDialogProps<TRow>) {\n const hasServerExport = exportOptions?.fetchRows != null;\n const resolvedFields = useMemo(\n () => exportOptions?.fields ?? buildColumnExportFields(columns),\n [exportOptions?.fields, columns],\n );\n const [format, setFormat] = useState<DataGridExportFormat>(\"csv\");\n const [scope, setScope] = useState<DataGridExportScope>(exportOptions?.defaultScope ?? \"all\");\n const [fields, setFields] = useState<readonly DataGridExportField<TRow>[]>(resolvedFields);\n const [isExporting, setIsExporting] = useState(false);\n const [progress, setProgress] = useState<ExportProgress>(idleExportProgress);\n const [errorMessage, setErrorMessage] = useState<string | null>(null);\n\n useEffect(() => {\n if (!isExporting) {\n setFields(resolvedFields);\n }\n }, [isExporting, resolvedFields]);\n\n // Reset the scope to its default each time the dialog opens. The dialog stays\n // mounted between opens, so without this the scope would retain whatever the\n // user last picked instead of honoring `defaultScope` on every open. We track\n // the previous `open` value with a ref so the reset only fires on a genuine\n // closed->open transition -- not on every render that flips other state (e.g.\n // `isExporting` going false after a failed/empty export would otherwise wipe\n // the user's current selection while the dialog is still open).\n const defaultScope = exportOptions?.defaultScope ?? \"all\";\n const wasOpenRef = useRef(false);\n useEffect(() => {\n if (open && !wasOpenRef.current) {\n setScope(defaultScope);\n }\n wasOpenRef.current = open;\n }, [open, defaultScope]);\n\n const entityName = exportOptions?.entityName ?? \"row\";\n const entityNamePlural = exportOptions?.entityNamePlural ?? \"rows\";\n const filenamePrefix = exportOptions?.filenamePrefix ?? exportFilename;\n const title = exportOptions?.title ?? \"Export data\";\n const description = exportOptions?.description ?? (\n hasServerExport\n ? \"Configure and download data from this table\"\n : \"Configure and download the rows currently loaded in this table\"\n );\n const allScopeLabel = exportOptions?.allScopeLabel ?? `Export all ${entityNamePlural} in the project`;\n const filteredScopeLabel = exportOptions?.filteredScopeLabel ?? `Export only filtered/searched ${entityNamePlural}`;\n const progressSubjectLabel = exportOptions?.progressSubjectLabel ?? entityNamePlural;\n const progressTitle = progress.phase === \"complete\" ? \"Export complete\" : `Exporting ${progressSubjectLabel}`;\n const fetchExportRows = exportOptions?.fetchRows;\n\n const closeDialog = useCallback(() => {\n onOpenChange(false);\n setErrorMessage(null);\n }, [onOpenChange]);\n\n const handleOpenChange = useCallback((nextOpen: boolean) => {\n if (isExporting && !nextOpen) {\n return;\n }\n if (nextOpen) {\n onOpenChange(true);\n } else {\n closeDialog();\n }\n }, [closeDialog, isExporting, onOpenChange]);\n\n const toggleField = useCallback((key: string) => {\n setFields((prev) =>\n prev.map((field) =>\n field.key === key ? { ...field, enabled: !field.enabled } : field\n )\n );\n }, []);\n\n const selectAllFields = useCallback(() => {\n setFields((prev) => prev.map((field) => ({ ...field, enabled: true })));\n }, []);\n\n const deselectAllFields = useCallback(() => {\n setFields((prev) => prev.map((field) => ({ ...field, enabled: false })));\n }, []);\n\n const fetchRows = useCallback(async () => {\n if (fetchExportRows != null) {\n return await fetchExportRows({\n scope,\n onProgress: (fetched) => setProgress({ phase: \"fetching\", fetched }),\n });\n }\n\n setProgress({ phase: \"fetching\", fetched: rows.length });\n return rows;\n }, [fetchExportRows, rows, scope]);\n\n const handleExport = async () => {\n const enabledFields = fields.filter((field) => field.enabled);\n if (enabledFields.length === 0) {\n setErrorMessage(\"Select at least one field to export.\");\n return;\n }\n\n setErrorMessage(null);\n setIsExporting(true);\n setProgress({ phase: \"fetching\", fetched: 0 });\n try {\n const exportRows = await fetchRows();\n\n if (exportRows.length === 0) {\n setErrorMessage(\n exportOptions?.emptyExportDescription\n ?? `There are no ${entityNamePlural} to export.`,\n );\n setIsExporting(false);\n setProgress(idleExportProgress);\n return;\n }\n\n setProgress({ phase: \"generating\", fetched: exportRows.length });\n const transformedData = buildExportTable(exportRows, enabledFields);\n\n if (format === \"csv\") {\n exportToCsv(transformedData, filenamePrefix);\n } else {\n exportToJson(transformedData, filenamePrefix);\n }\n\n setProgress({ phase: \"complete\", fetched: exportRows.length });\n await new Promise<void>((resolve) => setTimeout(resolve, exportCompletionDisplayMs));\n closeDialog();\n } catch {\n setErrorMessage(\"Something went wrong while exporting. Please try again.\");\n } finally {\n setIsExporting(false);\n setProgress(idleExportProgress);\n }\n };\n\n return (\n <DesignDialog\n open={open}\n onOpenChange={handleOpenChange}\n title={isExporting ? progressTitle : title}\n description={isExporting ? `Preparing export for ${progressSubjectLabel}.` : description}\n size=\"2xl\"\n variant=\"plain\"\n headerClassName={isExporting ? \"sr-only\" : undefined}\n hideTopCloseButton={isExporting}\n >\n {isExporting ? (\n <ExportProgressContent\n progress={progress}\n format={format}\n subjectLabel={progressSubjectLabel}\n />\n ) : (\n <div className=\"space-y-6\">\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\" htmlFor={`${filenamePrefix}-export-format`}>\n Export Format\n </label>\n <select\n id={`${filenamePrefix}-export-format`}\n value={format}\n onChange={(event) => setFormat(event.currentTarget.value === \"json\" ? \"json\" : \"csv\")}\n className=\"h-9 w-full rounded-md border border-input bg-white px-3 text-sm dark:bg-background\"\n >\n <option value=\"csv\">CSV (Comma-separated values)</option>\n <option value=\"json\">JSON (JavaScript Object Notation)</option>\n </select>\n </div>\n\n {hasServerExport ? (\n <fieldset className=\"space-y-2\">\n <legend className=\"text-sm font-medium\">Export Scope</legend>\n <label className=\"flex cursor-pointer items-center gap-2 text-sm\">\n <input\n type=\"radio\"\n name={`${filenamePrefix}-export-scope`}\n value=\"all\"\n checked={scope === \"all\"}\n onChange={() => setScope(\"all\")}\n />\n <span>{allScopeLabel}</span>\n </label>\n <label className=\"flex cursor-pointer items-center gap-2 text-sm\">\n <input\n type=\"radio\"\n name={`${filenamePrefix}-export-scope`}\n value=\"filtered\"\n checked={scope === \"filtered\"}\n onChange={() => setScope(\"filtered\")}\n />\n <span>{filteredScopeLabel}</span>\n </label>\n </fieldset>\n ) : null}\n\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between gap-3\">\n <label className=\"text-sm font-medium\">Fields to Export</label>\n <div className=\"flex gap-2\">\n <DesignButton type=\"button\" variant=\"ghost\" size=\"sm\" onClick={selectAllFields} className=\"h-7 text-xs\">\n Select All\n </DesignButton>\n <DesignButton type=\"button\" variant=\"ghost\" size=\"sm\" onClick={deselectAllFields} className=\"h-7 text-xs\">\n Deselect All\n </DesignButton>\n </div>\n </div>\n <div className=\"grid max-h-[300px] grid-cols-1 gap-3 overflow-y-auto rounded-lg border border-border p-4 sm:grid-cols-2\">\n {fields.map((field) => (\n <label key={field.key} className=\"flex cursor-pointer items-center gap-2 text-sm font-normal\">\n <input\n type=\"checkbox\"\n checked={field.enabled}\n onChange={() => toggleField(field.key)}\n />\n <span>{field.label}</span>\n </label>\n ))}\n </div>\n </div>\n\n {errorMessage != null ? (\n <div className=\"rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-sm text-destructive\">\n <div className=\"font-medium\">{exportOptions?.emptyExportTitle ?? \"Export unavailable\"}</div>\n <div>{errorMessage}</div>\n </div>\n ) : null}\n\n <div className=\"flex justify-end gap-3 pt-2\">\n <DesignButton variant=\"outline\" onClick={closeDialog}>\n Cancel\n </DesignButton>\n <DesignButton onClick={handleExport}>\n <DownloadSimpleIcon className=\"mr-2 h-4 w-4\" />\n Export {titleCase(entityNamePlural)}\n </DesignButton>\n </div>\n </div>\n )}\n </DesignDialog>\n );\n}\n\nfunction ExportProgressContent(props: {\n progress: ExportProgress;\n format: DataGridExportFormat;\n subjectLabel: string;\n}) {\n const { progress, format, subjectLabel } = props;\n const fileLabel = format.toUpperCase();\n const isComplete = progress.phase === \"complete\";\n const title = isComplete ? \"Export complete\" : `Exporting ${subjectLabel}`;\n const description = isComplete\n ? `Your ${fileLabel} is ready and the download should begin automatically.`\n : `Your ${fileLabel} is being prepared from matching ${subjectLabel}.`;\n const statusLabel = progress.phase === \"complete\"\n ? \"Download ready\"\n : progress.phase === \"generating\"\n ? `Preparing ${fileLabel}`\n : `Fetching ${subjectLabel}`;\n const countLabel = `${progress.fetched.toLocaleString()} ${isComplete ? \"exported\" : \"fetched\"}`;\n\n return (\n <div className=\"space-y-4\">\n <div className=\"space-y-1\">\n <h2 className=\"text-base font-semibold leading-snug\">{title}</h2>\n <p className=\"text-sm text-muted-foreground\">{description}</p>\n </div>\n\n <div className=\"rounded-xl border border-border bg-muted/35 p-4\">\n <div className=\"mb-3 flex items-center justify-between gap-4 text-sm\">\n <span className=\"font-medium text-foreground\">{statusLabel}</span>\n <span className=\"shrink-0 tabular-nums text-muted-foreground\">\n {countLabel}\n </span>\n </div>\n <div className=\"relative h-2 overflow-hidden rounded-full bg-foreground/10\">\n {isComplete ? (\n <div className=\"h-full w-full rounded-full bg-emerald-500/80\" />\n ) : (\n <div className=\"data-grid-export-progress-shimmer absolute inset-y-0 left-0 w-2/5 rounded-full bg-gradient-to-r from-transparent via-foreground/65 to-transparent\" />\n )}\n </div>\n </div>\n\n <div className=\"rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-sm text-amber-900 dark:border-amber-500/30 dark:bg-amber-500/10 dark:text-amber-200\">\n Do not reload this page until the export finishes. The download will start automatically.\n </div>\n\n <div className=\"flex justify-end gap-3 pt-2\">\n <DesignButton variant=\"outline\" disabled>\n Cancel\n </DesignButton>\n </div>\n </div>\n );\n}\n\nfunction buildColumnExportFields<TRow>(\n columns: readonly DataGridColumnDef<TRow>[],\n): readonly DataGridExportField<TRow>[] {\n const fields: DataGridExportField<TRow>[] = [];\n\n for (const column of columns) {\n const label = typeof column.header === \"string\" ? column.header.trim() : column.id;\n if (label.length === 0) {\n continue;\n }\n\n fields.push({\n key: column.id,\n label,\n enabled: true,\n getValue: (row) => formatColumnExportValue(column, row),\n });\n }\n\n return fields;\n}\n\nfunction formatColumnExportValue<TRow>(\n column: DataGridColumnDef<TRow>,\n row: TRow,\n): unknown {\n const value = resolveColumnValue(column, row);\n if (column.formatValue != null) {\n return column.formatValue(value, row);\n }\n if (column.type === \"date\" || column.type === \"dateTime\") {\n return formatGridDate(value, \"absolute\", {\n parseValue: column.parseValue,\n dateFormat: column.dateFormat,\n }).display ?? \"\";\n }\n return value;\n}\n\nfunction buildExportTable<TRow>(\n rows: readonly TRow[],\n enabledFields: readonly DataGridExportField<TRow>[],\n): ExportTable {\n return {\n csvHeaders: enabledFields.map((field) => field.label),\n jsonKeys: buildJsonKeys(enabledFields),\n rows: rows.map((row) => enabledFields.map((field) => toExportCellValue(field.getValue(row)))),\n };\n}\n\nfunction buildJsonKeys<TRow>(\n fields: readonly DataGridExportField<TRow>[],\n): string[] {\n const labelCounts = new Map<string, number>();\n for (const field of fields) {\n labelCounts.set(field.label, (labelCounts.get(field.label) ?? 0) + 1);\n }\n\n const usedKeys = new Map<string, true>();\n const keys: string[] = [];\n for (const field of fields) {\n const baseKey = labelCounts.get(field.label) === 1 ? field.label : `${field.label} (${field.key})`;\n let key = baseKey;\n let suffix = 2;\n while (usedKeys.has(key)) {\n key = `${baseKey} ${suffix}`;\n suffix++;\n }\n usedKeys.set(key, true);\n keys.push(key);\n }\n\n return keys;\n}\n\nfunction toExportCellValue(value: unknown): ExportCellValue {\n if (value == null) {\n return \"\";\n }\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return value;\n }\n if (typeof value === \"bigint\") {\n return value.toString();\n }\n if (value instanceof Date) {\n return value.toISOString();\n }\n if (typeof value === \"object\") {\n return JSON.stringify(value);\n }\n return String(value);\n}\n\nfunction exportToCsv(data: ExportTable, filenamePrefix: string) {\n const csvContent = \"\\uFEFF\" + [\n data.csvHeaders.map(escapeCsvCell).join(\",\"),\n ...data.rows.map((row) => row.map(escapeCsvCell).join(\",\")),\n ].join(\"\\n\");\n downloadFile(csvContent, `${buildExportFilename(filenamePrefix)}.csv`, \"text/csv;charset=utf-8;\");\n}\n\nfunction escapeCsvCell(value: ExportCellValue): string {\n const rawText = String(value ?? \"\");\n const text = typeof value === \"string\" && /^[=+\\-@\\t\\r]/.test(rawText.trimStart()) ? `'${rawText}` : rawText;\n if (text.includes(\",\") || text.includes('\"') || text.includes(\"\\n\") || text.includes(\"\\r\")) {\n return `\"${text.replace(/\"/g, '\"\"')}\"`;\n }\n return text;\n}\n\nfunction exportToJson(data: ExportTable, filenamePrefix: string) {\n const rows = data.rows.map((row) => {\n const jsonRow: Record<string, ExportCellValue> = {};\n for (let i = 0; i < data.jsonKeys.length; i++) {\n jsonRow[data.jsonKeys[i]] = row[i] ?? \"\";\n }\n return jsonRow;\n });\n const jsonString = JSON.stringify(rows, null, 2);\n downloadFile(jsonString, `${buildExportFilename(filenamePrefix)}.json`, \"application/json\");\n}\n\nfunction downloadFile(content: string, filename: string, type: string) {\n const blob = new Blob([content], { type });\n const url = URL.createObjectURL(blob);\n const link = document.createElement(\"a\");\n link.href = url;\n link.download = filename;\n document.body.appendChild(link);\n try {\n link.click();\n } finally {\n link.remove();\n URL.revokeObjectURL(url);\n }\n}\n\nfunction buildExportFilename(prefix: string) {\n return `${prefix}-${new Date().toISOString().split(\"T\")[0]}`;\n}\n\nfunction titleCase(value: string) {\n return value.charAt(0).toUpperCase() + value.slice(1);\n}\n"],"mappings":";;;;;;;;;;;AAqCA,MAAM,qBAAqC;CACzC,OAAO;CACP,SAAS;AACX;AACA,MAAM,4BAA4B;AAElC,SAAgB,qBAA2B,EACzC,MACA,cACA,MACA,SACA,gBACA,iBACkC;CAClC,MAAM,kBAAkB,eAAe,aAAa;CACpD,MAAM,kBAAA,GAAA,MAAA,QAAA,OACE,eAAe,UAAU,wBAAwB,OAAO,GAC9D,CAAC,eAAe,QAAQ,OAAO,CACjC;CACA,MAAM,CAAC,QAAQ,cAAA,GAAA,MAAA,SAAA,CAA4C,KAAK;CAChE,MAAM,CAAC,OAAO,aAAA,GAAA,MAAA,SAAA,CAA0C,eAAe,gBAAgB,KAAK;CAC5F,MAAM,CAAC,QAAQ,cAAA,GAAA,MAAA,SAAA,CAA4D,cAAc;CACzF,MAAM,CAAC,aAAa,mBAAA,GAAA,MAAA,SAAA,CAA2B,KAAK;CACpD,MAAM,CAAC,UAAU,gBAAA,GAAA,MAAA,SAAA,CAAwC,kBAAkB;CAC3E,MAAM,CAAC,cAAc,oBAAA,GAAA,MAAA,SAAA,CAA2C,IAAI;CAEpE,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,IAAI,CAAC,aACH,UAAU,cAAc;CAE5B,GAAG,CAAC,aAAa,cAAc,CAAC;CAShC,MAAM,eAAe,eAAe,gBAAgB;CACpD,MAAM,cAAA,GAAA,MAAA,OAAA,CAAoB,KAAK;CAC/B,CAAA,GAAA,MAAA,UAAA,OAAgB;EACd,IAAI,QAAQ,CAAC,WAAW,SACtB,SAAS,YAAY;EAEvB,WAAW,UAAU;CACvB,GAAG,CAAC,MAAM,YAAY,CAAC;CAEJ,eAAe;CAClC,MAAM,mBAAmB,eAAe,oBAAoB;CAC5D,MAAM,iBAAiB,eAAe,kBAAkB;CACxD,MAAM,QAAQ,eAAe,SAAS;CACtC,MAAM,cAAc,eAAe,gBACjC,kBACI,gDACA;CAEN,MAAM,gBAAgB,eAAe,iBAAiB,cAAc,iBAAiB;CACrF,MAAM,qBAAqB,eAAe,sBAAsB,iCAAiC;CACjG,MAAM,uBAAuB,eAAe,wBAAwB;CACpE,MAAM,gBAAgB,SAAS,UAAU,aAAa,oBAAoB,aAAa;CACvF,MAAM,kBAAkB,eAAe;CAEvC,MAAM,eAAA,GAAA,MAAA,YAAA,OAAgC;EACpC,aAAa,KAAK;EAClB,gBAAgB,IAAI;CACtB,GAAG,CAAC,YAAY,CAAC;CAEjB,MAAM,oBAAA,GAAA,MAAA,YAAA,EAAgC,aAAsB;EAC1D,IAAI,eAAe,CAAC,UAClB;EAEF,IAAI,UACF,aAAa,IAAI;OAEjB,YAAY;CAEhB,GAAG;EAAC;EAAa;EAAa;CAAY,CAAC;CAE3C,MAAM,eAAA,GAAA,MAAA,YAAA,EAA2B,QAAgB;EAC/C,WAAW,SACT,KAAK,KAAK,UACR,MAAM,QAAQ,MAAM;GAAE,GAAG;GAAO,SAAS,CAAC,MAAM;EAAQ,IAAI,KAC9D,CACF;CACF,GAAG,CAAC,CAAC;CAEL,MAAM,mBAAA,GAAA,MAAA,YAAA,OAAoC;EACxC,WAAW,SAAS,KAAK,KAAK,WAAW;GAAE,GAAG;GAAO,SAAS;EAAK,EAAE,CAAC;CACxE,GAAG,CAAC,CAAC;CAEL,MAAM,qBAAA,GAAA,MAAA,YAAA,OAAsC;EAC1C,WAAW,SAAS,KAAK,KAAK,WAAW;GAAE,GAAG;GAAO,SAAS;EAAM,EAAE,CAAC;CACzE,GAAG,CAAC,CAAC;CAEL,MAAM,aAAA,GAAA,MAAA,YAAA,CAAwB,YAAY;EACxC,IAAI,mBAAmB,MACrB,OAAO,MAAM,gBAAgB;GAC3B;GACA,aAAa,YAAY,YAAY;IAAE,OAAO;IAAY;GAAQ,CAAC;EACrE,CAAC;EAGH,YAAY;GAAE,OAAO;GAAY,SAAS,KAAK;EAAO,CAAC;EACvD,OAAO;CACT,GAAG;EAAC;EAAiB;EAAM;CAAK,CAAC;CAEjC,MAAM,eAAe,YAAY;EAC/B,MAAM,gBAAgB,OAAO,QAAQ,UAAU,MAAM,OAAO;EAC5D,IAAI,cAAc,WAAW,GAAG;GAC9B,gBAAgB,sCAAsC;GACtD;EACF;EAEA,gBAAgB,IAAI;EACpB,eAAe,IAAI;EACnB,YAAY;GAAE,OAAO;GAAY,SAAS;EAAE,CAAC;EAC7C,IAAI;GACF,MAAM,aAAa,MAAM,UAAU;GAEnC,IAAI,WAAW,WAAW,GAAG;IAC3B,gBACE,eAAe,0BACZ,gBAAgB,iBAAiB,YACtC;IACA,eAAe,KAAK;IACpB,YAAY,kBAAkB;IAC9B;GACF;GAEA,YAAY;IAAE,OAAO;IAAc,SAAS,WAAW;GAAO,CAAC;GAC/D,MAAM,kBAAkB,iBAAiB,YAAY,aAAa;GAElE,IAAI,WAAW,OACb,YAAY,iBAAiB,cAAc;QAE3C,aAAa,iBAAiB,cAAc;GAG9C,YAAY;IAAE,OAAO;IAAY,SAAS,WAAW;GAAO,CAAC;GAC7D,MAAM,IAAI,SAAe,YAAY,WAAW,SAAS,yBAAyB,CAAC;GACnF,YAAY;EACd,QAAQ;GACN,gBAAgB,yDAAyD;EAC3E,UAAU;GACR,eAAe,KAAK;GACpB,YAAY,kBAAkB;EAChC;CACF;CAEA,OACE,iBAAA,GAAA,kBAAA,IAAA,CAACA,aAAAA,cAAD;EACQ;EACN,cAAc;EACd,OAAO,cAAc,gBAAgB;EACrC,aAAa,cAAc,wBAAwB,qBAAqB,KAAK;EAC7E,MAAK;EACL,SAAQ;EACR,iBAAiB,cAAc,YAAY,KAAA;EAC3C,oBAAoB;YAEnB,cACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,uBAAD;GACY;GACF;GACR,cAAc;EACf,CAAA,IAED,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;GAAK,WAAU;aAAf;IACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAU;eAAf,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;MAAO,WAAU;MAAsB,SAAS,GAAG,eAAe;gBAAiB;KAE5E,CAAA,GACP,iBAAA,GAAA,kBAAA,KAAA,CAAC,UAAD;MACE,IAAI,GAAG,eAAe;MACtB,OAAO;MACP,WAAW,UAAU,UAAU,MAAM,cAAc,UAAU,SAAS,SAAS,KAAK;MACpF,WAAU;gBAJZ,CAME,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;OAAQ,OAAM;iBAAM;MAAoC,CAAA,GACxD,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;OAAQ,OAAM;iBAAO;MAAyC,CAAA,CACxD;OACL;;IAEJ,kBACC,iBAAA,GAAA,kBAAA,KAAA,CAAC,YAAD;KAAU,WAAU;eAApB;MACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,UAAD;OAAQ,WAAU;iBAAsB;MAAoB,CAAA;MAC5D,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;OAAO,WAAU;iBAAjB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;QACE,MAAK;QACL,MAAM,GAAG,eAAe;QACxB,OAAM;QACN,SAAS,UAAU;QACnB,gBAAgB,SAAS,KAAK;OAC/B,CAAA,GACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAO,cAAoB,CAAA,CACtB;;MACP,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;OAAO,WAAU;iBAAjB,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;QACE,MAAK;QACL,MAAM,GAAG,eAAe;QACxB,OAAM;QACN,SAAS,UAAU;QACnB,gBAAgB,SAAS,UAAU;OACpC,CAAA,GACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAO,mBAAyB,CAAA,CAC3B;;KACC;SACR;IAEJ,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAU;eAAf,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;MAAK,WAAU;gBAAf,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;OAAO,WAAU;iBAAsB;MAAuB,CAAA,GAC9D,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;OAAK,WAAU;iBAAf,CACE,iBAAA,GAAA,kBAAA,IAAA,CAACC,aAAAA,cAAD;QAAc,MAAK;QAAS,SAAQ;QAAQ,MAAK;QAAK,SAAS;QAAiB,WAAU;kBAAc;OAE1F,CAAA,GACd,iBAAA,GAAA,kBAAA,IAAA,CAACA,aAAAA,cAAD;QAAc,MAAK;QAAS,SAAQ;QAAQ,MAAK;QAAK,SAAS;QAAmB,WAAU;kBAAc;OAE5F,CAAA,CACX;QACF;SACL,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAAK,WAAU;gBACZ,OAAO,KAAK,UACX,iBAAA,GAAA,kBAAA,KAAA,CAAC,SAAD;OAAuB,WAAU;iBAAjC,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,SAAD;QACE,MAAK;QACL,SAAS,MAAM;QACf,gBAAgB,YAAY,MAAM,GAAG;OACtC,CAAA,GACD,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAO,MAAM,MAAY,CAAA,CACpB;SAPK,MAAM,GAOX,CACR;KACE,CAAA,CACF;;IAEJ,gBAAgB,OACf,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAU;eAAf,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;MAAK,WAAU;gBAAe,eAAe,oBAAoB;KAA0B,CAAA,GAC3F,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD,EAAA,UAAM,aAAkB,CAAA,CACrB;SACH;IAEJ,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAU;eAAf,CACE,iBAAA,GAAA,kBAAA,IAAA,CAACA,aAAAA,cAAD;MAAc,SAAQ;MAAU,SAAS;gBAAa;KAExC,CAAA,GACd,iBAAA,GAAA,kBAAA,KAAA,CAACA,aAAAA,cAAD;MAAc,SAAS;gBAAvB;OACE,iBAAA,GAAA,kBAAA,IAAA,CAACC,sBAAAA,oBAAD,EAAoB,WAAU,eAAgB,CAAA;OAAC;OACvC,UAAU,gBAAgB;MACtB;OACX;;GACF;;CAEK,CAAA;AAElB;AAEA,SAAS,sBAAsB,OAI5B;CACD,MAAM,EAAE,UAAU,QAAQ,iBAAiB;CAC3C,MAAM,YAAY,OAAO,YAAY;CACrC,MAAM,aAAa,SAAS,UAAU;CACtC,MAAM,QAAQ,aAAa,oBAAoB,aAAa;CAC5D,MAAM,cAAc,aAChB,QAAQ,UAAU,0DAClB,QAAQ,UAAU,mCAAmC,aAAa;CACtE,MAAM,cAAc,SAAS,UAAU,aACnC,mBACA,SAAS,UAAU,eACjB,aAAa,cACb,YAAY;CAClB,MAAM,aAAa,GAAG,SAAS,QAAQ,eAAe,EAAE,GAAG,aAAa,aAAa;CAErF,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;EAAK,WAAU;YAAf;GACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAU;cAAf,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;KAAI,WAAU;eAAwC;IAAU,CAAA,GAChE,iBAAA,GAAA,kBAAA,IAAA,CAAC,KAAD;KAAG,WAAU;eAAiC;IAAe,CAAA,CAC1D;;GAEL,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;IAAK,WAAU;cAAf,CACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,OAAD;KAAK,WAAU;eAAf,CACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAU;gBAA+B;KAAkB,CAAA,GACjE,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MAAM,WAAU;gBACb;KACG,CAAA,CACH;QACL,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;KAAK,WAAU;eACZ,aACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD,EAAK,WAAU,+CAAgD,CAAA,IAE/D,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD,EAAK,WAAU,oJAAqJ,CAAA;IAEnK,CAAA,CACF;;GAEL,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,WAAU;cAAoJ;GAE9J,CAAA;GAEL,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;IAAK,WAAU;cACb,iBAAA,GAAA,kBAAA,IAAA,CAACD,aAAAA,cAAD;KAAc,SAAQ;KAAU,UAAA;eAAS;IAE3B,CAAA;GACX,CAAA;EACF;;AAET;AAEA,SAAS,wBACP,SACsC;CACtC,MAAM,SAAsC,CAAC;CAE7C,KAAK,MAAM,UAAU,SAAS;EAC5B,MAAM,QAAQ,OAAO,OAAO,WAAW,WAAW,OAAO,OAAO,KAAK,IAAI,OAAO;EAChF,IAAI,MAAM,WAAW,GACnB;EAGF,OAAO,KAAK;GACV,KAAK,OAAO;GACZ;GACA,SAAS;GACT,WAAW,QAAQ,wBAAwB,QAAQ,GAAG;EACxD,CAAC;CACH;CAEA,OAAO;AACT;AAEA,SAAS,wBACP,QACA,KACS;CACT,MAAM,SAAA,GAAA,WAAA,mBAAA,CAA2B,QAAQ,GAAG;CAC5C,IAAI,OAAO,eAAe,MACxB,OAAO,OAAO,YAAY,OAAO,GAAG;CAEtC,IAAI,OAAO,SAAS,UAAU,OAAO,SAAS,YAC5C,QAAA,GAAA,WAAA,eAAA,CAAsB,OAAO,YAAY;EACvC,YAAY,OAAO;EACnB,YAAY,OAAO;CACrB,CAAC,CAAC,CAAC,WAAW;CAEhB,OAAO;AACT;AAEA,SAAS,iBACP,MACA,eACa;CACb,OAAO;EACL,YAAY,cAAc,KAAK,UAAU,MAAM,KAAK;EACpD,UAAU,cAAc,aAAa;EACrC,MAAM,KAAK,KAAK,QAAQ,cAAc,KAAK,UAAU,kBAAkB,MAAM,SAAS,GAAG,CAAC,CAAC,CAAC;CAC9F;AACF;AAEA,SAAS,cACP,QACU;CACV,MAAM,8BAAc,IAAI,IAAoB;CAC5C,KAAK,MAAM,SAAS,QAClB,YAAY,IAAI,MAAM,QAAQ,YAAY,IAAI,MAAM,KAAK,KAAK,KAAK,CAAC;CAGtE,MAAM,2BAAW,IAAI,IAAkB;CACvC,MAAM,OAAiB,CAAC;CACxB,KAAK,MAAM,SAAS,QAAQ;EAC1B,MAAM,UAAU,YAAY,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,QAAQ,GAAG,MAAM,MAAM,IAAI,MAAM,IAAI;EAChG,IAAI,MAAM;EACV,IAAI,SAAS;EACb,OAAO,SAAS,IAAI,GAAG,GAAG;GACxB,MAAM,GAAG,QAAQ,GAAG;GACpB;EACF;EACA,SAAS,IAAI,KAAK,IAAI;EACtB,KAAK,KAAK,GAAG;CACf;CAEA,OAAO;AACT;AAEA,SAAS,kBAAkB,OAAiC;CAC1D,IAAI,SAAS,MACX,OAAO;CAET,IAAI,OAAO,UAAU,YAAY,OAAO,UAAU,YAAY,OAAO,UAAU,WAC7E,OAAO;CAET,IAAI,OAAO,UAAU,UACnB,OAAO,MAAM,SAAS;CAExB,IAAI,iBAAiB,MACnB,OAAO,MAAM,YAAY;CAE3B,IAAI,OAAO,UAAU,UACnB,OAAO,KAAK,UAAU,KAAK;CAE7B,OAAO,OAAO,KAAK;AACrB;AAEA,SAAS,YAAY,MAAmB,gBAAwB;CAK9D,aAJmB,MAAW,CAC5B,KAAK,WAAW,IAAI,aAAa,CAAC,CAAC,KAAK,GAAG,GAC3C,GAAG,KAAK,KAAK,KAAK,QAAQ,IAAI,IAAI,aAAa,CAAC,CAAC,KAAK,GAAG,CAAC,CAC5D,CAAC,CAAC,KAAK,IAAI,GACc,GAAG,oBAAoB,cAAc,EAAE,OAAO,yBAAyB;AAClG;AAEA,SAAS,cAAc,OAAgC;CACrD,MAAM,UAAU,OAAO,SAAS,EAAE;CAClC,MAAM,OAAO,OAAO,UAAU,YAAY,eAAe,KAAK,QAAQ,UAAU,CAAC,IAAI,IAAI,YAAY;CACrG,IAAI,KAAK,SAAS,GAAG,KAAK,KAAK,SAAS,IAAG,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,IAAI,GACvF,OAAO,IAAI,KAAK,QAAQ,MAAM,MAAI,EAAE;CAEtC,OAAO;AACT;AAEA,SAAS,aAAa,MAAmB,gBAAwB;CAC/D,MAAM,OAAO,KAAK,KAAK,KAAK,QAAQ;EAClC,MAAM,UAA2C,CAAC;EAClD,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,SAAS,QAAQ,KACxC,QAAQ,KAAK,SAAS,MAAM,IAAI,MAAM;EAExC,OAAO;CACT,CAAC;CAED,aADmB,KAAK,UAAU,MAAM,MAAM,CACxB,GAAG,GAAG,oBAAoB,cAAc,EAAE,QAAQ,kBAAkB;AAC5F;AAEA,SAAS,aAAa,SAAiB,UAAkB,MAAc;CACrE,MAAM,OAAO,IAAI,KAAK,CAAC,OAAO,GAAG,EAAE,KAAK,CAAC;CACzC,MAAM,MAAM,IAAI,gBAAgB,IAAI;CACpC,MAAM,OAAO,SAAS,cAAc,GAAG;CACvC,KAAK,OAAO;CACZ,KAAK,WAAW;CAChB,SAAS,KAAK,YAAY,IAAI;CAC9B,IAAI;EACF,KAAK,MAAM;CACb,UAAU;EACR,KAAK,OAAO;EACZ,IAAI,gBAAgB,GAAG;CACzB;AACF;AAEA,SAAS,oBAAoB,QAAgB;CAC3C,OAAO,GAAG,OAAO,oBAAG,IAAI,KAAK,EAAA,CAAE,YAAY,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;AAC1D;AAEA,SAAS,UAAU,OAAe;CAChC,OAAO,MAAM,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,MAAM,MAAM,CAAC;AACtD"}
|
|
@@ -1,13 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
//#region src/components/data-grid/data-grid-sizing.d.ts
|
|
4
|
-
declare const DEFAULT_MAX_COL_WIDTH = 800;
|
|
5
|
-
declare const DEFAULT_COL_WIDTH = 150;
|
|
6
|
-
/** Effective minimum column width. When `col.minWidth` is unset, derive
|
|
7
|
-
* one from the header label so it never gets clipped during resize. */
|
|
8
|
-
declare function getEffectiveMinWidth<TRow>(col: DataGridColumnDef<TRow>): number;
|
|
9
|
-
declare function getEffectiveMaxWidth<TRow>(col: DataGridColumnDef<TRow>): number;
|
|
10
|
-
declare function clampColumnWidth<TRow>(col: DataGridColumnDef<TRow>, width: number): number;
|
|
11
|
-
//#endregion
|
|
12
|
-
export { DEFAULT_COL_WIDTH, DEFAULT_MAX_COL_WIDTH, clampColumnWidth, getEffectiveMaxWidth, getEffectiveMinWidth };
|
|
13
|
-
//# sourceMappingURL=data-grid-sizing.d.ts.map
|
|
1
|
+
import { a as getEffectiveMinWidth, i as getEffectiveMaxWidth, n as DEFAULT_MAX_COL_WIDTH, r as clampColumnWidth, t as DEFAULT_COL_WIDTH } from "../../data-grid-sizing-S1ixcZKo.js";
|
|
2
|
+
export { DEFAULT_COL_WIDTH, DEFAULT_MAX_COL_WIDTH, clampColumnWidth, getEffectiveMaxWidth, getEffectiveMinWidth };
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value:
|
|
2
|
-
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
2
|
//#region src/components/data-grid/data-grid-sizing.ts
|
|
4
3
|
const MIN_COL_WIDTH = 20;
|
|
5
4
|
const MIN_CUSTOM_HEADER_WIDTH = 50;
|
|
@@ -29,16 +28,16 @@ function getEffectiveMinWidth(col) {
|
|
|
29
28
|
return Math.max(MIN_COL_WIDTH, measureHeaderLabelWidth(label) + HEADER_CHROME_PX);
|
|
30
29
|
}
|
|
31
30
|
function getEffectiveMaxWidth(col) {
|
|
32
|
-
return col.maxWidth ??
|
|
31
|
+
return col.maxWidth ?? 800;
|
|
33
32
|
}
|
|
34
33
|
function clampColumnWidth(col, width) {
|
|
35
34
|
return Math.max(getEffectiveMinWidth(col), Math.min(getEffectiveMaxWidth(col), width));
|
|
36
35
|
}
|
|
37
|
-
|
|
38
36
|
//#endregion
|
|
39
37
|
exports.DEFAULT_COL_WIDTH = DEFAULT_COL_WIDTH;
|
|
40
38
|
exports.DEFAULT_MAX_COL_WIDTH = DEFAULT_MAX_COL_WIDTH;
|
|
41
39
|
exports.clampColumnWidth = clampColumnWidth;
|
|
42
40
|
exports.getEffectiveMaxWidth = getEffectiveMaxWidth;
|
|
43
41
|
exports.getEffectiveMinWidth = getEffectiveMinWidth;
|
|
42
|
+
|
|
44
43
|
//# sourceMappingURL=data-grid-sizing.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-grid-sizing.js","names":[],"sources":["../../../src/components/data-grid/data-grid-sizing.ts"],"sourcesContent":["import type { DataGridColumnDef } from \"./types\";\n\nconst MIN_COL_WIDTH = 20;\nconst MIN_CUSTOM_HEADER_WIDTH = 50;\nexport const DEFAULT_MAX_COL_WIDTH = 800;\nexport const DEFAULT_COL_WIDTH = 150;\n\n// px-3 both sides + gap-1.5 + sort icon (h-3 w-3) + 2px rounding buffer\nconst HEADER_CHROME_PX = 12 + 12 + 6 + 12 + 2;\n\nlet measureContext: CanvasRenderingContext2D | null = null;\nconst headerWidthCache = new Map<string, number>();\n\nfunction measureHeaderLabelWidth(label: string): number {\n const cached = headerWidthCache.get(label);\n if (cached != null) return cached;\n if (typeof document === \"undefined\") return 0;\n if (measureContext == null) {\n measureContext = document.createElement(\"canvas\").getContext(\"2d\");\n }\n if (measureContext == null) return 0;\n\n // Match header cell: text-xs (12px) font-semibold uppercase tracking-wider (0.05em)\n measureContext.font = \"600 12px system-ui, -apple-system, sans-serif\";\n const text = label.toUpperCase();\n const letterSpacingPx = 0.05 * 12;\n const width = Math.ceil(\n measureContext.measureText(text).width + letterSpacingPx * text.length,\n );\n headerWidthCache.set(label, width);\n return width;\n}\n\n/** Effective minimum column width. When `col.minWidth` is unset, derive\n * one from the header label so it never gets clipped during resize. */\nexport function getEffectiveMinWidth<TRow>(col: DataGridColumnDef<TRow>): number {\n if (col.minWidth != null) return col.minWidth;\n const label = typeof col.header === \"string\" ? col.header : null;\n if (label == null) {\n return typeof col.header === \"function\" ? MIN_CUSTOM_HEADER_WIDTH : MIN_COL_WIDTH;\n }\n return Math.max(MIN_COL_WIDTH, measureHeaderLabelWidth(label) + HEADER_CHROME_PX);\n}\n\nexport function getEffectiveMaxWidth<TRow>(col: DataGridColumnDef<TRow>): number {\n return col.maxWidth ?? DEFAULT_MAX_COL_WIDTH;\n}\n\nexport function clampColumnWidth<TRow>(col: DataGridColumnDef<TRow>, width: number): number {\n return Math.max(getEffectiveMinWidth(col), Math.min(getEffectiveMaxWidth(col), width));\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"data-grid-sizing.js","names":[],"sources":["../../../src/components/data-grid/data-grid-sizing.ts"],"sourcesContent":["import type { DataGridColumnDef } from \"./types\";\n\nconst MIN_COL_WIDTH = 20;\nconst MIN_CUSTOM_HEADER_WIDTH = 50;\nexport const DEFAULT_MAX_COL_WIDTH = 800;\nexport const DEFAULT_COL_WIDTH = 150;\n\n// px-3 both sides + gap-1.5 + sort icon (h-3 w-3) + 2px rounding buffer\nconst HEADER_CHROME_PX = 12 + 12 + 6 + 12 + 2;\n\nlet measureContext: CanvasRenderingContext2D | null = null;\nconst headerWidthCache = new Map<string, number>();\n\nfunction measureHeaderLabelWidth(label: string): number {\n const cached = headerWidthCache.get(label);\n if (cached != null) return cached;\n if (typeof document === \"undefined\") return 0;\n if (measureContext == null) {\n measureContext = document.createElement(\"canvas\").getContext(\"2d\");\n }\n if (measureContext == null) return 0;\n\n // Match header cell: text-xs (12px) font-semibold uppercase tracking-wider (0.05em)\n measureContext.font = \"600 12px system-ui, -apple-system, sans-serif\";\n const text = label.toUpperCase();\n const letterSpacingPx = 0.05 * 12;\n const width = Math.ceil(\n measureContext.measureText(text).width + letterSpacingPx * text.length,\n );\n headerWidthCache.set(label, width);\n return width;\n}\n\n/** Effective minimum column width. When `col.minWidth` is unset, derive\n * one from the header label so it never gets clipped during resize. */\nexport function getEffectiveMinWidth<TRow>(col: DataGridColumnDef<TRow>): number {\n if (col.minWidth != null) return col.minWidth;\n const label = typeof col.header === \"string\" ? col.header : null;\n if (label == null) {\n return typeof col.header === \"function\" ? MIN_CUSTOM_HEADER_WIDTH : MIN_COL_WIDTH;\n }\n return Math.max(MIN_COL_WIDTH, measureHeaderLabelWidth(label) + HEADER_CHROME_PX);\n}\n\nexport function getEffectiveMaxWidth<TRow>(col: DataGridColumnDef<TRow>): number {\n return col.maxWidth ?? DEFAULT_MAX_COL_WIDTH;\n}\n\nexport function clampColumnWidth<TRow>(col: DataGridColumnDef<TRow>, width: number): number {\n return Math.max(getEffectiveMinWidth(col), Math.min(getEffectiveMaxWidth(col), width));\n}\n"],"mappings":";;AAEA,MAAM,gBAAgB;AACtB,MAAM,0BAA0B;AAChC,MAAa,wBAAwB;AACrC,MAAa,oBAAoB;AAGjC,MAAM,mBAAmB;AAEzB,IAAI,iBAAkD;AACtD,MAAM,mCAAmB,IAAI,IAAoB;AAEjD,SAAS,wBAAwB,OAAuB;CACtD,MAAM,SAAS,iBAAiB,IAAI,KAAK;CACzC,IAAI,UAAU,MAAM,OAAO;CAC3B,IAAI,OAAO,aAAa,aAAa,OAAO;CAC5C,IAAI,kBAAkB,MACpB,iBAAiB,SAAS,cAAc,QAAQ,CAAC,CAAC,WAAW,IAAI;CAEnE,IAAI,kBAAkB,MAAM,OAAO;CAGnC,eAAe,OAAO;CACtB,MAAM,OAAO,MAAM,YAAY;CAE/B,MAAM,QAAQ,KAAK,KACjB,eAAe,YAAY,IAAI,CAAC,CAAC,QAFX,MAAO,KAE8B,KAAK,MAClE;CACA,iBAAiB,IAAI,OAAO,KAAK;CACjC,OAAO;AACT;;;AAIA,SAAgB,qBAA2B,KAAsC;CAC/E,IAAI,IAAI,YAAY,MAAM,OAAO,IAAI;CACrC,MAAM,QAAQ,OAAO,IAAI,WAAW,WAAW,IAAI,SAAS;CAC5D,IAAI,SAAS,MACX,OAAO,OAAO,IAAI,WAAW,aAAa,0BAA0B;CAEtE,OAAO,KAAK,IAAI,eAAe,wBAAwB,KAAK,IAAI,gBAAgB;AAClF;AAEA,SAAgB,qBAA2B,KAAsC;CAC/E,OAAO,IAAI,YAAA;AACb;AAEA,SAAgB,iBAAuB,KAA8B,OAAuB;CAC1F,OAAO,KAAK,IAAI,qBAAqB,GAAG,GAAG,KAAK,IAAI,qBAAqB,GAAG,GAAG,KAAK,CAAC;AACvF"}
|
|
@@ -1,31 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import React from "react";
|
|
4
|
-
|
|
5
|
-
//#region src/components/data-grid/data-grid-toolbar.d.ts
|
|
6
|
-
declare function DataGridToolbar<TRow>({
|
|
7
|
-
ctx,
|
|
8
|
-
extra,
|
|
9
|
-
extraLeading,
|
|
10
|
-
hideQuickSearch
|
|
11
|
-
}: {
|
|
12
|
-
ctx: DataGridToolbarContext<TRow>;
|
|
13
|
-
/** Extra content rendered inside the toolbar row, to the left of the
|
|
14
|
-
* built-in columns / export actions. Use this to add table-specific
|
|
15
|
-
* affordances (refresh, custom toggles, row counts) without giving up
|
|
16
|
-
* the default actions. */
|
|
17
|
-
extra?: React.ReactNode;
|
|
18
|
-
/** Extra content rendered at the START of the toolbar row — occupies
|
|
19
|
-
* the same position as the built-in quick search (after it, if the
|
|
20
|
-
* quick search is visible). Use this together with `hideQuickSearch`
|
|
21
|
-
* to fully replace the quick search with a custom input, e.g. an
|
|
22
|
-
* AI-powered search bar. */
|
|
23
|
-
extraLeading?: React.ReactNode;
|
|
24
|
-
/** Whether to hide the built-in quick-search input. When `true`,
|
|
25
|
-
* callers are expected to provide their own search UI via
|
|
26
|
-
* `extraLeading`. */
|
|
27
|
-
hideQuickSearch?: boolean;
|
|
28
|
-
}): react_jsx_runtime0.JSX.Element;
|
|
29
|
-
//#endregion
|
|
30
|
-
export { DataGridToolbar };
|
|
31
|
-
//# sourceMappingURL=data-grid-toolbar.d.ts.map
|
|
1
|
+
import { t as DataGridToolbar } from "../../data-grid-toolbar-BGSNGDpT.js";
|
|
2
|
+
export { DataGridToolbar };
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const require_chunk = require('../../chunk-BE-pF4vm.js');
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const require_rolldown_runtime = require("../../rolldown-runtime-D6vf50IK.js");
|
|
5
4
|
let _phosphor_icons_react = require("@phosphor-icons/react");
|
|
6
5
|
let _hexclave_ui = require("@hexclave/ui");
|
|
7
6
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
8
7
|
let react = require("react");
|
|
9
|
-
react =
|
|
10
|
-
|
|
8
|
+
react = require_rolldown_runtime.__toESM(react);
|
|
11
9
|
//#region src/components/data-grid/data-grid-toolbar.tsx
|
|
12
10
|
function usePopover() {
|
|
13
11
|
const [open, setOpen] = (0, react.useState)(false);
|
|
@@ -37,7 +35,7 @@ function usePopover() {
|
|
|
37
35
|
function PopoverPanel({ children, className, popoverRef }) {
|
|
38
36
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
39
37
|
ref: popoverRef,
|
|
40
|
-
className: (0, _hexclave_ui.cn)("absolute top-full left-0 mt-1 z-50", "bg-
|
|
38
|
+
className: (0, _hexclave_ui.cn)("absolute top-full left-0 mt-1 z-50", "bg-white text-popover-foreground rounded-xl shadow-lg dark:bg-popover", "ring-1 ring-black/[0.08] dark:ring-white/[0.1]", "backdrop-blur-xl", className),
|
|
41
39
|
children
|
|
42
40
|
});
|
|
43
41
|
}
|
|
@@ -223,7 +221,7 @@ function DataGridToolbar({ ctx, extra, extraLeading, hideQuickSearch }) {
|
|
|
223
221
|
})]
|
|
224
222
|
});
|
|
225
223
|
}
|
|
226
|
-
|
|
227
224
|
//#endregion
|
|
228
225
|
exports.DataGridToolbar = DataGridToolbar;
|
|
226
|
+
|
|
229
227
|
//# sourceMappingURL=data-grid-toolbar.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-grid-toolbar.js","names":["MagnifyingGlass","X","Eye","EyeSlash","Check","DownloadSimple"],"sources":["../../../src/components/data-grid/data-grid-toolbar.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"@hexclave/ui\";\nimport {\n Check,\n DownloadSimple,\n Eye,\n EyeSlash,\n MagnifyingGlass,\n X,\n} from \"@phosphor-icons/react\";\nimport React, { useCallback, useMemo, useRef, useState } from \"react\";\nimport type {\n DataGridColumnDef,\n DataGridDateDisplay,\n DataGridStrings,\n DataGridToolbarContext,\n} from \"./types\";\n\n// ─── Popover primitive ───────────────────────────────────────────────\n\nfunction usePopover() {\n const [open, setOpen] = useState(false);\n const ref = useRef<HTMLDivElement>(null);\n\n React.useEffect(() => {\n if (!open) return;\n const handler = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) {\n setOpen(false);\n }\n };\n document.addEventListener(\"mousedown\", handler);\n return () => document.removeEventListener(\"mousedown\", handler);\n }, [open]);\n\n React.useEffect(() => {\n if (!open) return;\n const handler = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") setOpen(false);\n };\n document.addEventListener(\"keydown\", handler);\n return () => document.removeEventListener(\"keydown\", handler);\n }, [open]);\n\n return { open, setOpen, ref };\n}\n\nfunction PopoverPanel({\n children,\n className,\n popoverRef,\n}: {\n children: React.ReactNode;\n className?: string;\n popoverRef: React.Ref<HTMLDivElement>;\n}) {\n return (\n <div\n ref={popoverRef}\n className={cn(\n \"absolute top-full left-0 mt-1 z-50\",\n \"bg-popover text-popover-foreground rounded-xl shadow-lg\",\n \"ring-1 ring-black/[0.08] dark:ring-white/[0.1]\",\n \"backdrop-blur-xl\",\n className,\n )}\n >\n {children}\n </div>\n );\n}\n\n// ─── Quick search ────────────────────────────────────────────────────\n\nfunction QuickSearch({\n value,\n onChange,\n placeholder,\n}: {\n value: string;\n onChange: (value: string) => void;\n placeholder: string;\n}) {\n return (\n <div className=\"relative flex min-w-0 flex-1 items-center sm:flex-initial\">\n <MagnifyingGlass className=\"absolute left-2.5 h-3.5 w-3.5 text-muted-foreground/60 pointer-events-none\" />\n <input\n type=\"text\"\n className={cn(\n \"h-8 w-full sm:w-52 pl-8 pr-7 rounded-xl text-xs\",\n \"border border-black/[0.08] dark:border-white/[0.06]\",\n \"bg-white dark:bg-background shadow-sm ring-1 ring-black/[0.08] dark:ring-white/[0.06]\",\n \"placeholder:text-muted-foreground/50\",\n \"focus:outline-none focus:ring-1 focus:ring-foreground/[0.1]\",\n \"transition-all duration-150 hover:transition-none hover:ring-black/[0.12] dark:hover:ring-white/[0.1]\",\n )}\n placeholder={placeholder}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n />\n {value && (\n <button\n className=\"absolute right-2 text-muted-foreground/40 hover:text-muted-foreground\"\n onClick={() => onChange(\"\")}\n aria-label=\"Clear search\"\n >\n <X className=\"h-3 w-3\" />\n </button>\n )}\n </div>\n );\n}\n\n// ─── Toolbar button ──────────────────────────────────────────────────\n\nfunction ToolbarButton({\n children,\n onClick,\n active,\n title,\n className: extraClassName,\n}: {\n children: React.ReactNode;\n onClick?: () => void;\n active?: boolean;\n title?: string;\n className?: string;\n}) {\n return (\n <button\n className={cn(\n \"relative flex items-center justify-center rounded-lg text-xs font-medium\",\n \"h-7 w-7\",\n \"transition-colors duration-75\",\n active\n ? \"bg-foreground/[0.06] text-foreground\"\n : \"text-muted-foreground hover:text-foreground hover:bg-foreground/[0.04]\",\n extraClassName,\n )}\n onClick={onClick}\n title={title}\n >\n {children}\n </button>\n );\n}\n\n// ─── Column manager ──────────────────────────────────────────────────\n\nfunction ColumnManager<TRow>({\n columns,\n visibility,\n onChange,\n strings,\n dateDisplay,\n onDateDisplayChange,\n hasDateColumns,\n}: {\n columns: readonly DataGridColumnDef<TRow>[];\n visibility: Record<string, boolean>;\n onChange: (visibility: Record<string, boolean>) => void;\n strings: DataGridStrings;\n dateDisplay: DataGridDateDisplay;\n onDateDisplayChange: (mode: DataGridDateDisplay) => void;\n hasDateColumns: boolean;\n}) {\n const hideableColumns = useMemo(\n () => columns.filter((c) => c.hideable !== false),\n [columns],\n );\n\n const toggleColumn = (id: string) => {\n const current = visibility[id] !== false;\n onChange({ ...visibility, [id]: !current });\n };\n\n const showAll = () => {\n const next = { ...visibility };\n for (const col of hideableColumns) next[col.id] = true;\n onChange(next);\n };\n\n const hideAll = () => {\n const next = { ...visibility };\n for (const col of hideableColumns) next[col.id] = false;\n onChange(next);\n };\n\n return (\n <div className=\"p-2 min-w-[240px] max-w-[300px]\">\n <div className=\"max-h-[280px] overflow-y-auto space-y-0.5\">\n {hideableColumns.map((col) => {\n const visible = visibility[col.id] !== false;\n return (\n <button\n key={col.id}\n className={cn(\n \"flex items-center gap-2 w-full px-2.5 py-1.5 rounded-lg text-xs\",\n \"hover:bg-foreground/[0.06] transition-colors duration-75\",\n visible ? \"text-foreground\" : \"text-muted-foreground/50\",\n )}\n onClick={() => toggleColumn(col.id)}\n >\n {visible ? (\n <Eye className=\"h-3.5 w-3.5 flex-shrink-0 text-blue-500\" />\n ) : (\n <EyeSlash className=\"h-3.5 w-3.5 flex-shrink-0\" />\n )}\n <span className=\"truncate text-left\">\n {typeof col.header === \"string\" ? col.header : col.id}\n </span>\n {visible && <Check className=\"h-3 w-3 ml-auto flex-shrink-0 text-blue-500\" />}\n </button>\n );\n })}\n </div>\n <div className=\"flex items-center gap-2 mt-2 pt-2 border-t border-foreground/[0.06]\">\n <button className=\"text-[10px] text-muted-foreground hover:text-foreground font-medium uppercase tracking-wider transition-colors duration-75\" onClick={showAll}>\n {strings.showAll}\n </button>\n <span className=\"text-muted-foreground/20\">|</span>\n <button className=\"text-[10px] text-muted-foreground hover:text-foreground font-medium uppercase tracking-wider transition-colors duration-75\" onClick={hideAll}>\n {strings.hideAll}\n </button>\n </div>\n\n {/* Date format toggle — only rendered when at least one column\n uses `type: \"date\"` or `\"dateTime\"`. Toggling writes to\n `state.dateDisplay` and the grid re-renders every date cell. */}\n {hasDateColumns && (\n <div className=\"mt-2 pt-2 border-t border-foreground/[0.06]\">\n <div className=\"flex items-center justify-between gap-2 px-1\">\n <span className=\"text-[10px] font-medium uppercase tracking-wider text-muted-foreground\">\n {strings.dateFormat}\n </span>\n <div className=\"inline-flex items-center gap-0.5 rounded-lg bg-zinc-100/90 p-0.5 ring-1 ring-black/[0.06] dark:bg-foreground/[0.04] dark:ring-white/[0.06]\">\n <button\n className={cn(\n \"px-2 py-0.5 rounded-md text-[11px] font-medium transition-colors duration-150 hover:transition-none\",\n dateDisplay === \"relative\"\n ? \"bg-white text-foreground shadow-sm ring-1 ring-black/[0.12] dark:bg-background dark:ring-white/[0.06]\"\n : \"text-muted-foreground hover:text-foreground hover:bg-white/50 dark:hover:bg-white/[0.06]\",\n )}\n onClick={() => onDateDisplayChange(\"relative\")}\n >\n {strings.dateFormatRelative}\n </button>\n <button\n className={cn(\n \"px-2 py-0.5 rounded-md text-[11px] font-medium transition-colors duration-150 hover:transition-none\",\n dateDisplay === \"absolute\"\n ? \"bg-white text-foreground shadow-sm ring-1 ring-black/[0.12] dark:bg-background dark:ring-white/[0.06]\"\n : \"text-muted-foreground hover:text-foreground hover:bg-white/50 dark:hover:bg-white/[0.06]\",\n )}\n onClick={() => onDateDisplayChange(\"absolute\")}\n >\n {strings.dateFormatAbsolute}\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n\n// ─── Main toolbar ────────────────────────────────────────────────────\n\nexport function DataGridToolbar<TRow>({\n ctx,\n extra,\n extraLeading,\n hideQuickSearch,\n}: {\n ctx: DataGridToolbarContext<TRow>;\n /** Extra content rendered inside the toolbar row, to the left of the\n * built-in columns / export actions. Use this to add table-specific\n * affordances (refresh, custom toggles, row counts) without giving up\n * the default actions. */\n extra?: React.ReactNode;\n /** Extra content rendered at the START of the toolbar row — occupies\n * the same position as the built-in quick search (after it, if the\n * quick search is visible). Use this together with `hideQuickSearch`\n * to fully replace the quick search with a custom input, e.g. an\n * AI-powered search bar. */\n extraLeading?: React.ReactNode;\n /** Whether to hide the built-in quick-search input. When `true`,\n * callers are expected to provide their own search UI via\n * `extraLeading`. */\n hideQuickSearch?: boolean;\n}) {\n const { state, onChange, columns, strings, exportCsv } = ctx;\n\n const columnPopover = usePopover();\n\n const updateVisibility = useCallback(\n (visibility: Record<string, boolean>) => {\n onChange((s) => ({ ...s, columnVisibility: visibility }));\n },\n [onChange],\n );\n\n const updateDateDisplay = useCallback(\n (mode: DataGridDateDisplay) => {\n onChange((s) => ({ ...s, dateDisplay: mode }));\n },\n [onChange],\n );\n\n const updateQuickSearch = useCallback(\n (value: string) => {\n onChange((s) => ({\n ...s,\n quickSearch: value,\n // Reset to first page whenever the search text changes,\n // otherwise you can end up on a page index that no longer\n // exists in the filtered / refetched result set.\n pagination: { ...s.pagination, pageIndex: 0 },\n }));\n },\n [onChange],\n );\n\n const hasDateColumns = useMemo(\n () => columns.some((c) => c.type === \"date\" || c.type === \"dateTime\"),\n [columns],\n );\n\n return (\n <div className=\"flex w-full min-w-0 flex-col gap-2 px-2.5 py-2.5 border-b border-foreground/[0.06] sm:flex-row sm:items-center sm:gap-2\">\n <div className=\"flex min-w-0 flex-1 flex-wrap items-center gap-2\">\n {!hideQuickSearch && (\n <QuickSearch\n value={state.quickSearch}\n onChange={updateQuickSearch}\n placeholder={strings.searchPlaceholder}\n />\n )}\n {extraLeading}\n {extra}\n </div>\n <div className=\"flex shrink-0 items-center justify-end gap-2\">\n <div className=\"relative shrink-0\" ref={columnPopover.ref}>\n <ToolbarButton\n onClick={() => columnPopover.setOpen(!columnPopover.open)}\n active={columnPopover.open}\n title={strings.columns}\n >\n <Eye className=\"h-3.5 w-3.5\" />\n </ToolbarButton>\n {columnPopover.open && (\n <PopoverPanel popoverRef={columnPopover.ref} className=\"right-0 left-auto\">\n <ColumnManager\n columns={columns}\n visibility={state.columnVisibility}\n onChange={updateVisibility}\n strings={strings}\n dateDisplay={state.dateDisplay}\n onDateDisplayChange={updateDateDisplay}\n hasDateColumns={hasDateColumns}\n />\n </PopoverPanel>\n )}\n </div>\n\n <ToolbarButton onClick={exportCsv} title={strings.export}>\n <DownloadSimple className=\"h-3.5 w-3.5\" />\n </ToolbarButton>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"data-grid-toolbar.js","names":["MagnifyingGlass","X","Eye","EyeSlash","Check","DownloadSimple"],"sources":["../../../src/components/data-grid/data-grid-toolbar.tsx"],"sourcesContent":["\"use client\";\n\nimport { cn } from \"@hexclave/ui\";\nimport {\n Check,\n DownloadSimple,\n Eye,\n EyeSlash,\n MagnifyingGlass,\n X,\n} from \"@phosphor-icons/react\";\nimport React, { useCallback, useMemo, useRef, useState } from \"react\";\nimport type {\n DataGridColumnDef,\n DataGridDateDisplay,\n DataGridStrings,\n DataGridToolbarContext,\n} from \"./types\";\n\n// ─── Popover primitive ───────────────────────────────────────────────\n\nfunction usePopover() {\n const [open, setOpen] = useState(false);\n const ref = useRef<HTMLDivElement>(null);\n\n React.useEffect(() => {\n if (!open) return;\n const handler = (e: MouseEvent) => {\n if (ref.current && !ref.current.contains(e.target as Node)) {\n setOpen(false);\n }\n };\n document.addEventListener(\"mousedown\", handler);\n return () => document.removeEventListener(\"mousedown\", handler);\n }, [open]);\n\n React.useEffect(() => {\n if (!open) return;\n const handler = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") setOpen(false);\n };\n document.addEventListener(\"keydown\", handler);\n return () => document.removeEventListener(\"keydown\", handler);\n }, [open]);\n\n return { open, setOpen, ref };\n}\n\nfunction PopoverPanel({\n children,\n className,\n popoverRef,\n}: {\n children: React.ReactNode;\n className?: string;\n popoverRef: React.Ref<HTMLDivElement>;\n}) {\n return (\n <div\n ref={popoverRef}\n className={cn(\n \"absolute top-full left-0 mt-1 z-50\",\n \"bg-white text-popover-foreground rounded-xl shadow-lg dark:bg-popover\",\n \"ring-1 ring-black/[0.08] dark:ring-white/[0.1]\",\n \"backdrop-blur-xl\",\n className,\n )}\n >\n {children}\n </div>\n );\n}\n\n// ─── Quick search ────────────────────────────────────────────────────\n\nfunction QuickSearch({\n value,\n onChange,\n placeholder,\n}: {\n value: string;\n onChange: (value: string) => void;\n placeholder: string;\n}) {\n return (\n <div className=\"relative flex min-w-0 flex-1 items-center sm:flex-initial\">\n <MagnifyingGlass className=\"absolute left-2.5 h-3.5 w-3.5 text-muted-foreground/60 pointer-events-none\" />\n <input\n type=\"text\"\n className={cn(\n \"h-8 w-full sm:w-52 pl-8 pr-7 rounded-xl text-xs\",\n \"border border-black/[0.08] dark:border-white/[0.06]\",\n \"bg-white dark:bg-background shadow-sm ring-1 ring-black/[0.08] dark:ring-white/[0.06]\",\n \"placeholder:text-muted-foreground/50\",\n \"focus:outline-none focus:ring-1 focus:ring-foreground/[0.1]\",\n \"transition-all duration-150 hover:transition-none hover:ring-black/[0.12] dark:hover:ring-white/[0.1]\",\n )}\n placeholder={placeholder}\n value={value}\n onChange={(e) => onChange(e.target.value)}\n />\n {value && (\n <button\n className=\"absolute right-2 text-muted-foreground/40 hover:text-muted-foreground\"\n onClick={() => onChange(\"\")}\n aria-label=\"Clear search\"\n >\n <X className=\"h-3 w-3\" />\n </button>\n )}\n </div>\n );\n}\n\n// ─── Toolbar button ──────────────────────────────────────────────────\n\nfunction ToolbarButton({\n children,\n onClick,\n active,\n title,\n className: extraClassName,\n}: {\n children: React.ReactNode;\n onClick?: () => void;\n active?: boolean;\n title?: string;\n className?: string;\n}) {\n return (\n <button\n className={cn(\n \"relative flex items-center justify-center rounded-lg text-xs font-medium\",\n \"h-7 w-7\",\n \"transition-colors duration-75\",\n active\n ? \"bg-foreground/[0.06] text-foreground\"\n : \"text-muted-foreground hover:text-foreground hover:bg-foreground/[0.04]\",\n extraClassName,\n )}\n onClick={onClick}\n title={title}\n >\n {children}\n </button>\n );\n}\n\n// ─── Column manager ──────────────────────────────────────────────────\n\nfunction ColumnManager<TRow>({\n columns,\n visibility,\n onChange,\n strings,\n dateDisplay,\n onDateDisplayChange,\n hasDateColumns,\n}: {\n columns: readonly DataGridColumnDef<TRow>[];\n visibility: Record<string, boolean>;\n onChange: (visibility: Record<string, boolean>) => void;\n strings: DataGridStrings;\n dateDisplay: DataGridDateDisplay;\n onDateDisplayChange: (mode: DataGridDateDisplay) => void;\n hasDateColumns: boolean;\n}) {\n const hideableColumns = useMemo(\n () => columns.filter((c) => c.hideable !== false),\n [columns],\n );\n\n const toggleColumn = (id: string) => {\n const current = visibility[id] !== false;\n onChange({ ...visibility, [id]: !current });\n };\n\n const showAll = () => {\n const next = { ...visibility };\n for (const col of hideableColumns) next[col.id] = true;\n onChange(next);\n };\n\n const hideAll = () => {\n const next = { ...visibility };\n for (const col of hideableColumns) next[col.id] = false;\n onChange(next);\n };\n\n return (\n <div className=\"p-2 min-w-[240px] max-w-[300px]\">\n <div className=\"max-h-[280px] overflow-y-auto space-y-0.5\">\n {hideableColumns.map((col) => {\n const visible = visibility[col.id] !== false;\n return (\n <button\n key={col.id}\n className={cn(\n \"flex items-center gap-2 w-full px-2.5 py-1.5 rounded-lg text-xs\",\n \"hover:bg-foreground/[0.06] transition-colors duration-75\",\n visible ? \"text-foreground\" : \"text-muted-foreground/50\",\n )}\n onClick={() => toggleColumn(col.id)}\n >\n {visible ? (\n <Eye className=\"h-3.5 w-3.5 flex-shrink-0 text-blue-500\" />\n ) : (\n <EyeSlash className=\"h-3.5 w-3.5 flex-shrink-0\" />\n )}\n <span className=\"truncate text-left\">\n {typeof col.header === \"string\" ? col.header : col.id}\n </span>\n {visible && <Check className=\"h-3 w-3 ml-auto flex-shrink-0 text-blue-500\" />}\n </button>\n );\n })}\n </div>\n <div className=\"flex items-center gap-2 mt-2 pt-2 border-t border-foreground/[0.06]\">\n <button className=\"text-[10px] text-muted-foreground hover:text-foreground font-medium uppercase tracking-wider transition-colors duration-75\" onClick={showAll}>\n {strings.showAll}\n </button>\n <span className=\"text-muted-foreground/20\">|</span>\n <button className=\"text-[10px] text-muted-foreground hover:text-foreground font-medium uppercase tracking-wider transition-colors duration-75\" onClick={hideAll}>\n {strings.hideAll}\n </button>\n </div>\n\n {/* Date format toggle — only rendered when at least one column\n uses `type: \"date\"` or `\"dateTime\"`. Toggling writes to\n `state.dateDisplay` and the grid re-renders every date cell. */}\n {hasDateColumns && (\n <div className=\"mt-2 pt-2 border-t border-foreground/[0.06]\">\n <div className=\"flex items-center justify-between gap-2 px-1\">\n <span className=\"text-[10px] font-medium uppercase tracking-wider text-muted-foreground\">\n {strings.dateFormat}\n </span>\n <div className=\"inline-flex items-center gap-0.5 rounded-lg bg-zinc-100/90 p-0.5 ring-1 ring-black/[0.06] dark:bg-foreground/[0.04] dark:ring-white/[0.06]\">\n <button\n className={cn(\n \"px-2 py-0.5 rounded-md text-[11px] font-medium transition-colors duration-150 hover:transition-none\",\n dateDisplay === \"relative\"\n ? \"bg-white text-foreground shadow-sm ring-1 ring-black/[0.12] dark:bg-background dark:ring-white/[0.06]\"\n : \"text-muted-foreground hover:text-foreground hover:bg-white/50 dark:hover:bg-white/[0.06]\",\n )}\n onClick={() => onDateDisplayChange(\"relative\")}\n >\n {strings.dateFormatRelative}\n </button>\n <button\n className={cn(\n \"px-2 py-0.5 rounded-md text-[11px] font-medium transition-colors duration-150 hover:transition-none\",\n dateDisplay === \"absolute\"\n ? \"bg-white text-foreground shadow-sm ring-1 ring-black/[0.12] dark:bg-background dark:ring-white/[0.06]\"\n : \"text-muted-foreground hover:text-foreground hover:bg-white/50 dark:hover:bg-white/[0.06]\",\n )}\n onClick={() => onDateDisplayChange(\"absolute\")}\n >\n {strings.dateFormatAbsolute}\n </button>\n </div>\n </div>\n </div>\n )}\n </div>\n );\n}\n\n// ─── Main toolbar ────────────────────────────────────────────────────\n\nexport function DataGridToolbar<TRow>({\n ctx,\n extra,\n extraLeading,\n hideQuickSearch,\n}: {\n ctx: DataGridToolbarContext<TRow>;\n /** Extra content rendered inside the toolbar row, to the left of the\n * built-in columns / export actions. Use this to add table-specific\n * affordances (refresh, custom toggles, row counts) without giving up\n * the default actions. */\n extra?: React.ReactNode;\n /** Extra content rendered at the START of the toolbar row — occupies\n * the same position as the built-in quick search (after it, if the\n * quick search is visible). Use this together with `hideQuickSearch`\n * to fully replace the quick search with a custom input, e.g. an\n * AI-powered search bar. */\n extraLeading?: React.ReactNode;\n /** Whether to hide the built-in quick-search input. When `true`,\n * callers are expected to provide their own search UI via\n * `extraLeading`. */\n hideQuickSearch?: boolean;\n}) {\n const { state, onChange, columns, strings, exportCsv } = ctx;\n\n const columnPopover = usePopover();\n\n const updateVisibility = useCallback(\n (visibility: Record<string, boolean>) => {\n onChange((s) => ({ ...s, columnVisibility: visibility }));\n },\n [onChange],\n );\n\n const updateDateDisplay = useCallback(\n (mode: DataGridDateDisplay) => {\n onChange((s) => ({ ...s, dateDisplay: mode }));\n },\n [onChange],\n );\n\n const updateQuickSearch = useCallback(\n (value: string) => {\n onChange((s) => ({\n ...s,\n quickSearch: value,\n // Reset to first page whenever the search text changes,\n // otherwise you can end up on a page index that no longer\n // exists in the filtered / refetched result set.\n pagination: { ...s.pagination, pageIndex: 0 },\n }));\n },\n [onChange],\n );\n\n const hasDateColumns = useMemo(\n () => columns.some((c) => c.type === \"date\" || c.type === \"dateTime\"),\n [columns],\n );\n\n return (\n <div className=\"flex w-full min-w-0 flex-col gap-2 px-2.5 py-2.5 border-b border-foreground/[0.06] sm:flex-row sm:items-center sm:gap-2\">\n <div className=\"flex min-w-0 flex-1 flex-wrap items-center gap-2\">\n {!hideQuickSearch && (\n <QuickSearch\n value={state.quickSearch}\n onChange={updateQuickSearch}\n placeholder={strings.searchPlaceholder}\n />\n )}\n {extraLeading}\n {extra}\n </div>\n <div className=\"flex shrink-0 items-center justify-end gap-2\">\n <div className=\"relative shrink-0\" ref={columnPopover.ref}>\n <ToolbarButton\n onClick={() => columnPopover.setOpen(!columnPopover.open)}\n active={columnPopover.open}\n title={strings.columns}\n >\n <Eye className=\"h-3.5 w-3.5\" />\n </ToolbarButton>\n {columnPopover.open && (\n <PopoverPanel popoverRef={columnPopover.ref} className=\"right-0 left-auto\">\n <ColumnManager\n columns={columns}\n visibility={state.columnVisibility}\n onChange={updateVisibility}\n strings={strings}\n dateDisplay={state.dateDisplay}\n onDateDisplayChange={updateDateDisplay}\n hasDateColumns={hasDateColumns}\n />\n </PopoverPanel>\n )}\n </div>\n\n <ToolbarButton onClick={exportCsv} title={strings.export}>\n <DownloadSimple className=\"h-3.5 w-3.5\" />\n </ToolbarButton>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,47 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
//#region src/components/data-grid/data-grid.d.ts
|
|
5
|
-
declare function isDataGridInteractiveRowClickTarget(target: EventTarget | null): boolean;
|
|
6
|
-
/**
|
|
7
|
-
* Interactive table built on TanStack Table v8. Sorting, column sizing,
|
|
8
|
-
* visibility, ordering, and pinning are owned by the table instance; we
|
|
9
|
-
* layer virtualization, sticky toolbar/header/footer, infinite scroll,
|
|
10
|
-
* quick search, CSV export, and date-format toggling on top.
|
|
11
|
-
*
|
|
12
|
-
* The grid is display-only — it does not fetch or page data itself. Pair
|
|
13
|
-
* with `useDataSource` for client- or server-side data and pass the
|
|
14
|
-
* already-processed slice through `rows`.
|
|
15
|
-
*
|
|
16
|
-
* ```tsx
|
|
17
|
-
* const columns = useMemo(() => [...], []);
|
|
18
|
-
* const [gridState, setGridState] = useState(() => createDefaultDataGridState(columns));
|
|
19
|
-
* const gridData = useDataSource({
|
|
20
|
-
* data: users, columns, getRowId: (r) => r.id,
|
|
21
|
-
* sorting: gridState.sorting,
|
|
22
|
-
* quickSearch: gridState.quickSearch,
|
|
23
|
-
* pagination: gridState.pagination,
|
|
24
|
-
* paginationMode: "client",
|
|
25
|
-
* });
|
|
26
|
-
*
|
|
27
|
-
* <DataGrid
|
|
28
|
-
* columns={columns}
|
|
29
|
-
* rows={gridData.rows}
|
|
30
|
-
* getRowId={(r) => r.id}
|
|
31
|
-
* totalRowCount={gridData.totalRowCount}
|
|
32
|
-
* isLoading={gridData.isLoading}
|
|
33
|
-
* state={gridState}
|
|
34
|
-
* onChange={setGridState}
|
|
35
|
-
* />
|
|
36
|
-
* ```
|
|
37
|
-
*
|
|
38
|
-
* Iron rules:
|
|
39
|
-
* - `rows` is always `gridData.rows`, never your raw array.
|
|
40
|
-
* - Columns must be stable (define outside the component or wrap in `useMemo`).
|
|
41
|
-
* - Initialize state with `createDefaultDataGridState(columns)`.
|
|
42
|
-
* - `renderCell` must be a pure function — no React hooks inside.
|
|
43
|
-
*/
|
|
44
|
-
declare function DataGrid<TRow>(props: DataGridProps<TRow>): react_jsx_runtime0.JSX.Element;
|
|
45
|
-
//#endregion
|
|
46
|
-
export { DataGrid, isDataGridInteractiveRowClickTarget };
|
|
47
|
-
//# sourceMappingURL=data-grid.d.ts.map
|
|
1
|
+
import { n as isDataGridInteractiveRowClickTarget, t as DataGrid } from "../../data-grid-AJi1TNDa.js";
|
|
2
|
+
export { DataGrid, isDataGridInteractiveRowClickTarget };
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const require_chunk = require('../../chunk-BE-pF4vm.js');
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const require_rolldown_runtime = require("../../rolldown-runtime-D6vf50IK.js");
|
|
5
4
|
let _phosphor_icons_react = require("@phosphor-icons/react");
|
|
6
5
|
let _hexclave_ui = require("@hexclave/ui");
|
|
7
6
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
8
7
|
let react = require("react");
|
|
9
|
-
react =
|
|
8
|
+
react = require_rolldown_runtime.__toESM(react);
|
|
10
9
|
let __state_js = require("./state.js");
|
|
11
10
|
let __strings_js = require("./strings.js");
|
|
12
11
|
let _hexclave_shared_dist_utils_errors = require("@hexclave/shared/dist/utils/errors");
|
|
@@ -16,7 +15,6 @@ let ___skeleton_js = require("../skeleton.js");
|
|
|
16
15
|
let __data_grid_sizing_js = require("./data-grid-sizing.js");
|
|
17
16
|
let __data_grid_export_dialog_js = require("./data-grid-export-dialog.js");
|
|
18
17
|
let __data_grid_toolbar_js = require("./data-grid-toolbar.js");
|
|
19
|
-
|
|
20
18
|
//#region src/components/data-grid/data-grid.tsx
|
|
21
19
|
function getEventTargetElement(target) {
|
|
22
20
|
if (target instanceof Element) return target;
|
|
@@ -75,7 +73,7 @@ function distributeFlexWidths(sizes, visibleColumns, available) {
|
|
|
75
73
|
function selectSingle(current, rowId) {
|
|
76
74
|
const isSelected = current.selectedIds.has(rowId);
|
|
77
75
|
return {
|
|
78
|
-
selectedIds: isSelected ? /* @__PURE__ */ new Set() : new Set([rowId]),
|
|
76
|
+
selectedIds: isSelected ? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set([rowId]),
|
|
79
77
|
anchorId: isSelected ? null : rowId
|
|
80
78
|
};
|
|
81
79
|
}
|
|
@@ -111,7 +109,7 @@ function nextSelection(input) {
|
|
|
111
109
|
}
|
|
112
110
|
if (modifiers.ctrl) return selectToggle(current, rowId);
|
|
113
111
|
return {
|
|
114
|
-
selectedIds: new Set([rowId]),
|
|
112
|
+
selectedIds: /* @__PURE__ */ new Set([rowId]),
|
|
115
113
|
anchorId: rowId
|
|
116
114
|
};
|
|
117
115
|
}
|
|
@@ -784,7 +782,7 @@ function DataGrid(props) {
|
|
|
784
782
|
children: [
|
|
785
783
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
786
784
|
ref: stickyChromeRef,
|
|
787
|
-
className: "sticky z-30 w-full min-w-0 shrink-0 overflow-visible rounded-t-[calc(var(--radius)*2)] bg-white/90 dark:bg-background
|
|
785
|
+
className: "sticky z-30 w-full min-w-0 shrink-0 overflow-visible rounded-t-[calc(var(--radius)*2)] bg-white/90 dark:bg-background backdrop-blur-xl",
|
|
788
786
|
style: { top: stickyTop ?? (maxHeight != null ? 0 : "var(--data-grid-sticky-top, 0px)") },
|
|
789
787
|
children: [toolbar !== false && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
790
788
|
className: "relative bg-transparent",
|
|
@@ -916,7 +914,7 @@ function DataGrid(props) {
|
|
|
916
914
|
})
|
|
917
915
|
}),
|
|
918
916
|
footer !== false && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
919
|
-
className: "sticky bottom-0 z-30 shrink-0 overflow-hidden rounded-b-[calc(var(--radius)*2)] bg-white/90 dark:bg-background
|
|
917
|
+
className: "sticky bottom-0 z-30 shrink-0 overflow-hidden rounded-b-[calc(var(--radius)*2)] bg-white/90 dark:bg-background backdrop-blur-xl",
|
|
920
918
|
children: [footer ? footer(footerCtx) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DefaultFooter, {
|
|
921
919
|
ctx: footerCtx,
|
|
922
920
|
pagination: paginationMode,
|
|
@@ -926,8 +924,8 @@ function DataGrid(props) {
|
|
|
926
924
|
]
|
|
927
925
|
})] });
|
|
928
926
|
}
|
|
929
|
-
|
|
930
927
|
//#endregion
|
|
931
928
|
exports.DataGrid = DataGrid;
|
|
932
929
|
exports.isDataGridInteractiveRowClickTarget = isDataGridInteractiveRowClickTarget;
|
|
930
|
+
|
|
933
931
|
//# sourceMappingURL=data-grid.js.map
|