basalt-ui 1.25.0 → 1.27.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/AGENTS.md +8 -6
- package/CHANGELOG.md +26 -0
- package/MIGRATING.md +815 -23
- package/README.md +45 -32
- package/agent/rules/basalt-batteries.md +205 -0
- package/agent/rules/basalt-charts.md +125 -555
- package/agent/rules/basalt-controls.md +160 -0
- package/agent/rules/basalt-mantine.md +146 -439
- package/agent/rules/basalt-state.md +118 -96
- package/agent/rules/basalt-tokens.md +126 -288
- package/agent/skills/basalt-app/SKILL.md +70 -195
- package/agent/skills/basalt-charts/SKILL.md +54 -234
- package/agent/skills/basalt-design/SKILL.md +56 -248
- package/agent/templates/CLAUDE-block.md.tpl +31 -40
- package/agent/templates/DESIGN.md.tpl +22 -51
- package/configs/oxlint-plugin.js +1465 -36
- package/configs/oxlint-plugin.test.ts +1190 -11
- package/configs/oxlint.json +11 -3
- package/dist/charts/cursor/resolve.d.ts +18 -0
- package/dist/charts/cursor/resolve.d.ts.map +1 -1
- package/dist/charts/cursor/resolve.js +15 -6
- package/dist/charts/cursor/scope.d.ts +6 -3
- package/dist/charts/cursor/scope.d.ts.map +1 -1
- package/dist/charts/cursor/store.d.ts +5 -1
- package/dist/charts/cursor/store.d.ts.map +1 -1
- package/dist/charts/cursor/store.js +4 -4
- package/dist/charts/hooks/useChartCursor.d.ts.map +1 -1
- package/dist/charts/hooks/useChartCursor.js +9 -8
- package/dist/charts/index.d.ts +2 -2
- package/dist/charts/index.d.ts.map +1 -1
- package/dist/charts/primitives/ChartCard.d.ts +34 -9
- package/dist/charts/primitives/ChartCard.d.ts.map +1 -1
- package/dist/charts/primitives/ChartCard.js +29 -114
- package/dist/charts/primitives/ChartCard.test.d.ts +2 -0
- package/dist/charts/primitives/ChartCard.test.d.ts.map +1 -0
- package/dist/charts/sparklines/BarSparkline.d.ts +26 -2
- package/dist/charts/sparklines/BarSparkline.d.ts.map +1 -1
- package/dist/charts/sparklines/BarSparkline.js +18 -4
- package/dist/cli/check-coverage.test.d.ts +2 -0
- package/dist/cli/check-coverage.test.d.ts.map +1 -0
- package/dist/cli/index.d.ts +67 -4
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +225 -7
- package/dist/connectivity/connectivity-indicator.d.ts +4 -1
- package/dist/connectivity/connectivity-indicator.d.ts.map +1 -1
- package/dist/connectivity/connectivity-indicator.js +1 -1
- package/dist/content/index.d.ts +5 -3
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/index.js +4 -2
- package/dist/content/prose.module.css +7 -28
- package/dist/controls/actions.d.ts +169 -0
- package/dist/controls/actions.d.ts.map +1 -0
- package/dist/controls/actions.js +287 -0
- package/dist/controls/actions.module.css +62 -0
- package/dist/controls/actions.module.css.d.ts +13 -0
- package/dist/controls/actions.test.d.ts +2 -0
- package/dist/controls/actions.test.d.ts.map +1 -0
- package/dist/controls/actions.type-guard.test.d.ts +2 -0
- package/dist/controls/actions.type-guard.test.d.ts.map +1 -0
- package/dist/controls/compare-filter.d.ts +41 -0
- package/dist/controls/compare-filter.d.ts.map +1 -0
- package/dist/controls/compare-filter.js +23 -0
- package/dist/controls/control-group.d.ts +19 -0
- package/dist/controls/control-group.d.ts.map +1 -0
- package/dist/controls/control-group.js +20 -0
- package/dist/controls/control-group.test.d.ts +2 -0
- package/dist/controls/control-group.test.d.ts.map +1 -0
- package/dist/controls/controls.module.css +542 -0
- package/dist/controls/controls.module.css.d.ts +35 -0
- package/dist/controls/controls.router.test.d.ts +2 -0
- package/dist/controls/controls.router.test.d.ts.map +1 -0
- package/dist/controls/enum-filter.d.ts +39 -0
- package/dist/controls/enum-filter.d.ts.map +1 -0
- package/dist/controls/enum-filter.js +93 -0
- package/dist/controls/filter-context.d.ts +60 -0
- package/dist/controls/filter-context.d.ts.map +1 -0
- package/dist/controls/filter-context.js +69 -0
- package/dist/controls/filter-pill.d.ts +28 -0
- package/dist/controls/filter-pill.d.ts.map +1 -0
- package/dist/controls/filter-pill.js +70 -0
- package/dist/controls/filter-set.d.ts +13 -0
- package/dist/controls/filter-set.d.ts.map +1 -0
- package/dist/controls/filter-set.js +125 -0
- package/dist/controls/filter-set.test.d.ts +2 -0
- package/dist/controls/filter-set.test.d.ts.map +1 -0
- package/dist/controls/filter-sheet.d.ts +117 -0
- package/dist/controls/filter-sheet.d.ts.map +1 -0
- package/dist/controls/filter-sheet.js +146 -0
- package/dist/controls/glyphs.d.ts +27 -0
- package/dist/controls/glyphs.d.ts.map +1 -0
- package/dist/controls/glyphs.js +49 -0
- package/dist/controls/index.d.ts +20 -0
- package/dist/controls/index.d.ts.map +1 -0
- package/dist/controls/index.js +46 -0
- package/dist/controls/multi-select-filter.d.ts +23 -0
- package/dist/controls/multi-select-filter.d.ts.map +1 -0
- package/dist/controls/multi-select-filter.js +89 -0
- package/dist/controls/number-filter.d.ts +26 -0
- package/dist/controls/number-filter.d.ts.map +1 -0
- package/dist/controls/number-filter.js +143 -0
- package/dist/controls/peer-boundary.test.d.ts +2 -0
- package/dist/controls/peer-boundary.test.d.ts.map +1 -0
- package/dist/controls/props-contract.test.d.ts +2 -0
- package/dist/controls/props-contract.test.d.ts.map +1 -0
- package/dist/controls/range-filter.d.ts +43 -0
- package/dist/controls/range-filter.d.ts.map +1 -0
- package/dist/controls/range-filter.js +135 -0
- package/dist/controls/range-filter.type-guard.test.d.ts +2 -0
- package/dist/controls/range-filter.type-guard.test.d.ts.map +1 -0
- package/dist/controls/search-filter.d.ts +10 -0
- package/dist/controls/search-filter.d.ts.map +1 -0
- package/dist/controls/search-filter.js +81 -0
- package/dist/controls/select-filter.d.ts +74 -0
- package/dist/controls/select-filter.d.ts.map +1 -0
- package/dist/controls/select-filter.js +10 -0
- package/dist/controls/sync-button.d.ts +38 -0
- package/dist/controls/sync-button.d.ts.map +1 -0
- package/dist/controls/sync-button.js +119 -0
- package/dist/controls/sync-button.module.css +63 -0
- package/dist/controls/sync-button.module.css.d.ts +11 -0
- package/dist/controls/sync-button.test.d.ts +2 -0
- package/dist/controls/sync-button.test.d.ts.map +1 -0
- package/dist/controls/toggle-filter.d.ts +9 -0
- package/dist/controls/toggle-filter.d.ts.map +1 -0
- package/dist/controls/toggle-filter.js +42 -0
- package/dist/controls/view-tabs.d.ts +23 -0
- package/dist/controls/view-tabs.d.ts.map +1 -0
- package/dist/controls/view-tabs.js +59 -0
- package/dist/controls-dates/date-range-picker.d.ts +4 -0
- package/dist/controls-dates/date-range-picker.d.ts.map +1 -0
- package/dist/controls-dates/date-range-picker.js +18 -0
- package/dist/controls-dates/index.d.ts +9 -0
- package/dist/controls-dates/index.d.ts.map +1 -0
- package/dist/controls-dates/index.js +4 -0
- package/dist/dashboard/delta-badge.d.ts +6 -12
- package/dist/dashboard/delta-badge.d.ts.map +1 -1
- package/dist/dashboard/delta-badge.js +1 -50
- package/dist/dashboard/index.d.ts +1 -1
- package/dist/dashboard/index.d.ts.map +1 -1
- package/dist/dashboard/index.js +3 -1
- package/dist/dashboard/settings-section.d.ts +6 -4
- package/dist/dashboard/settings-section.d.ts.map +1 -1
- package/dist/dashboard/settings-section.js +23 -16
- package/dist/dashboard/settings-section.module.css +10 -0
- package/dist/dashboard/settings-section.module.css.d.ts +1 -0
- package/dist/dashboard/settings-section.test.d.ts +2 -0
- package/dist/dashboard/settings-section.test.d.ts.map +1 -0
- package/dist/dashboard/stat-card.d.ts +95 -9
- package/dist/dashboard/stat-card.d.ts.map +1 -1
- package/dist/dashboard/stat-card.js +108 -49
- package/dist/dashboard/stat-card.module.css +153 -0
- package/dist/dashboard/stat-card.module.css.d.ts +15 -0
- package/dist/data/data-table.d.ts +37 -15
- package/dist/data/data-table.d.ts.map +1 -1
- package/dist/data/data-table.js +96 -58
- package/dist/guard/grace.test.d.ts +20 -0
- package/dist/guard/grace.test.d.ts.map +1 -0
- package/dist/guard/index.d.ts +66 -3
- package/dist/guard/index.d.ts.map +1 -1
- package/dist/guard/index.js +78 -7
- package/dist/guard/types.d.ts +3 -3
- package/dist/guard/types.d.ts.map +1 -1
- package/dist/index.d.ts +13 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -10
- package/dist/nav/types.d.ts +78 -2
- package/dist/nav/types.d.ts.map +1 -1
- package/dist/notifications/bell.d.ts +4 -1
- package/dist/notifications/bell.d.ts.map +1 -1
- package/dist/notifications/index.d.ts +1 -1
- package/dist/router-tanstack/field.d.ts +14 -0
- package/dist/router-tanstack/field.d.ts.map +1 -0
- package/dist/router-tanstack/field.js +4 -0
- package/dist/router-tanstack/index.d.ts +6 -2
- package/dist/router-tanstack/index.d.ts.map +1 -1
- package/dist/router-tanstack/index.js +4 -0
- package/dist/router-tanstack/multi-search-param-store.d.ts +4 -52
- package/dist/router-tanstack/multi-search-param-store.d.ts.map +1 -1
- package/dist/router-tanstack/multi-search-param-store.js +19 -27
- package/dist/router-tanstack/search-param-store.d.ts +3 -87
- package/dist/router-tanstack/search-param-store.d.ts.map +1 -1
- package/dist/router-tanstack/search-param-store.js +16 -45
- package/dist/router-tanstack/search-store.d.ts +84 -0
- package/dist/router-tanstack/search-store.d.ts.map +1 -0
- package/dist/router-tanstack/search-store.js +271 -0
- package/dist/router-tanstack/search-store.router.test.d.ts +2 -0
- package/dist/router-tanstack/search-store.router.test.d.ts.map +1 -0
- package/dist/router-tanstack/search-store.test.d.ts +2 -0
- package/dist/router-tanstack/search-store.test.d.ts.map +1 -0
- package/dist/router-tanstack/use-nav.d.ts +0 -2
- package/dist/router-tanstack/use-nav.d.ts.map +1 -1
- package/dist/router-tanstack/use-nav.js +34 -12
- package/dist/router-tanstack/use-nav.test.d.ts +2 -0
- package/dist/router-tanstack/use-nav.test.d.ts.map +1 -0
- package/dist/section/index.d.ts +2 -0
- package/dist/section/index.d.ts.map +1 -0
- package/dist/section/index.js +4 -0
- package/dist/section/section.d.ts +24 -0
- package/dist/section/section.d.ts.map +1 -0
- package/dist/section/section.js +126 -0
- package/dist/section/section.module.css +104 -0
- package/dist/section/section.module.css.d.ts +11 -0
- package/dist/section/section.test.d.ts +2 -0
- package/dist/section/section.test.d.ts.map +1 -0
- package/dist/shell/app-breadcrumbs.d.ts.map +1 -1
- package/dist/shell/app-breadcrumbs.js +18 -15
- package/dist/shell/app-header.module.css +77 -37
- package/dist/shell/app-header.module.css.d.ts +2 -1
- package/dist/shell/app-mobile-nav.d.ts +9 -2
- package/dist/shell/app-mobile-nav.d.ts.map +1 -1
- package/dist/shell/app-mobile-nav.js +98 -11
- package/dist/shell/app-mobile-nav.module.css +8 -0
- package/dist/shell/app-mobile-nav.module.css.d.ts +1 -0
- package/dist/shell/app-sidebar.d.ts +55 -28
- package/dist/shell/app-sidebar.d.ts.map +1 -1
- package/dist/shell/app-sidebar.js +116 -67
- package/dist/shell/app-sidebar.module.css +303 -20
- package/dist/shell/app-sidebar.module.css.d.ts +19 -1
- package/dist/shell/index.d.ts +55 -21
- package/dist/shell/index.d.ts.map +1 -1
- package/dist/shell/index.js +40 -18
- package/dist/shell/mobile-nav-model.d.ts +13 -2
- package/dist/shell/mobile-nav-model.d.ts.map +1 -1
- package/dist/shell/mobile-nav-model.js +15 -1
- package/dist/shell/nav-count-badge.d.ts +1 -1
- package/dist/shell/page-bar.d.ts +51 -0
- package/dist/shell/page-bar.d.ts.map +1 -0
- package/dist/shell/page-bar.js +154 -0
- package/dist/shell/page-bar.module.css +178 -0
- package/dist/shell/page-bar.module.css.d.ts +17 -0
- package/dist/shell/page-bar.test.d.ts +2 -0
- package/dist/shell/page-bar.test.d.ts.map +1 -0
- package/dist/shell/sidebar-block-model.d.ts +48 -0
- package/dist/shell/sidebar-block-model.d.ts.map +1 -0
- package/dist/shell/sidebar-block-model.js +39 -0
- package/dist/shell/sidebar-blocks.d.ts +32 -0
- package/dist/shell/sidebar-blocks.d.ts.map +1 -0
- package/dist/shell/sidebar-blocks.js +169 -0
- package/dist/shell/sidebar-search.d.ts +13 -1
- package/dist/shell/sidebar-search.d.ts.map +1 -1
- package/dist/shell/sidebar-search.js +34 -1
- package/dist/shell/sidebar-search.module.css +26 -0
- package/dist/shell/sidebar-search.module.css.d.ts +2 -0
- package/dist/state/fields.d.ts +565 -0
- package/dist/state/fields.d.ts.map +1 -0
- package/dist/state/fields.js +405 -0
- package/dist/state/fields.test.d.ts +2 -0
- package/dist/state/fields.test.d.ts.map +1 -0
- package/dist/state/persisted.d.ts +60 -0
- package/dist/state/persisted.d.ts.map +1 -0
- package/dist/state/persisted.js +123 -0
- package/dist/state/persisted.test.d.ts +2 -0
- package/dist/state/persisted.test.d.ts.map +1 -0
- package/dist/state.d.ts +11 -56
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +14 -120
- package/dist/styles.css +13 -0
- package/dist/surfaces.d.ts +106 -24
- package/dist/surfaces.d.ts.map +1 -1
- package/dist/surfaces.js +156 -19
- package/dist/theme/controls.module.css +16 -1
- package/dist/theme/ctl-theme.d.ts +32 -0
- package/dist/theme/ctl-theme.d.ts.map +1 -0
- package/dist/theme/ctl-theme.js +54 -0
- package/dist/theme/ctl-theme.test.d.ts +2 -0
- package/dist/theme/ctl-theme.test.d.ts.map +1 -0
- package/dist/theme/ctl-tier-coverage.test.d.ts +2 -0
- package/dist/theme/ctl-tier-coverage.test.d.ts.map +1 -0
- package/dist/theme/divider-law.test.d.ts +2 -0
- package/dist/theme/divider-law.test.d.ts.map +1 -0
- package/dist/theme/icon-slot.d.ts +44 -0
- package/dist/theme/icon-slot.d.ts.map +1 -0
- package/dist/theme/icon-slot.js +21 -0
- package/dist/theme/icon-slot.module.css +47 -0
- package/dist/theme/icon-slot.module.css.d.ts +8 -0
- package/dist/theme/icon-slot.test.d.ts +2 -0
- package/dist/theme/icon-slot.test.d.ts.map +1 -0
- package/dist/theme/index.d.ts +1 -0
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/index.js +82 -5
- package/dist/theme/layout-rhythm-css.test.d.ts +2 -0
- package/dist/theme/layout-rhythm-css.test.d.ts.map +1 -0
- package/dist/theme/segmented-control.module.css +20 -0
- package/dist/theme/shadow-surfaces.test.d.ts.map +1 -1
- package/dist/tokens/index.d.ts +12 -0
- package/dist/tokens/index.d.ts.map +1 -1
- package/dist/tokens/index.js +38 -8
- package/dist/tokens/palette.d.ts +97 -61
- package/dist/tokens/palette.d.ts.map +1 -1
- package/dist/tokens/palette.js +76 -38
- package/dist/tokens.css +10 -2
- package/dist/widget-header/delta-badge.d.ts +13 -0
- package/dist/widget-header/delta-badge.d.ts.map +1 -0
- package/dist/widget-header/delta-badge.js +29 -0
- package/dist/widget-header/delta-badge.test.d.ts +2 -0
- package/dist/widget-header/delta-badge.test.d.ts.map +1 -0
- package/dist/widget-header/index.d.ts +3 -0
- package/dist/widget-header/index.d.ts.map +1 -0
- package/dist/widget-header/index.js +6 -0
- package/dist/widget-header/no-mantine.test.d.ts +2 -0
- package/dist/widget-header/no-mantine.test.d.ts.map +1 -0
- package/dist/widget-header/widget-header.d.ts +67 -0
- package/dist/widget-header/widget-header.d.ts.map +1 -0
- package/dist/widget-header/widget-header.js +89 -0
- package/dist/widget-header/widget-header.module.css +350 -0
- package/dist/widget-header/widget-header.module.css.d.ts +25 -0
- package/dist/widget-header/widget-header.test.d.ts +2 -0
- package/dist/widget-header/widget-header.test.d.ts.map +1 -0
- package/llms.txt +30 -17
- package/package.json +14 -1
- package/src/charts/cursor/resolve.test.ts +29 -1
- package/src/charts/cursor/resolve.ts +38 -6
- package/src/charts/cursor/scope.tsx +6 -3
- package/src/charts/cursor/store.test.ts +19 -1
- package/src/charts/cursor/store.ts +10 -5
- package/src/charts/hooks/useChartCursor.ts +16 -8
- package/src/charts/index.ts +2 -2
- package/src/charts/primitives/CartesianChart.test.tsx +124 -0
- package/src/charts/primitives/ChartCard.test.tsx +66 -0
- package/src/charts/primitives/ChartCard.tsx +86 -146
- package/src/charts/sparklines/BarSparkline.tsx +43 -5
- package/src/cli/check-coverage.test.ts +297 -0
- package/src/cli/check-theme.test.ts +38 -14
- package/src/cli/index.ts +392 -16
- package/src/cli/init-sync.test.ts +97 -0
- package/src/connectivity/connectivity-indicator.tsx +16 -9
- package/src/content/index.ts +16 -3
- package/src/content/prose.module.css +7 -28
- package/src/content/prose.module.css.test.ts +8 -24
- package/src/controls/actions.module.css +62 -0
- package/src/controls/actions.module.css.d.ts +13 -0
- package/src/controls/actions.test.tsx +252 -0
- package/src/controls/actions.tsx +655 -0
- package/src/controls/actions.type-guard.test.ts +63 -0
- package/src/controls/compare-filter.tsx +64 -0
- package/src/controls/control-group.test.tsx +229 -0
- package/src/controls/control-group.tsx +63 -0
- package/src/controls/controls.module.css +542 -0
- package/src/controls/controls.module.css.d.ts +35 -0
- package/src/controls/controls.router.test.tsx +1053 -0
- package/src/controls/enum-filter.tsx +170 -0
- package/src/controls/filter-context.tsx +158 -0
- package/src/controls/filter-pill.tsx +120 -0
- package/src/controls/filter-set.test.tsx +472 -0
- package/src/controls/filter-set.tsx +225 -0
- package/src/controls/filter-sheet.tsx +285 -0
- package/src/controls/glyphs.tsx +81 -0
- package/src/controls/index.ts +49 -0
- package/src/controls/multi-select-filter.tsx +140 -0
- package/src/controls/number-filter.tsx +291 -0
- package/src/controls/peer-boundary.test.ts +85 -0
- package/src/controls/props-contract.test.tsx +137 -0
- package/src/controls/range-filter.tsx +237 -0
- package/src/controls/range-filter.type-guard.test.tsx +122 -0
- package/src/controls/search-filter.tsx +123 -0
- package/src/controls/select-filter.tsx +89 -0
- package/src/controls/sync-button.module.css +63 -0
- package/src/controls/sync-button.module.css.d.ts +11 -0
- package/src/controls/sync-button.test.tsx +183 -0
- package/src/controls/sync-button.tsx +197 -0
- package/src/controls/toggle-filter.tsx +60 -0
- package/src/controls/view-tabs.tsx +110 -0
- package/src/controls-dates/date-range-picker.tsx +42 -0
- package/src/controls-dates/index.ts +8 -0
- package/src/dashboard/delta-badge.tsx +4 -74
- package/src/dashboard/index.ts +6 -1
- package/src/dashboard/settings-section.module.css +10 -0
- package/src/dashboard/settings-section.module.css.d.ts +1 -0
- package/src/dashboard/settings-section.test.tsx +56 -0
- package/src/dashboard/settings-section.tsx +33 -30
- package/src/dashboard/stat-card.module.css +153 -0
- package/src/dashboard/stat-card.module.css.d.ts +15 -0
- package/src/dashboard/stat-card.test.tsx +298 -1
- package/src/dashboard/stat-card.tsx +289 -67
- package/src/data/data-table.test.tsx +96 -11
- package/src/data/data-table.tsx +228 -84
- package/src/guard/check-source.test.ts +159 -13
- package/src/guard/grace.test.ts +158 -0
- package/src/guard/index.ts +185 -29
- package/src/guard/types.ts +4 -2
- package/src/index.ts +51 -5
- package/src/nav/types.ts +84 -2
- package/src/notifications/bell.tsx +6 -3
- package/src/notifications/index.ts +1 -1
- package/src/router-tanstack/field.ts +35 -0
- package/src/router-tanstack/index.ts +28 -2
- package/src/router-tanstack/multi-search-param-store.test.ts +71 -3
- package/src/router-tanstack/multi-search-param-store.ts +46 -77
- package/src/router-tanstack/search-param-store.ts +42 -159
- package/src/router-tanstack/search-store.router.test.tsx +882 -0
- package/src/router-tanstack/search-store.test.ts +578 -0
- package/src/router-tanstack/search-store.ts +546 -0
- package/src/router-tanstack/use-nav.test.tsx +187 -0
- package/src/router-tanstack/use-nav.ts +72 -14
- package/src/section/index.ts +1 -0
- package/src/section/section.module.css +104 -0
- package/src/section/section.module.css.d.ts +11 -0
- package/src/section/section.test.tsx +204 -0
- package/src/section/section.tsx +220 -0
- package/src/shell/app-breadcrumbs.tsx +44 -31
- package/src/shell/app-header.module.css +77 -37
- package/src/shell/app-header.module.css.d.ts +2 -1
- package/src/shell/app-mobile-nav.module.css +8 -0
- package/src/shell/app-mobile-nav.module.css.d.ts +1 -0
- package/src/shell/app-mobile-nav.tsx +147 -8
- package/src/shell/app-sidebar-account.tsx +2 -2
- package/src/shell/app-sidebar.module.css +303 -20
- package/src/shell/app-sidebar.module.css.d.ts +19 -1
- package/src/shell/app-sidebar.test.tsx +456 -41
- package/src/shell/app-sidebar.tsx +276 -140
- package/src/shell/index.test.tsx +291 -5
- package/src/shell/index.tsx +137 -38
- package/src/shell/mobile-nav-model.test.ts +228 -7
- package/src/shell/mobile-nav-model.ts +53 -3
- package/src/shell/nav-count-badge.tsx +1 -1
- package/src/shell/page-bar.module.css +178 -0
- package/src/shell/page-bar.module.css.d.ts +17 -0
- package/src/shell/page-bar.test.tsx +316 -0
- package/src/shell/page-bar.tsx +315 -0
- package/src/shell/sidebar-block-model.ts +83 -0
- package/src/shell/sidebar-blocks.tsx +301 -0
- package/src/shell/sidebar-search.module.css +26 -0
- package/src/shell/sidebar-search.module.css.d.ts +2 -0
- package/src/shell/sidebar-search.tsx +71 -2
- package/src/state/fields.test.tsx +512 -0
- package/src/state/fields.ts +1150 -0
- package/src/state/persisted.test.ts +91 -0
- package/src/state/persisted.ts +261 -0
- package/src/state.ts +52 -240
- package/src/styles.css +13 -0
- package/src/surfaces.ts +204 -36
- package/src/theme/controls.module.css +16 -1
- package/src/theme/ctl-theme.test.tsx +275 -0
- package/src/theme/ctl-theme.tsx +138 -0
- package/src/theme/ctl-tier-coverage.test.ts +170 -0
- package/src/theme/density-relations.test.ts +106 -51
- package/src/theme/divider-law.test.ts +259 -0
- package/src/theme/icon-slot.module.css +47 -0
- package/src/theme/icon-slot.module.css.d.ts +8 -0
- package/src/theme/icon-slot.test.tsx +275 -0
- package/src/theme/icon-slot.tsx +59 -0
- package/src/theme/index.ts +165 -3
- package/src/theme/layout-rhythm-css.test.ts +72 -0
- package/src/theme/radius.test.ts +11 -1
- package/src/theme/segmented-control.module.css +20 -0
- package/src/theme/shadow-surfaces.test.ts +20 -7
- package/src/theme/spacing.test.ts +75 -27
- package/src/theme/use-basalt-spacing.ts +2 -2
- package/src/tokens/density.test.ts +7 -25
- package/src/tokens/index.ts +48 -8
- package/src/tokens/palette.ts +107 -73
- package/src/widget-header/delta-badge.test.tsx +60 -0
- package/src/widget-header/delta-badge.tsx +57 -0
- package/src/widget-header/index.ts +2 -0
- package/src/widget-header/no-mantine.test.ts +33 -0
- package/src/widget-header/widget-header.module.css +350 -0
- package/src/widget-header/widget-header.module.css.d.ts +25 -0
- package/src/widget-header/widget-header.test.tsx +187 -0
- package/src/widget-header/widget-header.tsx +213 -0
- package/agent/rules/basalt-agent.md +0 -452
- package/agent/rules/basalt-app.md +0 -246
- package/agent/rules/basalt-commands.md +0 -320
- package/agent/rules/basalt-content.md +0 -409
- package/agent/rules/basalt-data.md +0 -329
- package/agent/rules/basalt-forms.md +0 -186
- package/agent/rules/basalt-notifications.md +0 -264
- package/agent/rules/basalt-query.md +0 -187
- package/agent/rules/basalt-router.md +0 -336
- package/dist/content/article-filter-bar.d.ts +0 -40
- package/dist/content/article-filter-bar.d.ts.map +0 -1
- package/dist/content/article-filter-bar.js +0 -56
- package/dist/shell/page-header.d.ts +0 -13
- package/dist/shell/page-header.d.ts.map +0 -1
- package/dist/shell/page-header.js +0 -23
- package/src/content/article-filter-bar.tsx +0 -88
- package/src/shell/page-header.tsx +0 -35
package/src/data/data-table.tsx
CHANGED
|
@@ -21,27 +21,18 @@
|
|
|
21
21
|
* <BasaltDataTable data={rows} columns={columns} />
|
|
22
22
|
*
|
|
23
23
|
* @example
|
|
24
|
-
* // With the toolbar + pagination bar:
|
|
24
|
+
* // With the title, the toolbar + pagination bar:
|
|
25
25
|
* <BasaltDataTable
|
|
26
|
+
* title="Top pages"
|
|
26
27
|
* data={rows}
|
|
27
28
|
* columns={columns}
|
|
28
29
|
* enableGlobalFilter
|
|
29
30
|
* facets={[{ columnId: 'department', label: 'Department', options: departmentOptions }]}
|
|
30
|
-
*
|
|
31
|
+
* actions={<Button>Export</Button>}
|
|
31
32
|
* enablePagination
|
|
32
33
|
* />
|
|
33
34
|
*/
|
|
34
|
-
import {
|
|
35
|
-
Box,
|
|
36
|
-
Group,
|
|
37
|
-
MultiSelect,
|
|
38
|
-
Pagination,
|
|
39
|
-
Select,
|
|
40
|
-
Skeleton,
|
|
41
|
-
Table,
|
|
42
|
-
Text,
|
|
43
|
-
TextInput,
|
|
44
|
-
} from '@mantine/core'
|
|
35
|
+
import { Box, Group, Pagination, Select, Skeleton, Table, Text, TextInput } from '@mantine/core'
|
|
45
36
|
import type { MantineSpacing } from '@mantine/core'
|
|
46
37
|
import type {
|
|
47
38
|
Column,
|
|
@@ -65,7 +56,17 @@ import {
|
|
|
65
56
|
} from '@tanstack/react-table'
|
|
66
57
|
import type { CSSProperties, ReactNode } from 'react'
|
|
67
58
|
import { useCallback, useMemo, useState } from 'react'
|
|
59
|
+
import { FilterSet } from '../controls'
|
|
60
|
+
// `EnumFilter` is deliberately NOT on the `./controls` barrel (`docs/CONTROLS-SPEC.md` §3 —
|
|
61
|
+
// reaching for it directly is hand-rolling a filter, `basalt/hand-rolled-filter`); a facet column
|
|
62
|
+
// is the one place inside the framework itself that legitimately builds a `FieldHandle` over
|
|
63
|
+
// something that is not a store field, so it reaches past the barrel on purpose.
|
|
64
|
+
import { EnumFilter } from '../controls/enum-filter'
|
|
65
|
+
import { MultiSelectFilter } from '../controls/multi-select-filter'
|
|
66
|
+
import { CtlSlot } from '../theme'
|
|
68
67
|
import { alpha, VX } from '../tokens'
|
|
68
|
+
import type { EnumField, FieldHandle, MultiField } from '../state'
|
|
69
|
+
import { WidgetHeader } from '../widget-header'
|
|
69
70
|
|
|
70
71
|
// ── Column alignment ──────────────────────────────────────────────────────────
|
|
71
72
|
|
|
@@ -113,17 +114,17 @@ function resolveAlign<T>(column: Column<T, unknown>): DataTableAlign | undefined
|
|
|
113
114
|
|
|
114
115
|
// ── Facets ────────────────────────────────────────────────────────────────────
|
|
115
116
|
|
|
116
|
-
/** A single selectable option inside a {@link DataTableFacet}'s
|
|
117
|
+
/** A single selectable option inside a {@link DataTableFacet}'s `EnumFilter`/`MultiSelectFilter` pill. */
|
|
117
118
|
export type DataTableFacetOption = {
|
|
118
119
|
/** The raw filter value, compared against the column's stringified cell value. */
|
|
119
120
|
value: string
|
|
120
|
-
/** Label shown in the
|
|
121
|
+
/** Label shown in the pill's popover. */
|
|
121
122
|
label: string
|
|
122
123
|
}
|
|
123
124
|
|
|
124
125
|
/**
|
|
125
|
-
* Declares one faceted column filter, rendered as
|
|
126
|
-
* `multiple` is set) inside the toolbar.
|
|
126
|
+
* Declares one faceted column filter, rendered as an `EnumFilter` pill (or `MultiSelectFilter`
|
|
127
|
+
* when `multiple` is set) inside a `FilterSet` in the toolbar (`docs/CONTROLS-SPEC.md` §3).
|
|
127
128
|
*
|
|
128
129
|
* @example
|
|
129
130
|
* const facets: DataTableFacet[] = [
|
|
@@ -135,14 +136,97 @@ export type DataTableFacetOption = {
|
|
|
135
136
|
export type DataTableFacet = {
|
|
136
137
|
/** The TanStack column id — the column's manual `id`, or its `accessorKey` string. */
|
|
137
138
|
columnId: string
|
|
138
|
-
/**
|
|
139
|
+
/** The pill's label — read at rest (single-select) and as the `Filters`/count fallback (multi). */
|
|
139
140
|
label: string
|
|
140
141
|
/** Selectable options for this facet. */
|
|
141
142
|
options: DataTableFacetOption[]
|
|
142
|
-
/** Render a
|
|
143
|
+
/** Render a `MultiSelectFilter` (any-of match) instead of an `EnumFilter` (exact match). @default false */
|
|
143
144
|
multiple?: boolean
|
|
144
145
|
}
|
|
145
146
|
|
|
147
|
+
/**
|
|
148
|
+
* The "no filter" member of a single-select facet's `FieldHandle`. A closed enum field always has
|
|
149
|
+
* a real member as its fallback (C4) — there is no "unset" — so a facet, whose underlying
|
|
150
|
+
* `column.getFilterValue()` genuinely can be `undefined`, needs one synthetic option to stand for
|
|
151
|
+
* that state. Rendered as the enum's first radio; picking it clears the column filter, same as every
|
|
152
|
+
* other value change.
|
|
153
|
+
*
|
|
154
|
+
* Its label is `Any <facet>`, and it used to be a bare `All`. The pill now reads the SELECTED
|
|
155
|
+
* option's label at every value including the fallback (`controls/enum-filter.tsx` — a bar reading
|
|
156
|
+
* `Compare` over a field holding `'previous'` is the bug that law fixes), and a toolbar with three
|
|
157
|
+
* facets would then have read `All` three times. `Any project` is the one label that works in both
|
|
158
|
+
* places at once: it is a legible popover row for "no constraint", and a legible pill readout of the
|
|
159
|
+
* state the filter is actually in. Derived from `facet.label`, so no facet has to declare it.
|
|
160
|
+
*/
|
|
161
|
+
const FACET_ALL_VALUE = '__basalt_facet_all__'
|
|
162
|
+
|
|
163
|
+
/** The synthetic row's label — see {@link FACET_ALL_VALUE}. */
|
|
164
|
+
function facetAllLabel(facet: DataTableFacet): string {
|
|
165
|
+
return `Any ${facet.label.toLowerCase()}`
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Presents a single-select facet column as a `FieldHandle<EnumField<string>>` so it can render
|
|
170
|
+
* through the shared `EnumFilter` pill instead of a hand-rolled `Select` (`basalt/hand-rolled-filter`).
|
|
171
|
+
* `use()` reads/writes `column.getFilterValue()`/`setFilterValue()` directly — no internal
|
|
172
|
+
* subscription needed, since the enclosing `BasaltDataTable` already re-renders on every
|
|
173
|
+
* `columnFilters` change and this handle is rebuilt fresh each render alongside its column.
|
|
174
|
+
*/
|
|
175
|
+
function facetEnumHandle<T>(
|
|
176
|
+
column: Column<T, unknown>,
|
|
177
|
+
facet: DataTableFacet,
|
|
178
|
+
): FieldHandle<EnumField<string>> {
|
|
179
|
+
return {
|
|
180
|
+
kind: 'enum',
|
|
181
|
+
fallback: FACET_ALL_VALUE,
|
|
182
|
+
options: [{ value: FACET_ALL_VALUE, label: facetAllLabel(facet) }, ...facet.options],
|
|
183
|
+
use: () => {
|
|
184
|
+
const current = (column.getFilterValue() as string | undefined) ?? FACET_ALL_VALUE
|
|
185
|
+
return [
|
|
186
|
+
current,
|
|
187
|
+
(next: string) => {
|
|
188
|
+
column.setFilterValue(next === FACET_ALL_VALUE ? undefined : next)
|
|
189
|
+
},
|
|
190
|
+
] as const
|
|
191
|
+
},
|
|
192
|
+
// A facet column has no lane to unset: clearing the column filter IS its fallback state.
|
|
193
|
+
clear: () => {
|
|
194
|
+
column.setFilterValue(undefined)
|
|
195
|
+
},
|
|
196
|
+
isDefault: (value) => value === FACET_ALL_VALUE,
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Presents a multi-select facet column as a `FieldHandle<MultiField<string>>`. Unlike the
|
|
202
|
+
* single-select case, `MultiField`'s own fallback — an empty selection — already means "no
|
|
203
|
+
* constraint", so no synthetic option is needed here.
|
|
204
|
+
*/
|
|
205
|
+
function facetMultiHandle<T>(
|
|
206
|
+
column: Column<T, unknown>,
|
|
207
|
+
facet: DataTableFacet,
|
|
208
|
+
): FieldHandle<MultiField<string>> {
|
|
209
|
+
return {
|
|
210
|
+
kind: 'multi',
|
|
211
|
+
fallback: [],
|
|
212
|
+
options: facet.options,
|
|
213
|
+
use: () => {
|
|
214
|
+
const current = (column.getFilterValue() as readonly string[] | undefined) ?? []
|
|
215
|
+
return [
|
|
216
|
+
current,
|
|
217
|
+
(next: readonly string[]) => {
|
|
218
|
+
column.setFilterValue(next.length > 0 ? [...next] : undefined)
|
|
219
|
+
},
|
|
220
|
+
] as const
|
|
221
|
+
},
|
|
222
|
+
// Same as the single-select facet: an empty column filter is this handle's fallback.
|
|
223
|
+
clear: () => {
|
|
224
|
+
column.setFilterValue(undefined)
|
|
225
|
+
},
|
|
226
|
+
isDefault: (value) => value.length === 0,
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
146
230
|
// ── Props ─────────────────────────────────────────────────────────────────────
|
|
147
231
|
|
|
148
232
|
/**
|
|
@@ -159,6 +243,19 @@ export type DataTableFacet = {
|
|
|
159
243
|
* }
|
|
160
244
|
*/
|
|
161
245
|
export type BasaltDataTableProps<T> = {
|
|
246
|
+
// ── Header (WidgetHeader, docs/CONTROLS-SPEC.md §2.2) ──────────────────────────
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Optional heading rendered above the toolbar via `WidgetHeader tier="widget"`. `count` always
|
|
250
|
+
* reads `table.getRowCount()` (C11) — never a raw `data.length` — so it tracks the row model
|
|
251
|
+
* (post-filter/-pagination) rather than the unfiltered input.
|
|
252
|
+
*/
|
|
253
|
+
title?: string
|
|
254
|
+
/** Optional leading icon, forwarded to `WidgetHeader`. */
|
|
255
|
+
icon?: ReactNode
|
|
256
|
+
/** Optional muted line rendered below the title row. */
|
|
257
|
+
subtitle?: string
|
|
258
|
+
|
|
162
259
|
/** Row data array. */
|
|
163
260
|
data: T[]
|
|
164
261
|
/**
|
|
@@ -262,9 +359,9 @@ export type BasaltDataTableProps<T> = {
|
|
|
262
359
|
/** Called whenever the internal global filter value changes. */
|
|
263
360
|
onGlobalFilterChange?: (value: string) => void
|
|
264
361
|
/**
|
|
265
|
-
* Faceted column filters, rendered in the toolbar as
|
|
266
|
-
* to TanStack's per-column `columnFilters` state. The toolbar
|
|
267
|
-
* non-empty, `enableGlobalFilter` is set, or `
|
|
362
|
+
* Faceted column filters, rendered in the toolbar as `EnumFilter`/`MultiSelectFilter` pills
|
|
363
|
+
* inside a `FilterSet`, wired to TanStack's per-column `columnFilters` state. The toolbar
|
|
364
|
+
* renders whenever this array is non-empty, `enableGlobalFilter` is set, or `actions` is passed.
|
|
268
365
|
* @example
|
|
269
366
|
* facets={[{ columnId: 'department', label: 'Department', options: departmentOptions }]}
|
|
270
367
|
*/
|
|
@@ -283,9 +380,10 @@ export type BasaltDataTableProps<T> = {
|
|
|
283
380
|
manualFiltering?: boolean
|
|
284
381
|
/**
|
|
285
382
|
* Right-aligned toolbar slot (e.g. an "Export" button). Renders the toolbar row even when no
|
|
286
|
-
* search input or facets are configured.
|
|
383
|
+
* search input or facets are configured. Renamed from `toolbarActions` — the toolbar (search +
|
|
384
|
+
* facets + this slot) is wrapped in `CtlSlot` (C1/C5), so its controls resolve to the `ctl` tier.
|
|
287
385
|
*/
|
|
288
|
-
|
|
386
|
+
actions?: ReactNode
|
|
289
387
|
|
|
290
388
|
// ── Pagination ────────────────────────────────────────────────────────────────
|
|
291
389
|
|
|
@@ -389,9 +487,20 @@ export type BasaltDataTableProps<T> = {
|
|
|
389
487
|
/** Row separators. Forwarded to Mantine `Table`. @default true (Mantine's own default) */
|
|
390
488
|
withRowBorders?: boolean
|
|
391
489
|
/**
|
|
392
|
-
* Outer table border
|
|
393
|
-
*
|
|
394
|
-
*
|
|
490
|
+
* Outer table border — a full box around the table.
|
|
491
|
+
*
|
|
492
|
+
* **`false` by default since this minor** (it was `true`). Three separate faults, all visible on
|
|
493
|
+
* the playground's `Controls (mobile)` page at 390px: its TOP edge sat directly under the table's
|
|
494
|
+
* own `WidgetHeader`, separating a header from its own content; its BOTTOM edge landed on the last
|
|
495
|
+
* row's own hairline, two rules at zero distance; and its left/right edges carried no information
|
|
496
|
+
* at all on a table that fills the page (`docs/DESIGN-SPEC.md` §8 — a border is a layout divider,
|
|
497
|
+
* and there is nothing here to divide). The head-row rule and the between-row rules stay, so the
|
|
498
|
+
* table still reads as a table.
|
|
499
|
+
*
|
|
500
|
+
* Pass `true` for a table that genuinely needs a frame — a small table floating in whitespace
|
|
501
|
+
* beside other content, where the box IS the grouping.
|
|
502
|
+
*
|
|
503
|
+
* @default false
|
|
395
504
|
*/
|
|
396
505
|
withTableBorder?: boolean
|
|
397
506
|
}
|
|
@@ -428,6 +537,23 @@ const RANGE_LABEL_STYLE: CSSProperties = {
|
|
|
428
537
|
|
|
429
538
|
const DEFAULT_PAGE_SIZE_OPTIONS = [10, 25, 50, 100]
|
|
430
539
|
|
|
540
|
+
/**
|
|
541
|
+
* The header row's two halves. The lead SHRINKS and the toolbar does not — a title can ellipsize, a
|
|
542
|
+
* 220px search field with a facet pill beside it cannot, and when both were shrinkable flex split
|
|
543
|
+
* the overflow between them and clipped the search's placeholder mid-word.
|
|
544
|
+
*/
|
|
545
|
+
const TABLE_HEADER_LEAD_STYLE: CSSProperties = { flex: '1 1 auto', minWidth: 0 }
|
|
546
|
+
const TABLE_TOOLBAR_STYLE: CSSProperties = { flex: '0 0 auto' }
|
|
547
|
+
/**
|
|
548
|
+
* The toolbar search's width. Mantine's Input grows to its container, which in a `justify:
|
|
549
|
+
* space-between` row means "whatever is left" — so the field was 600px on a wide table and 180px on a
|
|
550
|
+
* narrow one, for the same one-word query. A stated width also makes the toolbar's own minimum width
|
|
551
|
+
* knowable, which is what lets it wrap under the title below `sm` with no media query.
|
|
552
|
+
*/
|
|
553
|
+
const SEARCH_WIDTH = 220
|
|
554
|
+
/** The rows-per-page Select's width — see `SEARCH_WIDTH` for why a toolbar field states one. */
|
|
555
|
+
const PAGE_SIZE_WIDTH = 116
|
|
556
|
+
|
|
431
557
|
// ── Column pinning helpers ────────────────────────────────────────────────────
|
|
432
558
|
|
|
433
559
|
// Merges the left/center/right header-group triad TanStack exposes for pinning into the single
|
|
@@ -597,6 +723,9 @@ function enforceManualPaginationContract(breaches: ManualPaginationBreach[]): vo
|
|
|
597
723
|
* />
|
|
598
724
|
*/
|
|
599
725
|
export function BasaltDataTable<T>({
|
|
726
|
+
title,
|
|
727
|
+
icon,
|
|
728
|
+
subtitle,
|
|
600
729
|
data,
|
|
601
730
|
columns,
|
|
602
731
|
enableSorting = true,
|
|
@@ -616,7 +745,7 @@ export function BasaltDataTable<T>({
|
|
|
616
745
|
facets,
|
|
617
746
|
onColumnFiltersChange,
|
|
618
747
|
manualFiltering = false,
|
|
619
|
-
|
|
748
|
+
actions,
|
|
620
749
|
enablePagination = false,
|
|
621
750
|
pageSizeOptions = DEFAULT_PAGE_SIZE_OPTIONS,
|
|
622
751
|
initialPagination,
|
|
@@ -633,7 +762,7 @@ export function BasaltDataTable<T>({
|
|
|
633
762
|
verticalSpacing,
|
|
634
763
|
horizontalSpacing,
|
|
635
764
|
withRowBorders,
|
|
636
|
-
withTableBorder =
|
|
765
|
+
withTableBorder = false,
|
|
637
766
|
}: BasaltDataTableProps<T>) {
|
|
638
767
|
const [sorting, setSorting] = useState<SortingState>(initialSorting ?? [])
|
|
639
768
|
const [globalFilter, setGlobalFilter] = useState(initialGlobalFilter ?? '')
|
|
@@ -773,7 +902,7 @@ export function BasaltDataTable<T>({
|
|
|
773
902
|
|
|
774
903
|
const showSearch = enableGlobalFilter && filteringEnabled
|
|
775
904
|
const showFacets = hasFacets && filteringEnabled
|
|
776
|
-
const showToolbar = showSearch || showFacets || Boolean(
|
|
905
|
+
const showToolbar = showSearch || showFacets || Boolean(actions)
|
|
777
906
|
const headerGroups = enablePinning ? getOrderedHeaderGroups(table) : table.getHeaderGroups()
|
|
778
907
|
// The rows actually rendered, not `data` — a filter or a page index that matches nothing leaves
|
|
779
908
|
// `data` non-empty while the body has nothing in it, and a blank body reads as a broken table.
|
|
@@ -906,63 +1035,81 @@ export function BasaltDataTable<T>({
|
|
|
906
1035
|
const scrolls = maxHeight !== undefined || minWidth !== undefined
|
|
907
1036
|
|
|
908
1037
|
const paginationState = table.getState().pagination
|
|
1038
|
+
// The CURRENT page size is always an option, even when it is not in `pageSizeOptions`. Mantine's
|
|
1039
|
+
// Select renders EMPTY when its `value` matches no row, so a table opened at
|
|
1040
|
+
// `initialPagination.pageSize: 5` against the default `[10, 25, 50, 100]` showed a blank
|
|
1041
|
+
// rows-per-page box — a control stating nothing, next to a range label stating `1–5`.
|
|
1042
|
+
const pageSizeRows = [...new Set([...pageSizeOptions, paginationState.pageSize])]
|
|
1043
|
+
.sort((a, b) => a - b)
|
|
1044
|
+
.map((size) => ({ value: String(size), label: `${size} / page` }))
|
|
909
1045
|
const total = table.getRowCount()
|
|
910
1046
|
const rangeStart = total === 0 ? 0 : paginationState.pageIndex * paginationState.pageSize + 1
|
|
911
1047
|
const rangeEnd = Math.min((paginationState.pageIndex + 1) * paginationState.pageSize, total)
|
|
912
1048
|
|
|
913
1049
|
return (
|
|
914
1050
|
<>
|
|
915
|
-
{
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
1051
|
+
{/*
|
|
1052
|
+
* ONE header row: the `WidgetHeader` (title · count) on the left, the toolbar right-aligned in
|
|
1053
|
+
* the SAME row. It was two stacked rows with `mb="xs"` on each, so a titled table with search
|
|
1054
|
+
* spent title → 11px → search → 11px → thead before a single datum appeared, and the toolbar
|
|
1055
|
+
* read as page furniture rather than as this table's controls.
|
|
1056
|
+
*
|
|
1057
|
+
* `wrap="wrap"` is the below-`sm` behaviour and needs no media query: the toolbar's minimum
|
|
1058
|
+
* width (a 220px search plus its pills) exceeds what is left beside a title on a phone, so flex
|
|
1059
|
+
* wraps it under the title on its own. `align="center"` puts the 30px toolbar controls on the
|
|
1060
|
+
* title's optical line rather than on its baseline.
|
|
1061
|
+
*/}
|
|
1062
|
+
{(title !== undefined || showToolbar) && (
|
|
1063
|
+
<Group justify="space-between" align="center" wrap="wrap" gap="xs" mb="xs">
|
|
1064
|
+
{title !== undefined ? (
|
|
1065
|
+
<Box style={TABLE_HEADER_LEAD_STYLE}>
|
|
1066
|
+
<WidgetHeader
|
|
1067
|
+
tier="widget"
|
|
1068
|
+
title={title}
|
|
1069
|
+
{...(icon !== undefined && { icon })}
|
|
1070
|
+
{...(subtitle !== undefined && { subtitle })}
|
|
1071
|
+
count={table.getRowCount()}
|
|
927
1072
|
/>
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
return (
|
|
936
|
-
<MultiSelect
|
|
937
|
-
key={facet.columnId}
|
|
938
|
-
size="xs"
|
|
939
|
-
radius="md"
|
|
940
|
-
placeholder={facet.label}
|
|
941
|
-
data={facet.options}
|
|
942
|
-
value={value}
|
|
943
|
-
onChange={(next) => column.setFilterValue(next.length > 0 ? next : undefined)}
|
|
944
|
-
clearable
|
|
945
|
-
w={200}
|
|
946
|
-
/>
|
|
947
|
-
)
|
|
948
|
-
}
|
|
949
|
-
const value = (column.getFilterValue() as string | undefined) ?? null
|
|
950
|
-
return (
|
|
951
|
-
<Select
|
|
952
|
-
key={facet.columnId}
|
|
953
|
-
size="xs"
|
|
1073
|
+
</Box>
|
|
1074
|
+
) : null}
|
|
1075
|
+
{showToolbar && (
|
|
1076
|
+
<CtlSlot>
|
|
1077
|
+
<Group gap="xs" wrap="wrap" align="center" style={TABLE_TOOLBAR_STYLE}>
|
|
1078
|
+
{showSearch && (
|
|
1079
|
+
<TextInput
|
|
954
1080
|
radius="md"
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
w={180}
|
|
1081
|
+
w={SEARCH_WIDTH}
|
|
1082
|
+
placeholder={globalFilterPlaceholder}
|
|
1083
|
+
leftSection={searchIcon}
|
|
1084
|
+
value={globalFilter}
|
|
1085
|
+
onChange={(event) => handleGlobalFilterChange(event.currentTarget.value)}
|
|
961
1086
|
/>
|
|
962
|
-
)
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
1087
|
+
)}
|
|
1088
|
+
{showFacets && (
|
|
1089
|
+
<FilterSet>
|
|
1090
|
+
{facets?.map((facet) => {
|
|
1091
|
+
const column = table.getColumn(facet.columnId)
|
|
1092
|
+
if (!column) return null
|
|
1093
|
+
return facet.multiple ? (
|
|
1094
|
+
<MultiSelectFilter
|
|
1095
|
+
key={facet.columnId}
|
|
1096
|
+
field={facetMultiHandle(column, facet)}
|
|
1097
|
+
label={facet.label}
|
|
1098
|
+
/>
|
|
1099
|
+
) : (
|
|
1100
|
+
<EnumFilter
|
|
1101
|
+
key={facet.columnId}
|
|
1102
|
+
field={facetEnumHandle(column, facet)}
|
|
1103
|
+
label={facet.label}
|
|
1104
|
+
/>
|
|
1105
|
+
)
|
|
1106
|
+
})}
|
|
1107
|
+
</FilterSet>
|
|
1108
|
+
)}
|
|
1109
|
+
{actions}
|
|
1110
|
+
</Group>
|
|
1111
|
+
</CtlSlot>
|
|
1112
|
+
)}
|
|
966
1113
|
</Group>
|
|
967
1114
|
)}
|
|
968
1115
|
{scrolls ? (
|
|
@@ -986,16 +1133,13 @@ export function BasaltDataTable<T>({
|
|
|
986
1133
|
</Text>
|
|
987
1134
|
<Group gap="xs" align="center">
|
|
988
1135
|
<Select
|
|
989
|
-
size="
|
|
1136
|
+
size="ctl"
|
|
990
1137
|
radius="md"
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
label: `${size} / page`,
|
|
994
|
-
}))}
|
|
1138
|
+
w={PAGE_SIZE_WIDTH}
|
|
1139
|
+
data={pageSizeRows}
|
|
995
1140
|
value={String(paginationState.pageSize)}
|
|
996
1141
|
onChange={(value) => value && table.setPageSize(Number(value))}
|
|
997
1142
|
allowDeselect={false}
|
|
998
|
-
w={110}
|
|
999
1143
|
/>
|
|
1000
1144
|
<Pagination
|
|
1001
1145
|
size="sm"
|