@eifi1/ui-kit 0.4.0 → 0.5.0
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/LICENSE +32 -0
- package/README.md +498 -57
- package/dist/chart.d.ts +10 -0
- package/dist/chart.js +10 -0
- package/dist/chart.js.map +1 -0
- package/dist/components/account-settings.d.ts +11 -0
- package/dist/components/account-settings.js +19 -12
- package/dist/components/account-settings.js.map +1 -1
- package/dist/components/alert-banner.d.ts +10 -6
- package/dist/components/alert-banner.js +20 -16
- package/dist/components/alert-banner.js.map +1 -1
- package/dist/components/amount-input.d.ts +30 -4
- package/dist/components/amount-input.js +36 -14
- package/dist/components/amount-input.js.map +1 -1
- package/dist/components/calculator.d.ts +24 -7
- package/dist/components/calculator.js +37 -20
- package/dist/components/calculator.js.map +1 -1
- package/dist/components/chart-zoom.d.ts +156 -0
- package/dist/components/chart-zoom.js +262 -0
- package/dist/components/chart-zoom.js.map +1 -0
- package/dist/components/chart.d.ts +28 -3
- package/dist/components/chart.js +71 -32
- package/dist/components/chart.js.map +1 -1
- package/dist/components/checkbox.d.ts +51 -0
- package/dist/components/checkbox.js +123 -0
- package/dist/components/checkbox.js.map +1 -0
- package/dist/components/chip.d.ts +128 -0
- package/dist/components/chip.js +357 -0
- package/dist/components/chip.js.map +1 -0
- package/dist/components/choice-parts.d.ts +24 -0
- package/dist/components/choice-parts.js +18 -0
- package/dist/components/choice-parts.js.map +1 -0
- package/dist/components/combobox-core.d.ts +52 -9
- package/dist/components/combobox-core.js +91 -20
- package/dist/components/combobox-core.js.map +1 -1
- package/dist/components/combobox.d.ts +43 -33
- package/dist/components/combobox.js +409 -340
- package/dist/components/combobox.js.map +1 -1
- package/dist/components/currency-select.d.ts +48 -8
- package/dist/components/currency-select.js +107 -65
- package/dist/components/currency-select.js.map +1 -1
- package/dist/components/data-table-filter-popover.d.ts +15 -3
- package/dist/components/data-table-filter-popover.js +23 -17
- package/dist/components/data-table-filter-popover.js.map +1 -1
- package/dist/components/data-table-filters.d.ts +1 -1
- package/dist/components/data-table-filters.js +3 -2
- package/dist/components/data-table-filters.js.map +1 -1
- package/dist/components/data-table-labels.d.ts +53 -2
- package/dist/components/data-table-labels.js +31 -2
- package/dist/components/data-table-labels.js.map +1 -1
- package/dist/components/data-table-pagination.d.ts +3 -1
- package/dist/components/data-table-pagination.js +16 -10
- package/dist/components/data-table-pagination.js.map +1 -1
- package/dist/components/data-table-sort.js +1 -0
- package/dist/components/data-table-sort.js.map +1 -1
- package/dist/components/data-table.d.ts +1 -1
- package/dist/components/data-table.js +201 -85
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/date-picker.d.ts +25 -9
- package/dist/components/date-picker.js +232 -94
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/dropdown.d.ts +96 -20
- package/dist/components/dropdown.js +77 -33
- package/dist/components/dropdown.js.map +1 -1
- package/dist/components/entity-combobox.d.ts +5 -4
- package/dist/components/entity-combobox.js +107 -76
- package/dist/components/entity-combobox.js.map +1 -1
- package/dist/components/facing-pair.d.ts +36 -0
- package/dist/components/facing-pair.js +40 -0
- package/dist/components/facing-pair.js.map +1 -0
- package/dist/components/field-sync.d.ts +164 -0
- package/dist/components/field-sync.js +264 -0
- package/dist/components/field-sync.js.map +1 -0
- package/dist/components/file-dropzone.d.ts +38 -6
- package/dist/components/file-dropzone.js +34 -9
- package/dist/components/file-dropzone.js.map +1 -1
- package/dist/components/full-bleed-dialog.d.ts +37 -26
- package/dist/components/full-bleed-dialog.js +20 -5
- package/dist/components/full-bleed-dialog.js.map +1 -1
- package/dist/components/grouped-picker.d.ts +21 -10
- package/dist/components/grouped-picker.js +66 -52
- package/dist/components/grouped-picker.js.map +1 -1
- package/dist/components/hover-menu.d.ts +20 -4
- package/dist/components/hover-menu.js +15 -4
- package/dist/components/hover-menu.js.map +1 -1
- package/dist/components/mini-calendar.d.ts +102 -14
- package/dist/components/mini-calendar.js +256 -70
- package/dist/components/mini-calendar.js.map +1 -1
- package/dist/components/modal.d.ts +9 -3
- package/dist/components/modal.js +34 -45
- package/dist/components/modal.js.map +1 -1
- package/dist/components/month-picker.d.ts +79 -0
- package/dist/components/month-picker.js +342 -0
- package/dist/components/month-picker.js.map +1 -0
- package/dist/components/multi-entity-combobox.d.ts +7 -6
- package/dist/components/multi-entity-combobox.js +112 -72
- package/dist/components/multi-entity-combobox.js.map +1 -1
- package/dist/components/multi-select.d.ts +13 -11
- package/dist/components/multi-select.js +161 -84
- package/dist/components/multi-select.js.map +1 -1
- package/dist/components/number-field.d.ts +92 -0
- package/dist/components/number-field.js +111 -0
- package/dist/components/number-field.js.map +1 -0
- package/dist/components/number-input.d.ts +28 -2
- package/dist/components/number-input.js +12 -2
- package/dist/components/number-input.js.map +1 -1
- package/dist/components/numpad-sheet.d.ts +32 -4
- package/dist/components/numpad-sheet.js +30 -13
- package/dist/components/numpad-sheet.js.map +1 -1
- package/dist/components/page-contents.d.ts +90 -0
- package/dist/components/page-contents.js +170 -0
- package/dist/components/page-contents.js.map +1 -0
- package/dist/components/password-strength.d.ts +106 -0
- package/dist/components/password-strength.js +132 -0
- package/dist/components/password-strength.js.map +1 -0
- package/dist/components/picker-sheet.d.ts +23 -15
- package/dist/components/picker-sheet.js +34 -14
- package/dist/components/picker-sheet.js.map +1 -1
- package/dist/components/popover.d.ts +62 -4
- package/dist/components/popover.js +52 -2
- package/dist/components/popover.js.map +1 -1
- package/dist/components/search-field.d.ts +25 -7
- package/dist/components/search-field.js +7 -5
- package/dist/components/search-field.js.map +1 -1
- package/dist/components/series-chart-labels.d.ts +14 -0
- package/dist/components/series-chart-labels.js +11 -0
- package/dist/components/series-chart-labels.js.map +1 -0
- package/dist/components/series-chart.d.ts +207 -0
- package/dist/components/series-chart.js +223 -0
- package/dist/components/series-chart.js.map +1 -0
- package/dist/components/settings-fields.d.ts +14 -4
- package/dist/components/settings-fields.js +19 -8
- package/dist/components/settings-fields.js.map +1 -1
- package/dist/components/signature-pad.d.ts +119 -0
- package/dist/components/signature-pad.js +405 -0
- package/dist/components/signature-pad.js.map +1 -0
- package/dist/components/slider.d.ts +80 -0
- package/dist/components/slider.js +155 -0
- package/dist/components/slider.js.map +1 -0
- package/dist/components/sparkline.d.ts +93 -0
- package/dist/components/sparkline.js +205 -0
- package/dist/components/sparkline.js.map +1 -0
- package/dist/components/stat-tile.d.ts +151 -0
- package/dist/components/stat-tile.js +236 -0
- package/dist/components/stat-tile.js.map +1 -0
- package/dist/components/swipeable-row.d.ts +25 -2
- package/dist/components/swipeable-row.js +31 -0
- package/dist/components/swipeable-row.js.map +1 -1
- package/dist/components/switch.d.ts +60 -0
- package/dist/components/switch.js +81 -0
- package/dist/components/switch.js.map +1 -0
- package/dist/components/time-input.d.ts +58 -0
- package/dist/components/time-input.js +50 -0
- package/dist/components/time-input.js.map +1 -0
- package/dist/components/toggle-group.d.ts +18 -3
- package/dist/components/toggle-group.js +10 -6
- package/dist/components/toggle-group.js.map +1 -1
- package/dist/components/toggle-legend.d.ts +115 -0
- package/dist/components/toggle-legend.js +114 -0
- package/dist/components/toggle-legend.js.map +1 -0
- package/dist/components/tooltip.d.ts +40 -11
- package/dist/components/tooltip.js +77 -20
- package/dist/components/tooltip.js.map +1 -1
- package/dist/components/treemap.d.ts +132 -0
- package/dist/components/treemap.js +179 -0
- package/dist/components/treemap.js.map +1 -0
- package/dist/components/ui.d.ts +159 -46
- package/dist/components/ui.js +220 -115
- package/dist/components/ui.js.map +1 -1
- package/dist/components/use-mobile-reveal.js +1 -0
- package/dist/components/use-mobile-reveal.js.map +1 -1
- package/dist/components/use-table-state.d.ts +1 -1
- package/dist/components/use-table-state.js +38 -17
- package/dist/components/use-table-state.js.map +1 -1
- package/dist/components/user-avatar.d.ts +15 -4
- package/dist/components/user-avatar.js +5 -4
- package/dist/components/user-avatar.js.map +1 -1
- package/dist/components/wizard-stepper.js +3 -2
- package/dist/components/wizard-stepper.js.map +1 -1
- package/dist/{data-table-filters-aXyf0Xub.d.ts → data-table-filters-DM1auUfH.d.ts} +27 -5
- package/dist/data-table.d.ts +7 -0
- package/dist/data-table.js +12 -0
- package/dist/data-table.js.map +1 -0
- package/dist/feedback/feedback-attachment.js +12 -11
- package/dist/feedback/feedback-attachment.js.map +1 -1
- package/dist/feedback/feedback-dialog.js +2 -1
- package/dist/feedback/feedback-dialog.js.map +1 -1
- package/dist/feedback/feedback-inbox.d.ts +33 -7
- package/dist/feedback/feedback-inbox.js +49 -37
- package/dist/feedback/feedback-inbox.js.map +1 -1
- package/dist/feedback.d.ts +5 -0
- package/dist/feedback.js +5 -0
- package/dist/feedback.js.map +1 -0
- package/dist/hooks/use-anchored-panel.js +1 -0
- package/dist/hooks/use-anchored-panel.js.map +1 -1
- package/dist/hooks/use-anchored-rect.js +1 -0
- package/dist/hooks/use-anchored-rect.js.map +1 -1
- package/dist/hooks/use-announce.d.ts +46 -0
- package/dist/hooks/use-announce.js +37 -0
- package/dist/hooks/use-announce.js.map +1 -0
- package/dist/hooks/use-body-scroll-lock.js +1 -0
- package/dist/hooks/use-body-scroll-lock.js.map +1 -1
- package/dist/hooks/use-close-transition.js +1 -0
- package/dist/hooks/use-close-transition.js.map +1 -1
- package/dist/hooks/use-dismiss.js +1 -0
- package/dist/hooks/use-dismiss.js.map +1 -1
- package/dist/hooks/use-focus-trap.d.ts +16 -0
- package/dist/hooks/use-focus-trap.js +67 -0
- package/dist/hooks/use-focus-trap.js.map +1 -0
- package/dist/hooks/use-media-query.js +1 -0
- package/dist/hooks/use-media-query.js.map +1 -1
- package/dist/hooks/use-overlay-history.js +27 -1
- package/dist/hooks/use-overlay-history.js.map +1 -1
- package/dist/hooks/use-row-swipe.js +1 -0
- package/dist/hooks/use-row-swipe.js.map +1 -1
- package/dist/i18n/defaults.d.ts +31 -0
- package/dist/i18n/defaults.js +63 -0
- package/dist/i18n/defaults.js.map +1 -0
- package/dist/i18n/kit-labels.d.ts +250 -0
- package/dist/i18n/kit-labels.js +184 -0
- package/dist/i18n/kit-labels.js.map +1 -0
- package/dist/index.d.ts +47 -22
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/calc.js +1 -0
- package/dist/lib/calc.js.map +1 -1
- package/dist/lib/cn.js +1 -0
- package/dist/lib/cn.js.map +1 -1
- package/dist/lib/dates.js +1 -0
- package/dist/lib/dates.js.map +1 -1
- package/dist/lib/logger.js +1 -0
- package/dist/lib/logger.js.map +1 -1
- package/dist/lib/safe-storage.js +1 -0
- package/dist/lib/safe-storage.js.map +1 -1
- package/dist/search/command-palette.d.ts +11 -1
- package/dist/search/command-palette.js +21 -15
- package/dist/search/command-palette.js.map +1 -1
- package/dist/search.d.ts +2 -0
- package/dist/search.js +3 -0
- package/dist/search.js.map +1 -0
- package/dist/shell/app-shell.d.ts +33 -4
- package/dist/shell/app-shell.js +275 -78
- package/dist/shell/app-shell.js.map +1 -1
- package/dist/shell/option-switcher-menu.js +3 -2
- package/dist/shell/option-switcher-menu.js.map +1 -1
- package/dist/shell/role-switcher.d.ts +6 -0
- package/dist/shell/role-switcher.js +7 -4
- package/dist/shell/role-switcher.js.map +1 -1
- package/dist/shell/top-bar.d.ts +15 -7
- package/dist/shell/top-bar.js +3 -5
- package/dist/shell/top-bar.js.map +1 -1
- package/dist/shell/topbar-action-menu.js +3 -2
- package/dist/shell/topbar-action-menu.js.map +1 -1
- package/dist/shell/topbar-controls.d.ts +5 -2
- package/dist/shell/topbar-controls.js +20 -15
- package/dist/shell/topbar-controls.js.map +1 -1
- package/dist/shell.d.ts +13 -0
- package/dist/shell.js +8 -0
- package/dist/shell.js.map +1 -0
- package/dist/theme/chart-palette.d.ts +19 -12
- package/dist/theme/chart-palette.js +24 -30
- package/dist/theme/chart-palette.js.map +1 -1
- package/dist/theme/color.d.ts +78 -0
- package/dist/theme/color.js +148 -0
- package/dist/theme/color.js.map +1 -0
- package/dist/theme/palette-derive.d.ts +140 -0
- package/dist/theme/palette-derive.js +376 -0
- package/dist/theme/palette-derive.js.map +1 -0
- package/dist/theme/palette-presets.d.ts +27 -5
- package/dist/theme/palette-presets.js +231 -33
- package/dist/theme/palette-presets.js.map +1 -1
- package/dist/theme/palette-store.js +1 -0
- package/dist/theme/palette-store.js.map +1 -1
- package/dist/theme/theme-store.js +1 -0
- package/dist/theme/theme-store.js.map +1 -1
- package/dist/tour/tour.d.ts +2 -1
- package/dist/tour/tour.js +15 -9
- package/dist/tour/tour.js.map +1 -1
- package/dist/tour.d.ts +2 -0
- package/dist/tour.js +3 -0
- package/dist/tour.js.map +1 -0
- package/dist/wizard/stepper-nav.js +10 -8
- package/dist/wizard/stepper-nav.js.map +1 -1
- package/dist/wizard/types.d.ts +18 -2
- package/dist/wizard/types.js +4 -1
- package/dist/wizard/types.js.map +1 -1
- package/dist/wizard/use-wizard.js +12 -4
- package/dist/wizard/use-wizard.js.map +1 -1
- package/dist/wizard/validation.js +1 -0
- package/dist/wizard/validation.js.map +1 -1
- package/dist/wizard/wizard-context.js +1 -0
- package/dist/wizard/wizard-context.js.map +1 -1
- package/dist/wizard/wizard-step.js +1 -0
- package/dist/wizard/wizard-step.js.map +1 -1
- package/dist/wizard/wizard-summary.js +5 -3
- package/dist/wizard/wizard-summary.js.map +1 -1
- package/dist/wizard.d.ts +8 -0
- package/dist/wizard.js +9 -0
- package/dist/wizard.js.map +1 -0
- package/package.json +67 -14
- package/src/chart.ts +22 -0
- package/src/components/account-settings.tsx +275 -0
- package/src/components/alert-banner.tsx +75 -0
- package/src/components/amount-input.tsx +471 -0
- package/src/components/calculator.tsx +252 -0
- package/src/components/chart-zoom.tsx +499 -0
- package/src/components/chart.tsx +363 -0
- package/src/components/checkbox.tsx +222 -0
- package/src/components/chip.tsx +570 -0
- package/src/components/choice-parts.ts +33 -0
- package/src/components/combobox-core.tsx +540 -0
- package/src/components/combobox.tsx +1026 -0
- package/src/components/currency-select.tsx +269 -0
- package/src/components/data-table-filter-popover.tsx +252 -0
- package/src/components/data-table-filters.ts +176 -0
- package/src/components/data-table-labels.ts +190 -0
- package/src/components/data-table-pagination.tsx +126 -0
- package/src/components/data-table-sort.ts +70 -0
- package/src/components/data-table.tsx +1740 -0
- package/src/components/date-picker.tsx +631 -0
- package/src/components/dropdown.tsx +341 -0
- package/src/components/entity-combobox.tsx +215 -0
- package/src/components/facing-pair.ts +86 -0
- package/src/components/field-sync.tsx +472 -0
- package/src/components/file-dropzone.tsx +181 -0
- package/src/components/full-bleed-dialog.tsx +179 -0
- package/src/components/grouped-picker.tsx +157 -0
- package/src/components/hover-menu.tsx +183 -0
- package/src/components/mini-calendar.tsx +554 -0
- package/src/components/modal.tsx +287 -0
- package/src/components/month-picker.tsx +549 -0
- package/src/components/multi-entity-combobox.tsx +226 -0
- package/src/components/multi-select.tsx +303 -0
- package/src/components/number-field.tsx +225 -0
- package/src/components/number-input.tsx +211 -0
- package/src/components/numpad-sheet.tsx +264 -0
- package/src/components/page-contents.tsx +289 -0
- package/src/components/password-strength.tsx +258 -0
- package/src/components/picker-sheet.tsx +251 -0
- package/src/components/popover.tsx +195 -0
- package/src/components/search-field.tsx +146 -0
- package/src/components/series-chart-labels.ts +26 -0
- package/src/components/series-chart.tsx +481 -0
- package/src/components/settings-fields.tsx +68 -0
- package/src/components/signature-pad.tsx +630 -0
- package/src/components/slider.tsx +313 -0
- package/src/components/sparkline.tsx +329 -0
- package/src/components/stat-tile.tsx +448 -0
- package/src/components/swipeable-row.tsx +271 -0
- package/src/components/switch.tsx +170 -0
- package/src/components/time-input.tsx +107 -0
- package/src/components/toggle-group.tsx +153 -0
- package/src/components/toggle-legend.tsx +229 -0
- package/src/components/tooltip.tsx +477 -0
- package/src/components/treemap.tsx +390 -0
- package/src/components/ui.tsx +1284 -0
- package/src/components/use-mobile-reveal.ts +54 -0
- package/src/components/use-table-state.ts +295 -0
- package/src/components/user-avatar.tsx +61 -0
- package/src/components/wizard-stepper.tsx +37 -0
- package/src/data-table.ts +19 -0
- package/src/feedback/feedback-attachment.tsx +246 -0
- package/src/feedback/feedback-dialog.tsx +209 -0
- package/src/feedback/feedback-inbox.tsx +615 -0
- package/src/feedback.ts +8 -0
- package/src/hooks/use-anchored-panel.ts +169 -0
- package/src/hooks/use-anchored-rect.ts +78 -0
- package/src/hooks/use-announce.ts +85 -0
- package/src/hooks/use-body-scroll-lock.ts +94 -0
- package/src/hooks/use-close-transition.ts +99 -0
- package/src/hooks/use-dismiss.ts +77 -0
- package/src/hooks/use-focus-trap.ts +160 -0
- package/src/hooks/use-media-query.ts +23 -0
- package/src/hooks/use-overlay-history.ts +345 -0
- package/src/hooks/use-row-swipe.ts +212 -0
- package/src/i18n/defaults.ts +68 -0
- package/src/i18n/kit-labels.tsx +447 -0
- package/src/index.ts +169 -0
- package/src/lib/calc.ts +309 -0
- package/src/lib/cn.ts +5 -0
- package/src/lib/dates.ts +187 -0
- package/src/lib/logger.ts +73 -0
- package/src/lib/safe-storage.ts +37 -0
- package/src/search/command-palette.tsx +342 -0
- package/src/search.ts +3 -0
- package/src/shell/app-shell.tsx +772 -0
- package/src/shell/option-switcher-menu.tsx +72 -0
- package/src/shell/role-switcher.tsx +46 -0
- package/src/shell/top-bar.tsx +39 -0
- package/src/shell/topbar-action-menu.tsx +91 -0
- package/src/shell/topbar-controls.tsx +229 -0
- package/src/shell.ts +10 -0
- package/src/theme/chart-palette.ts +145 -0
- package/src/theme/color.ts +266 -0
- package/src/theme/palette-derive.ts +681 -0
- package/src/theme/palette-presets.ts +760 -0
- package/src/theme/palette-store.ts +94 -0
- package/src/theme/theme-store.ts +145 -0
- package/src/tour/tour.tsx +586 -0
- package/src/tour.ts +3 -0
- package/src/vite-env.d.ts +26 -0
- package/src/wizard/stepper-nav.tsx +221 -0
- package/src/wizard/types.ts +178 -0
- package/src/wizard/use-wizard.ts +345 -0
- package/src/wizard/validation.ts +37 -0
- package/src/wizard/wizard-context.tsx +29 -0
- package/src/wizard/wizard-step.tsx +14 -0
- package/src/wizard/wizard-summary.tsx +69 -0
- package/src/wizard.ts +14 -0
- package/tokens.css +222 -20
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The phone's endless scroll, in place of the desktop pager (feedback #232).
|
|
5
|
+
*
|
|
6
|
+
* A client-side table already holds every row, so there is nothing to fetch — it simply
|
|
7
|
+
* reveals more of the sorted list as a sentinel scrolls into view. A SERVER-paginated
|
|
8
|
+
* table keeps its pager instead, because the rest of the rows genuinely are not here.
|
|
9
|
+
*
|
|
10
|
+
* The reveal count only ever grows and self-caps at the (re-filtered) list length, which
|
|
11
|
+
* is why nothing resets it: narrowing a filter cannot leave the limit pointing past the
|
|
12
|
+
* end, and widening one does not have to re-reveal what the user already scrolled past.
|
|
13
|
+
*
|
|
14
|
+
* Lifted out of `DataTable` with the rest of its state; the sentinel ref belongs to the
|
|
15
|
+
* caller's `<li>`.
|
|
16
|
+
*/
|
|
17
|
+
export function useMobileReveal<T>({
|
|
18
|
+
rows,
|
|
19
|
+
slice,
|
|
20
|
+
isServer,
|
|
21
|
+
isMdUp,
|
|
22
|
+
defaultPageSize,
|
|
23
|
+
}: {
|
|
24
|
+
/** The whole sorted list — what there is to reveal. */
|
|
25
|
+
rows: T[];
|
|
26
|
+
/** What a server-paginated table shows instead. */
|
|
27
|
+
slice: T[];
|
|
28
|
+
isServer: boolean;
|
|
29
|
+
isMdUp: boolean;
|
|
30
|
+
defaultPageSize: number;
|
|
31
|
+
}) {
|
|
32
|
+
const [mobileLimit, setMobileLimit] = useState(defaultPageSize);
|
|
33
|
+
const mobileSlice = isServer ? slice : rows.slice(0, mobileLimit);
|
|
34
|
+
const canRevealMoreMobile = !isServer && !isMdUp && mobileLimit < rows.length;
|
|
35
|
+
const loadMoreRef = useRef<HTMLLIElement | null>(null);
|
|
36
|
+
|
|
37
|
+
useEffect(() => {
|
|
38
|
+
if (!canRevealMoreMobile) return;
|
|
39
|
+
const el = loadMoreRef.current;
|
|
40
|
+
if (!el || typeof IntersectionObserver === "undefined") return;
|
|
41
|
+
const io = new IntersectionObserver(
|
|
42
|
+
(entries) => {
|
|
43
|
+
if (entries.some((e) => e.isIntersecting)) {
|
|
44
|
+
setMobileLimit((n) => n + (defaultPageSize || 25));
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
{ rootMargin: "300px" },
|
|
48
|
+
);
|
|
49
|
+
io.observe(el);
|
|
50
|
+
return () => io.disconnect();
|
|
51
|
+
}, [canRevealMoreMobile, mobileLimit, defaultPageSize]);
|
|
52
|
+
|
|
53
|
+
return { mobileSlice, canRevealMoreMobile, loadMoreRef };
|
|
54
|
+
}
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import type { useSearchParams } from "react-router";
|
|
3
|
+
import { readStored, writeStored } from "../lib/safe-storage";
|
|
4
|
+
import {
|
|
5
|
+
decodeFilterValue,
|
|
6
|
+
encodeFilterValue,
|
|
7
|
+
isFilterActive,
|
|
8
|
+
resolveFilter,
|
|
9
|
+
} from "./data-table-filters";
|
|
10
|
+
import { decodeSorts, encodeSorts, normalizeSorts, type SortState } from "./data-table-sort";
|
|
11
|
+
import type { DataTableColumn, FilterState } from "./data-table";
|
|
12
|
+
|
|
13
|
+
// ---------- Persisted + URL-encoded view state ----------
|
|
14
|
+
//
|
|
15
|
+
// Moved here with `useTableState` when `DataTable` was split: these are what the hook
|
|
16
|
+
// reads and writes, and nothing else in the table ever called them.
|
|
17
|
+
|
|
18
|
+
interface PersistedState {
|
|
19
|
+
// Multi-sort array; blobs from before the upgrade hold a single {key, dir}
|
|
20
|
+
// object (or null) — read back through normalizeSorts.
|
|
21
|
+
sort: SortState[] | { key: string; dir: string } | null;
|
|
22
|
+
filters: FilterState;
|
|
23
|
+
pageSize: number | "all";
|
|
24
|
+
widths?: Record<string, number>;
|
|
25
|
+
hidden?: string[];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const DEFAULT_PERSIST_PREFIX = "hbui-table:";
|
|
29
|
+
|
|
30
|
+
function loadPersisted(storageKey: string | undefined, prefix: string): Partial<PersistedState> {
|
|
31
|
+
if (!storageKey) return {};
|
|
32
|
+
const raw = readStored(prefix + storageKey);
|
|
33
|
+
if (!raw) return {};
|
|
34
|
+
try {
|
|
35
|
+
const parsed = JSON.parse(raw) as Partial<PersistedState>;
|
|
36
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
37
|
+
} catch {
|
|
38
|
+
return {}; // corrupt JSON — the storage access itself is guarded by readStored
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** The blob that would be stored — also the value the effect below compares by, so
|
|
43
|
+
* the comparison and the write can never disagree about what "unchanged" means. */
|
|
44
|
+
function serializePersisted(state: PersistedState): string {
|
|
45
|
+
return JSON.stringify(state);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ---------- URL sync helpers ----------
|
|
49
|
+
|
|
50
|
+
const URL_FILTER_PREFIX = "f.";
|
|
51
|
+
const URL_SORT_KEY = "sort";
|
|
52
|
+
const URL_PAGE_KEY = "p";
|
|
53
|
+
const URL_PAGE_SIZE_KEY = "ps";
|
|
54
|
+
|
|
55
|
+
interface UrlState {
|
|
56
|
+
sorts?: SortState[];
|
|
57
|
+
filters?: FilterState;
|
|
58
|
+
pageSize?: number; // Infinity for "all"
|
|
59
|
+
page?: number; // 0-based
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function readUrlState<T>(columns: DataTableColumn<T>[]): UrlState {
|
|
63
|
+
if (typeof window === "undefined") return {};
|
|
64
|
+
const sp = new URLSearchParams(window.location.search);
|
|
65
|
+
const out: UrlState = {};
|
|
66
|
+
|
|
67
|
+
const filters: FilterState = {};
|
|
68
|
+
for (const col of columns) {
|
|
69
|
+
const filter = resolveFilter(col);
|
|
70
|
+
if (!filter) continue;
|
|
71
|
+
const raw = sp.get(URL_FILTER_PREFIX + col.key);
|
|
72
|
+
if (raw == null) continue;
|
|
73
|
+
filters[col.key] = decodeFilterValue(filter, raw);
|
|
74
|
+
}
|
|
75
|
+
if (Object.keys(filters).length) out.filters = filters;
|
|
76
|
+
|
|
77
|
+
const sortRaw = sp.get(URL_SORT_KEY);
|
|
78
|
+
if (sortRaw) {
|
|
79
|
+
const decoded = decodeSorts(sortRaw, new Set(columns.map((c) => c.key)));
|
|
80
|
+
if (decoded.length) out.sorts = decoded;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const psRaw = sp.get(URL_PAGE_SIZE_KEY);
|
|
84
|
+
if (psRaw === "all") out.pageSize = Infinity;
|
|
85
|
+
else if (psRaw && Number(psRaw) > 0) out.pageSize = Number(psRaw);
|
|
86
|
+
|
|
87
|
+
const pRaw = sp.get(URL_PAGE_KEY);
|
|
88
|
+
if (pRaw && Number(pRaw) >= 1) out.page = Number(pRaw) - 1;
|
|
89
|
+
|
|
90
|
+
return out;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* The managed part of the query string, as a string, for comparing by VALUE.
|
|
95
|
+
*
|
|
96
|
+
* Everything the table puts in the address and nothing else, in a fixed order.
|
|
97
|
+
* `columns` is walked for its keys only, which is why it can be left out of the
|
|
98
|
+
* effect's dependencies without lying: a new column ARRAY carrying the same keys
|
|
99
|
+
* produces the same signature, and a genuinely different set of filterable columns
|
|
100
|
+
* produces a different one.
|
|
101
|
+
*/
|
|
102
|
+
function urlSignature<T>(
|
|
103
|
+
columns: DataTableColumn<T>[],
|
|
104
|
+
sorts: SortState[],
|
|
105
|
+
filters: FilterState,
|
|
106
|
+
pageSize: number,
|
|
107
|
+
page: number,
|
|
108
|
+
defaultPageSize: number,
|
|
109
|
+
): string {
|
|
110
|
+
const parts: string[] = [];
|
|
111
|
+
for (const col of columns) {
|
|
112
|
+
const state = filters[col.key];
|
|
113
|
+
if (!state || !isFilterActive(state)) continue;
|
|
114
|
+
const enc = encodeFilterValue(state);
|
|
115
|
+
if (enc != null) parts.push(`${URL_FILTER_PREFIX}${col.key}=${enc}`);
|
|
116
|
+
}
|
|
117
|
+
parts.push(`${URL_SORT_KEY}=${encodeSorts(sorts)}`);
|
|
118
|
+
parts.push(
|
|
119
|
+
`${URL_PAGE_SIZE_KEY}=${
|
|
120
|
+
pageSize === Infinity ? "all" : pageSize === defaultPageSize ? "" : String(pageSize)
|
|
121
|
+
}`,
|
|
122
|
+
);
|
|
123
|
+
parts.push(`${URL_PAGE_KEY}=${page > 0 ? String(page + 1) : ""}`);
|
|
124
|
+
return parts.join("&");
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function writeUrlState<T>(
|
|
128
|
+
setSearchParams: ReturnType<typeof useSearchParams>[1],
|
|
129
|
+
columns: DataTableColumn<T>[],
|
|
130
|
+
sorts: SortState[],
|
|
131
|
+
filters: FilterState,
|
|
132
|
+
pageSize: number,
|
|
133
|
+
page: number,
|
|
134
|
+
defaultPageSize: number,
|
|
135
|
+
): void {
|
|
136
|
+
setSearchParams(
|
|
137
|
+
(prev) => {
|
|
138
|
+
const next = new URLSearchParams(prev);
|
|
139
|
+
// clear managed keys
|
|
140
|
+
for (const col of columns) next.delete(URL_FILTER_PREFIX + col.key);
|
|
141
|
+
next.delete(URL_SORT_KEY);
|
|
142
|
+
next.delete(URL_PAGE_KEY);
|
|
143
|
+
next.delete(URL_PAGE_SIZE_KEY);
|
|
144
|
+
// write filters
|
|
145
|
+
for (const col of columns) {
|
|
146
|
+
const state = filters[col.key];
|
|
147
|
+
if (!state || !isFilterActive(state)) continue;
|
|
148
|
+
const enc = encodeFilterValue(state);
|
|
149
|
+
if (enc != null) next.set(URL_FILTER_PREFIX + col.key, enc);
|
|
150
|
+
}
|
|
151
|
+
// write sort
|
|
152
|
+
const sortEnc = encodeSorts(sorts);
|
|
153
|
+
if (sortEnc) next.set(URL_SORT_KEY, sortEnc);
|
|
154
|
+
// write page size if non-default
|
|
155
|
+
if (pageSize === Infinity) next.set(URL_PAGE_SIZE_KEY, "all");
|
|
156
|
+
else if (pageSize !== defaultPageSize) next.set(URL_PAGE_SIZE_KEY, String(pageSize));
|
|
157
|
+
// write page if not first
|
|
158
|
+
if (page > 0) next.set(URL_PAGE_KEY, String(page + 1));
|
|
159
|
+
return next;
|
|
160
|
+
},
|
|
161
|
+
{ replace: true },
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Where a table's view lives: what it is sorted and filtered by, which page, how wide
|
|
167
|
+
* the columns are and which are hidden — plus the two places that outlives a render.
|
|
168
|
+
*
|
|
169
|
+
* Lifted out of `DataTable`, which was 984 lines and twenty hooks in one function. This
|
|
170
|
+
* is the part that is genuinely about STATE rather than about drawing, and the three
|
|
171
|
+
* rules it encodes are easy to lose among the markup:
|
|
172
|
+
*
|
|
173
|
+
* * **The URL is read once, on mount.** A shared or deep link populates the initial view;
|
|
174
|
+
* after that the state is local, or the browser's own history would fight the user's
|
|
175
|
+
* next click.
|
|
176
|
+
* * **Sorting and filtering are optionally CONTROLLED.** A server-driven table passes
|
|
177
|
+
* state and a callback and owns them; everything else is self-owned. That is the
|
|
178
|
+
* `sortsProp ?? internalSorts` pair, and it is why the setters are exposed separately.
|
|
179
|
+
* * **Persistence writes on every change, the URL only when asked.** `storageKey` is the
|
|
180
|
+
* per-table identity; `urlSync` is opt-in because only some tables want their view in
|
|
181
|
+
* a shareable address.
|
|
182
|
+
*/
|
|
183
|
+
export function useTableState<T>({
|
|
184
|
+
columns,
|
|
185
|
+
storageKey,
|
|
186
|
+
storageKeyPrefix,
|
|
187
|
+
urlSync,
|
|
188
|
+
setSearchParams,
|
|
189
|
+
defaultPageSize,
|
|
190
|
+
sortsProp,
|
|
191
|
+
filtersProp,
|
|
192
|
+
}: {
|
|
193
|
+
columns: DataTableColumn<T>[];
|
|
194
|
+
storageKey?: string;
|
|
195
|
+
storageKeyPrefix: string;
|
|
196
|
+
urlSync?: boolean;
|
|
197
|
+
setSearchParams: ReturnType<typeof useSearchParams>[1];
|
|
198
|
+
defaultPageSize: number;
|
|
199
|
+
sortsProp?: SortState[];
|
|
200
|
+
filtersProp?: FilterState;
|
|
201
|
+
}) {
|
|
202
|
+
// Read URL once on mount so URL-encoded views (e.g. shared links, deep links from
|
|
203
|
+
// other pages) populate initial state. After mount, state is local.
|
|
204
|
+
const [urlInitial] = useState<UrlState>(() => (urlSync ? readUrlState(columns) : {}));
|
|
205
|
+
const initial = useMemo(
|
|
206
|
+
() => loadPersisted(storageKey, storageKeyPrefix),
|
|
207
|
+
[storageKey, storageKeyPrefix],
|
|
208
|
+
);
|
|
209
|
+
const [internalSorts, setInternalSorts] = useState<SortState[]>(() =>
|
|
210
|
+
urlInitial.sorts !== undefined ? urlInitial.sorts : normalizeSorts(initial.sort),
|
|
211
|
+
);
|
|
212
|
+
const [internalFilters, setInternalFilters] = useState<FilterState>(
|
|
213
|
+
() => urlInitial.filters ?? initial.filters ?? {},
|
|
214
|
+
);
|
|
215
|
+
// Controlled when the owner passes state + callback (server-driven tables);
|
|
216
|
+
// self-owned otherwise.
|
|
217
|
+
const sorts = sortsProp ?? internalSorts;
|
|
218
|
+
const filters = filtersProp ?? internalFilters;
|
|
219
|
+
const [page, setPage] = useState(() => urlInitial.page ?? 0);
|
|
220
|
+
const [pageSize, setPageSize] = useState<number>(() => {
|
|
221
|
+
if (urlInitial.pageSize !== undefined) return urlInitial.pageSize;
|
|
222
|
+
if (initial.pageSize === "all") return Infinity;
|
|
223
|
+
if (typeof initial.pageSize === "number" && initial.pageSize > 0) return initial.pageSize;
|
|
224
|
+
return defaultPageSize;
|
|
225
|
+
});
|
|
226
|
+
const [widths, setWidths] = useState<Record<string, number>>(() => initial.widths ?? {});
|
|
227
|
+
const [hiddenCols, setHiddenCols] = useState<Set<string>>(() => new Set(initial.hidden ?? []));
|
|
228
|
+
const [showSettings, setShowSettings] = useState(false);
|
|
229
|
+
const headRefs = useMemo(() => new Map<string, HTMLTableCellElement>(), []);
|
|
230
|
+
|
|
231
|
+
// ---- Writing out: both of these compare by VALUE ----
|
|
232
|
+
//
|
|
233
|
+
// A CONTROLLED table (`sorts`/`filters` props plus callbacks — every server-driven
|
|
234
|
+
// one) receives a freshly-built object on every render of the page around it, and
|
|
235
|
+
// `{}` is never `===` the `{}` before it. Keyed on identity, both effects below
|
|
236
|
+
// therefore fired on every unrelated parent render: persistence wrote the same JSON
|
|
237
|
+
// into `localStorage` each time — a synchronous main-thread write, on a page whose
|
|
238
|
+
// other half may be a form being typed into — and the URL one handed react-router a
|
|
239
|
+
// `replace` it answers with a render, which is the loop the audit records. A `ref`
|
|
240
|
+
// holding what was last written is what makes "changed" mean changed.
|
|
241
|
+
const lastPersisted = useRef<string | null>(null);
|
|
242
|
+
const persisted = !storageKey
|
|
243
|
+
? ""
|
|
244
|
+
: serializePersisted({
|
|
245
|
+
sort: sorts,
|
|
246
|
+
filters,
|
|
247
|
+
pageSize: pageSize === Infinity ? "all" : pageSize,
|
|
248
|
+
widths,
|
|
249
|
+
hidden: Array.from(hiddenCols),
|
|
250
|
+
});
|
|
251
|
+
useEffect(() => {
|
|
252
|
+
if (!storageKey) return;
|
|
253
|
+
// The destination is part of the signature: two tables can hold identical state,
|
|
254
|
+
// and a table that swaps `storageKey` has to write under the new one even though
|
|
255
|
+
// nothing about the view changed.
|
|
256
|
+
const target = storageKeyPrefix + storageKey;
|
|
257
|
+
const sig = `${target}\u0000${persisted}`;
|
|
258
|
+
if (lastPersisted.current === sig) return;
|
|
259
|
+
lastPersisted.current = sig;
|
|
260
|
+
writeStored(target, persisted);
|
|
261
|
+
}, [storageKey, storageKeyPrefix, persisted]);
|
|
262
|
+
|
|
263
|
+
const lastUrl = useRef<string | null>(null);
|
|
264
|
+
const urlSig = urlSync
|
|
265
|
+
? urlSignature(columns, sorts, filters, pageSize, page, defaultPageSize)
|
|
266
|
+
: "";
|
|
267
|
+
useEffect(() => {
|
|
268
|
+
if (!urlSync) return;
|
|
269
|
+
if (lastUrl.current === urlSig) return;
|
|
270
|
+
lastUrl.current = urlSig;
|
|
271
|
+
// `columns` is deliberately not a dependency and does not need to be: the
|
|
272
|
+
// signature above is computed from it, so a column set that would produce a
|
|
273
|
+
// different address produces a different signature first.
|
|
274
|
+
writeUrlState(setSearchParams, columns, sorts, filters, pageSize, page, defaultPageSize);
|
|
275
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
276
|
+
}, [urlSync, urlSig]);
|
|
277
|
+
|
|
278
|
+
return {
|
|
279
|
+
sorts,
|
|
280
|
+
filters,
|
|
281
|
+
setInternalSorts,
|
|
282
|
+
setInternalFilters,
|
|
283
|
+
page,
|
|
284
|
+
setPage,
|
|
285
|
+
pageSize,
|
|
286
|
+
setPageSize,
|
|
287
|
+
widths,
|
|
288
|
+
setWidths,
|
|
289
|
+
hiddenCols,
|
|
290
|
+
setHiddenCols,
|
|
291
|
+
showSettings,
|
|
292
|
+
setShowSettings,
|
|
293
|
+
headRefs,
|
|
294
|
+
};
|
|
295
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { ComponentPropsWithoutRef } from "react";
|
|
2
|
+
import { cn } from "../lib/cn";
|
|
3
|
+
|
|
4
|
+
/** Initials from a display name (first + last) or, failing that, an email —
|
|
5
|
+
* e.g. "Marcel Eifert" → "ME", "marcel@x.com" → "MA". App-agnostic.
|
|
6
|
+
*
|
|
7
|
+
* "Failing that" means BLANK, not merely absent. This was `name ?? email ?? "?"`,
|
|
8
|
+
* and `??` falls through on null/undefined alone — so an empty or whitespace-only
|
|
9
|
+
* display name short-circuited the email it had in hand and landed on the guard
|
|
10
|
+
* below, returning "?" for a user whose address says "MA" perfectly well. Keksdose
|
|
11
|
+
* cannot reach it (its `display_name` has `min_length=1`), but this is exported as
|
|
12
|
+
* app-agnostic, and any consumer whose profile name is optional free text got a wall
|
|
13
|
+
* of "?" chips. The guard is what shows the empty case was foreseen; it just
|
|
14
|
+
* answered it at the wrong end. */
|
|
15
|
+
export function avatarInitials(name?: string | null, email?: string | null): string {
|
|
16
|
+
const source = [name, email].map((s) => s?.trim()).find(Boolean) ?? "?";
|
|
17
|
+
const parts = source.split(/\s+/).filter(Boolean);
|
|
18
|
+
if (parts.length >= 2) return (parts[0][0] + parts[1][0]).toUpperCase();
|
|
19
|
+
return source.slice(0, 2).toUpperCase();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const AVATAR_SIZES = {
|
|
23
|
+
sm: "size-7 text-[11px]",
|
|
24
|
+
md: "size-8 text-xs",
|
|
25
|
+
lg: "size-12 text-base",
|
|
26
|
+
} as const;
|
|
27
|
+
|
|
28
|
+
/** A `<span>`'s props, minus `children`: the content is the initials this computes
|
|
29
|
+
* from `name`/`email`, so there is nothing for a caller to put inside. */
|
|
30
|
+
export interface UserAvatarProps extends Omit<ComponentPropsWithoutRef<"span">, "children"> {
|
|
31
|
+
name?: string | null;
|
|
32
|
+
email?: string | null;
|
|
33
|
+
size?: keyof typeof AVATAR_SIZES;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* A round initials avatar — the common user chip shared across apps (feedback
|
|
38
|
+
* #333). Purely presentational; wrap it in a button for the account menu trigger.
|
|
39
|
+
*/
|
|
40
|
+
export function UserAvatar({ name, email, size = "md", className, ...rest }: UserAvatarProps) {
|
|
41
|
+
return (
|
|
42
|
+
<span
|
|
43
|
+
// `aria-hidden` sits BEFORE the spread, unlike the structural attributes on the
|
|
44
|
+
// other components here, because it is a DEFAULT rather than an invariant. The
|
|
45
|
+
// avatar is decorative next to the name it belongs to — which is where all three
|
|
46
|
+
// apps render it — so hiding it stops a screen reader saying "ME" after the word
|
|
47
|
+
// "Marcel Eifert". A caller who renders one ALONE (an assignee column, a
|
|
48
|
+
// presence dot) needs the opposite, and now has it: `aria-hidden={false}` plus an
|
|
49
|
+
// `aria-label` arrives through `...rest` and wins.
|
|
50
|
+
aria-hidden
|
|
51
|
+
{...rest}
|
|
52
|
+
className={cn(
|
|
53
|
+
"inline-flex shrink-0 items-center justify-center rounded-full bg-[var(--bg-inverse)] font-semibold text-[var(--text-inverse)]",
|
|
54
|
+
AVATAR_SIZES[size],
|
|
55
|
+
className,
|
|
56
|
+
)}
|
|
57
|
+
>
|
|
58
|
+
{avatarInitials(name, email)}
|
|
59
|
+
</span>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { cn } from "../lib/cn";
|
|
2
|
+
|
|
3
|
+
/** Compact step indicator for the import wizards. Past steps are plain, the
|
|
4
|
+
* current one is highlighted, future ones muted. */
|
|
5
|
+
export function WizardStepper({
|
|
6
|
+
steps,
|
|
7
|
+
current,
|
|
8
|
+
ariaLabel,
|
|
9
|
+
}: {
|
|
10
|
+
steps: { key: string; label: string }[];
|
|
11
|
+
current: string;
|
|
12
|
+
ariaLabel?: string;
|
|
13
|
+
}) {
|
|
14
|
+
const currentIndex = steps.findIndex((s) => s.key === current);
|
|
15
|
+
return (
|
|
16
|
+
<ol className="flex items-center gap-1 text-xs" aria-label={ariaLabel}>
|
|
17
|
+
{steps.map((step, i) => (
|
|
18
|
+
<li key={step.key} className="flex items-center gap-1">
|
|
19
|
+
{i > 0 && <span className="w-4 border-t border-[var(--border)]" />}
|
|
20
|
+
<span
|
|
21
|
+
aria-current={step.key === current ? "step" : undefined}
|
|
22
|
+
className={cn(
|
|
23
|
+
"rounded-full px-2 py-0.5",
|
|
24
|
+
i === currentIndex
|
|
25
|
+
? "bg-[var(--bg-inverse)] text-[var(--text-inverse)] font-medium"
|
|
26
|
+
: i < currentIndex
|
|
27
|
+
? "text-[var(--text-secondary)]"
|
|
28
|
+
: "text-[var(--text-placeholder)]",
|
|
29
|
+
)}
|
|
30
|
+
>
|
|
31
|
+
{step.label}
|
|
32
|
+
</span>
|
|
33
|
+
</li>
|
|
34
|
+
))}
|
|
35
|
+
</ol>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// `@eifi1/ui-kit/data-table` — the table suite.
|
|
2
|
+
//
|
|
3
|
+
// A re-slicing of the main barrel, not a new API. This entry point requires
|
|
4
|
+
// `react-router`: DataTable calls useSearchParams unconditionally, above any `urlSync`
|
|
5
|
+
// branch, so a Router is needed even with URL sync switched off.
|
|
6
|
+
export * from "./components/data-table-labels";
|
|
7
|
+
export * from "./components/data-table-sort";
|
|
8
|
+
export * from "./components/data-table-filters";
|
|
9
|
+
export * from "./components/data-table-pagination";
|
|
10
|
+
export { FilterPopover } from "./components/data-table-filter-popover";
|
|
11
|
+
// `SortState` comes from data-table-sort above; re-exporting the module wholesale
|
|
12
|
+
// would collide with it, which is why the main barrel names these explicitly too.
|
|
13
|
+
export { DataTable } from "./components/data-table";
|
|
14
|
+
export type {
|
|
15
|
+
DataTableColumn,
|
|
16
|
+
DataTableProps,
|
|
17
|
+
ServerPagination,
|
|
18
|
+
FilterState,
|
|
19
|
+
} from "./components/data-table";
|