basalt-ui 1.24.0 → 1.26.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 +25 -0
- package/MIGRATING.md +547 -21
- package/README.md +46 -33
- package/agent/rules/basalt-batteries.md +205 -0
- package/agent/rules/basalt-charts.md +125 -555
- package/agent/rules/basalt-controls.md +155 -0
- package/agent/rules/basalt-mantine.md +146 -439
- package/agent/rules/basalt-state.md +113 -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 +1275 -31
- package/configs/oxlint-plugin.test.ts +947 -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 +30 -0
- package/dist/controls/enum-filter.d.ts.map +1 -0
- package/dist/controls/enum-filter.js +91 -0
- package/dist/controls/filter-context.d.ts +55 -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 +19 -0
- package/dist/controls/index.d.ts.map +1 -0
- package/dist/controls/index.js +44 -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/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 +29 -0
- package/dist/controls/range-filter.d.ts.map +1 -0
- package/dist/controls/range-filter.js +120 -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/query-state.d.ts +1 -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 +44 -9
- package/dist/dashboard/stat-card.d.ts.map +1 -1
- package/dist/dashboard/stat-card.js +80 -48
- package/dist/dashboard/stat-card.module.css +82 -0
- package/dist/dashboard/stat-card.module.css.d.ts +11 -0
- package/dist/data/data-table.d.ts +102 -20
- package/dist/data/data-table.d.ts.map +1 -1
- package/dist/data/data-table.js +166 -65
- package/dist/data/table.d.ts +1 -1
- package/dist/data/table.d.ts.map +1 -1
- 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 +82 -7
- package/dist/guard/types.d.ts +3 -3
- package/dist/guard/types.d.ts.map +1 -1
- package/dist/index.d.ts +12 -2
- 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 +81 -0
- package/dist/router-tanstack/search-store.d.ts.map +1 -0
- package/dist/router-tanstack/search-store.js +187 -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 +392 -0
- package/dist/state/fields.d.ts.map +1 -0
- package/dist/state/fields.js +369 -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 +48 -0
- package/dist/state/persisted.d.ts.map +1 -0
- package/dist/state/persisted.js +105 -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 +155 -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 +37 -0
- package/dist/widget-header/widget-header.d.ts.map +1 -0
- package/dist/widget-header/widget-header.js +77 -0
- package/dist/widget-header/widget-header.module.css +335 -0
- package/dist/widget-header/widget-header.module.css.d.ts +24 -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 +637 -0
- package/src/controls/enum-filter.tsx +159 -0
- package/src/controls/filter-context.tsx +153 -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 +48 -0
- package/src/controls/multi-select-filter.tsx +140 -0
- package/src/controls/peer-boundary.test.ts +85 -0
- package/src/controls/props-contract.test.tsx +106 -0
- package/src/controls/range-filter.tsx +184 -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/query-state.tsx +1 -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 +82 -0
- package/src/dashboard/stat-card.module.css.d.ts +11 -0
- package/src/dashboard/stat-card.test.tsx +67 -1
- package/src/dashboard/stat-card.tsx +209 -68
- package/src/data/data-table.test.tsx +282 -6
- package/src/data/data-table.tsx +429 -94
- package/src/data/table.ts +2 -0
- package/src/guard/check-source.test.ts +126 -13
- package/src/guard/grace.test.ts +149 -0
- package/src/guard/index.ts +172 -29
- package/src/guard/types.ts +4 -2
- package/src/index.ts +46 -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 +31 -0
- package/src/router-tanstack/index.ts +24 -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 +661 -0
- package/src/router-tanstack/search-store.test.ts +418 -0
- package/src/router-tanstack/search-store.ts +380 -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 +258 -0
- package/src/state/fields.ts +892 -0
- package/src/state/persisted.ts +211 -0
- package/src/state.ts +46 -240
- package/src/styles.css +13 -0
- package/src/surfaces.ts +203 -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 +335 -0
- package/src/widget-header/widget-header.module.css.d.ts +24 -0
- package/src/widget-header/widget-header.test.tsx +187 -0
- package/src/widget-header/widget-header.tsx +168 -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 -269
- 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
|
@@ -1,52 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* createMultiSearchParamStore — the multi-select sibling of `createSearchParamStore`, for search
|
|
3
|
-
* params backed by an ANY-OF set (e.g. a tag filter) instead of a single value (e.g. a tab).
|
|
4
|
-
*
|
|
5
|
-
* Same three-concern factory shape as `createSearchParamStore`:
|
|
6
|
-
* 1. `validateSearch` — pass directly to `createFileRoute({ validateSearch })`.
|
|
7
|
-
* Falls back to localStorage when the URL param is absent or invalid, then to `fallback`.
|
|
8
|
-
* 2. `useStore` — React hook: `const [values, persist] = store.useStore()`.
|
|
9
|
-
* Call `persist(next)` alongside `navigate` so the selection survives navigation.
|
|
10
|
-
* 3. `readStored` — plain function for non-React contexts (tests, guards).
|
|
11
|
-
* 4. `linkSearch` — the click-time `search:` thunk for a nav link, ready-made.
|
|
12
|
-
*
|
|
13
|
-
* Headless — no Mantine, no JSX. Same tier as `createSearchParamStore`.
|
|
14
|
-
*
|
|
15
|
-
* ## Encoding — array-native, not CSV
|
|
16
|
-
*
|
|
17
|
-
* TanStack Router's default search serialization is `stringifySearchWith(JSON.stringify,
|
|
18
|
-
* JSON.parse)`, and its `stringifyValue` branches on `typeof val === 'object' && val !== null` —
|
|
19
|
-
* an array is an object, so `{ tags: ['a', 'b'] }` serializes to `?tags=%5B%22a%22%2C%22b%22%5D`
|
|
20
|
-
* and `parseSearchWith(JSON.parse)` reverses it losslessly. This store deals entirely in arrays
|
|
21
|
-
* (what `validateSearch` returns is exactly what the router stringifies), so a CSV encoding is not
|
|
22
|
-
* reachable from here — there is no string-building step to intercept. A consumer who wants
|
|
23
|
-
* prettier URLs (e.g. `?tags=a,b`) configures router-global `parseSearch`/`stringifySearch` (see
|
|
24
|
-
* TanStack Router's documented custom-search-param-serialization recipe); this store keeps working
|
|
25
|
-
* untouched either way, because it hands the router an array, not an encoding.
|
|
26
|
-
*
|
|
27
|
-
* ## Decoding — defensive and canonical
|
|
28
|
-
*
|
|
29
|
-
* Any value pulled from the URL or localStorage is normalized in this order:
|
|
30
|
-
* 1. Accept only `Array.isArray` input — anything else decodes to empty.
|
|
31
|
-
* 2. Keep only entries present in `opts.values` (drops tampered values and values dropped from the
|
|
32
|
-
* vocabulary since the URL/localStorage entry was written).
|
|
33
|
-
* 3. Dedupe.
|
|
34
|
-
* 4. Re-sort into `opts.values` DECLARATION order.
|
|
35
|
-
*
|
|
36
|
-
* Canonical ordering means `['api', 'design']` and `['design', 'api']` normalize to the SAME
|
|
37
|
-
* array — one URL for one logical selection, so history entries and any loader cache keyed on the
|
|
38
|
-
* search stay stable regardless of the order a user toggled filters in.
|
|
39
|
-
*
|
|
40
|
-
* @example
|
|
41
|
-
* export const articleTags = createMultiSearchParamStore({
|
|
42
|
-
* key: 'article-tags', param: 'tags',
|
|
43
|
-
* values: ['api', 'design', 'guide'] as const,
|
|
44
|
-
* })
|
|
45
|
-
*
|
|
46
|
-
* export const Route = createFileRoute('/content')({
|
|
47
|
-
* validateSearch: articleTags.validateSearch,
|
|
48
|
-
* })
|
|
49
|
-
*/
|
|
50
1
|
export type MultiSearchParamStoreOptions<T extends string, P extends string = string> = {
|
|
51
2
|
/** localStorage key (namespaced `basalt:<key>` automatically). */
|
|
52
3
|
key: string;
|
|
@@ -69,7 +20,7 @@ export type MultiSearchParamStore<T extends string, P extends string = string> =
|
|
|
69
20
|
};
|
|
70
21
|
/**
|
|
71
22
|
* React hook: `const [current, persist] = store.useStore()`.
|
|
72
|
-
*
|
|
23
|
+
* localStorage only — it does NOT read or write the URL.
|
|
73
24
|
*/
|
|
74
25
|
useStore: () => readonly [readonly T[], (next: readonly T[]) => void];
|
|
75
26
|
/** Plain read — for use outside React (tests, guards, fallback reads). */
|
|
@@ -80,12 +31,13 @@ export type MultiSearchParamStore<T extends string, P extends string = string> =
|
|
|
80
31
|
* for why a module-scope literal silently defeats the store.
|
|
81
32
|
*
|
|
82
33
|
* No dev warning rides on this one, unlike the single-value store: an empty array in the URL is
|
|
83
|
-
* indistinguishable from an absent param here
|
|
84
|
-
*
|
|
34
|
+
* indistinguishable from an absent param here, so a link declaring `{ tags: [] }` restores
|
|
35
|
+
* correctly and there is no broken state to detect.
|
|
85
36
|
*/
|
|
86
37
|
linkSearch: () => {
|
|
87
38
|
[K in P]: readonly T[];
|
|
88
39
|
};
|
|
89
40
|
};
|
|
41
|
+
/** @deprecated Use `createSearchStore` + `field.multi`. Removed in 1.29.0. */
|
|
90
42
|
export declare function createMultiSearchParamStore<const T extends string, const P extends string>(opts: MultiSearchParamStoreOptions<T, P>): MultiSearchParamStore<T, P>;
|
|
91
43
|
//# sourceMappingURL=multi-search-param-store.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"multi-search-param-store.d.ts","sourceRoot":"","sources":["../../src/router-tanstack/multi-search-param-store.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"multi-search-param-store.d.ts","sourceRoot":"","sources":["../../src/router-tanstack/multi-search-param-store.ts"],"names":[],"mappings":"AAkCA,MAAM,MAAM,4BAA4B,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI;IACtF,kEAAkE;IAClE,GAAG,EAAE,MAAM,CAAA;IACX,6DAA6D;IAC7D,KAAK,EAAE,CAAC,CAAA;IACR,0FAA0F;IAC1F,MAAM,EAAE,SAAS,CAAC,EAAE,CAAA;IACpB,6FAA6F;IAC7F,QAAQ,CAAC,EAAE,SAAS,CAAC,EAAE,CAAA;IACvB,kFAAkF;IAClF,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,qBAAqB,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI;IAC/E;;;OAGG;IACH,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK;SAAG,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,EAAE;KAAE,CAAA;IAC/E;;;OAGG;IACH,QAAQ,EAAE,MAAM,SAAS,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,KAAK,IAAI,CAAC,CAAA;IACrE,0EAA0E;IAC1E,UAAU,EAAE,MAAM,SAAS,CAAC,EAAE,GAAG,IAAI,CAAA;IACrC;;;;;;;;OAQG;IACH,UAAU,EAAE,MAAM;SAAG,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,EAAE;KAAE,CAAA;CAC7C,CAAA;AAID,8EAA8E;AAC9E,wBAAgB,2BAA2B,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,CAAC,CAAC,SAAS,MAAM,EACxF,IAAI,EAAE,4BAA4B,CAAC,CAAC,EAAE,CAAC,CAAC,GACvC,qBAAqB,CAAC,CAAC,EAAE,CAAC,CAAC,CA4B7B"}
|
|
@@ -1,37 +1,29 @@
|
|
|
1
|
-
import { createPersistedState,
|
|
1
|
+
import { createPersistedState, field } from "../state.js";
|
|
2
|
+
import { buildSearchStore } from "./search-store.js";
|
|
2
3
|
function createMultiSearchParamStore(opts) {
|
|
3
4
|
const version = opts.version ?? 1;
|
|
4
5
|
const fallback = opts.fallback ?? [];
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
return opts.values.filter((value) => present.has(value));
|
|
13
|
-
};
|
|
14
|
-
const readStored = () => {
|
|
15
|
-
const raw = readPersistedValue(opts.key, version);
|
|
16
|
-
if (!Array.isArray(raw)) return null;
|
|
17
|
-
return normalize(raw);
|
|
18
|
-
};
|
|
19
|
-
const linkSearch = () => {
|
|
20
|
-
return { [opts.param]: readStored() ?? fallback };
|
|
21
|
-
};
|
|
22
|
-
const validateSearch = (search) => {
|
|
23
|
-
const fromUrl = normalize(search[opts.param]);
|
|
24
|
-
if (fromUrl.length > 0) {
|
|
25
|
-
return { [opts.param]: fromUrl };
|
|
26
|
-
}
|
|
27
|
-
return { [opts.param]: readStored() ?? fallback };
|
|
28
|
-
};
|
|
29
|
-
const useStore = createPersistedState({
|
|
6
|
+
const store = buildSearchStore({
|
|
7
|
+
key: opts.key,
|
|
8
|
+
version,
|
|
9
|
+
fields: { [opts.param]: field.multi(opts.values, fallback) },
|
|
10
|
+
legacyValueField: opts.param
|
|
11
|
+
});
|
|
12
|
+
const persisted = createPersistedState({
|
|
30
13
|
key: opts.key,
|
|
31
14
|
version,
|
|
32
15
|
initial: fallback
|
|
33
16
|
});
|
|
34
|
-
|
|
17
|
+
const useStore = () => {
|
|
18
|
+
store.markReaderWired();
|
|
19
|
+
return persisted();
|
|
20
|
+
};
|
|
21
|
+
return {
|
|
22
|
+
validateSearch: (search) => store.validateSearch(search),
|
|
23
|
+
useStore,
|
|
24
|
+
readStored: () => store.readStored()[opts.param] ?? null,
|
|
25
|
+
linkSearch: () => store.linkSearch()
|
|
26
|
+
};
|
|
35
27
|
}
|
|
36
28
|
export {
|
|
37
29
|
createMultiSearchParamStore
|
|
@@ -1,89 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* createSearchParamStore — bridge between TanStack Router URL search params and
|
|
3
|
-
* basalt-ui's localStorage persistence.
|
|
4
|
-
*
|
|
5
|
-
* Combines three concerns into one factory:
|
|
6
|
-
* 1. `validateSearch` — pass directly to `createFileRoute({ validateSearch })`.
|
|
7
|
-
* Falls back to localStorage when the URL param is absent or invalid.
|
|
8
|
-
* 2. `useStore` — React hook: `const [value, persist] = store.useStore()`.
|
|
9
|
-
* Call `persist(next)` alongside `navigate` so the selection survives
|
|
10
|
-
* navigation away from and back to the route.
|
|
11
|
-
* 3. `readStored` — plain function for non-React contexts (tests, guards).
|
|
12
|
-
* 4. `linkSearch` — the click-time `search:` thunk a nav link needs, ready-made.
|
|
13
|
-
*
|
|
14
|
-
* ## The half that is easy to skip
|
|
15
|
-
*
|
|
16
|
-
* `validateSearch` restores the value when you navigate TO the route with no param. It cannot do
|
|
17
|
-
* anything about a nav link that declares the param itself — and a link written as
|
|
18
|
-
* `search: { range: '30d' }` at module scope pins the fallback on every click, which silently
|
|
19
|
-
* defeats the whole store. The reference consumer shipped exactly that: three features adopted the
|
|
20
|
-
* persistence, the reader had ZERO call sites, and "remember my window" had never once worked.
|
|
21
|
-
*
|
|
22
|
-
* `linkSearch` exists so that failure is unreachable from the API rather than only warned about in
|
|
23
|
-
* this comment — the mistake is made while typing `search:`, so the remedy has to be something
|
|
24
|
-
* autocomplete offers at that keystroke. The JSDoc was already here when it happened.
|
|
25
|
-
*
|
|
26
|
-
* Headless — no Mantine, no JSX. Same tier as `useBasaltNav` and
|
|
27
|
-
* `useRouterBreadcrumbs`.
|
|
28
|
-
*
|
|
29
|
-
* ## Full integration recipe (5 steps)
|
|
30
|
-
*
|
|
31
|
-
* **1. Define** — one call per search param, e.g. in a shared lib/ module:
|
|
32
|
-
*
|
|
33
|
-
* export const dashboardRange = createSearchParamStore({
|
|
34
|
-
* key: 'dashboard-range', param: 'range',
|
|
35
|
-
* values: ['1d', '7d', '30d'] as const, fallback: '30d',
|
|
36
|
-
* })
|
|
37
|
-
*
|
|
38
|
-
* **2. Route** — plug validateSearch into the parent layout route:
|
|
39
|
-
*
|
|
40
|
-
* export const Route = createFileRoute('/dashboard')({
|
|
41
|
-
* validateSearch: dashboardRange.validateSearch,
|
|
42
|
-
* component: DashboardLayout, // renders <DateFilter/> + <Outlet/>
|
|
43
|
-
* })
|
|
44
|
-
*
|
|
45
|
-
* **3. Filter** — a component in the shell header (PageActions portal):
|
|
46
|
-
*
|
|
47
|
-
* function DateFilter() {
|
|
48
|
-
* const { range } = useSearch({ from: '/dashboard' })
|
|
49
|
-
* const [, persist] = dashboardRange.useStore()
|
|
50
|
-
* return <SegmentedControl value={range}
|
|
51
|
-
* onChange={(v) => { persist(v); navigate({ to: '.',
|
|
52
|
-
* search: (prev) => ({ ...prev, range: v }) }) }} />
|
|
53
|
-
* }
|
|
54
|
-
*
|
|
55
|
-
* **4. Page** — accepts the param as a **prop**, NOT from useSearch:
|
|
56
|
-
*
|
|
57
|
-
* // CRITICAL: never call useSearch({ from: '/dashboard' }) in a page
|
|
58
|
-
* // component that renders on a sibling route (e.g. /activity).
|
|
59
|
-
* // Sibling routes aren't children — the `from` fails.
|
|
60
|
-
* function DashboardPage({ range = '30d' }: { range?: DateRange }) {
|
|
61
|
-
* const data = useMemo(() => generateData(range), [range])
|
|
62
|
-
* return <Charts data={data} range={range} />
|
|
63
|
-
* }
|
|
64
|
-
*
|
|
65
|
-
* **5. Nav links** — carry the param across sub-pages, set per destination in
|
|
66
|
-
* the nav definition so only the dashboard sub-tree inherits it and every
|
|
67
|
-
* other link stays clean. Pass `linkSearch` BY REFERENCE — it is the click-time thunk:
|
|
68
|
-
*
|
|
69
|
-
* navGroup({ id: 'dash', label: 'Dashboard' }, [
|
|
70
|
-
* { id: 'dash-overview', label: 'Overview', icon: <IconHome />,
|
|
71
|
-
* link: linkOptions({ to: '/dashboard', search: dashboardRange.linkSearch }) },
|
|
72
|
-
* { id: 'dash-activity', label: 'Activity', icon: <IconPulse />,
|
|
73
|
-
* link: linkOptions({ to: '/dashboard/activity', search: dashboardRange.linkSearch }) },
|
|
74
|
-
* ])
|
|
75
|
-
*
|
|
76
|
-
* `linkSearch` IS that thunk (`() => ({ [param]: readStored() ?? fallback })`) — hand-rolling it
|
|
77
|
-
* over `readStored` still works and is what you need when the link also carries other params.
|
|
78
|
-
*
|
|
79
|
-
* NOT `search: true`. That flag means "keep the current search" and TanStack
|
|
80
|
-
* only offers it where the target's search is OPTIONAL — a route wired to a
|
|
81
|
-
* store's `validateSearch` always returns the param, so the router requires a
|
|
82
|
-
* value and `search: true` is a type error. The thunk is also the better
|
|
83
|
-
* behaviour: `<Link>` re-evaluates it at click time, so arriving from OUTSIDE
|
|
84
|
-
* the sub-tree restores the last selection instead of landing on the factory
|
|
85
|
-
* default, and a definition evaluated once at module scope never goes stale.
|
|
86
|
-
*/
|
|
87
1
|
export type SearchParamStoreOptions<T extends string, P extends string = string> = {
|
|
88
2
|
/** localStorage key (namespaced `basalt:<key>` automatically). */
|
|
89
3
|
key: string;
|
|
@@ -106,7 +20,8 @@ export type SearchParamStore<T extends string, P extends string = string> = {
|
|
|
106
20
|
};
|
|
107
21
|
/**
|
|
108
22
|
* React hook: `const [current, persist] = store.useStore()`.
|
|
109
|
-
*
|
|
23
|
+
* localStorage only — it does NOT read or write the URL. `createSearchStore`'s
|
|
24
|
+
* `field.<name>.use()` is the replacement that does both.
|
|
110
25
|
*/
|
|
111
26
|
useStore: () => readonly [T, (next: T) => void];
|
|
112
27
|
/** Plain read — for use outside React (tests, guards, fallback reads). */
|
|
@@ -122,5 +37,6 @@ export type SearchParamStore<T extends string, P extends string = string> = {
|
|
|
122
37
|
[K in P]: T;
|
|
123
38
|
};
|
|
124
39
|
};
|
|
40
|
+
/** @deprecated Use `createSearchStore` + `field.enum`. Removed in 1.29.0. */
|
|
125
41
|
export declare function createSearchParamStore<const T extends string, const P extends string>(opts: SearchParamStoreOptions<T, P>): SearchParamStore<T, P>;
|
|
126
42
|
//# sourceMappingURL=search-param-store.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-param-store.d.ts","sourceRoot":"","sources":["../../src/router-tanstack/search-param-store.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"search-param-store.d.ts","sourceRoot":"","sources":["../../src/router-tanstack/search-param-store.ts"],"names":[],"mappings":"AAiCA,MAAM,MAAM,uBAAuB,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI;IACjF,kEAAkE;IAClE,GAAG,EAAE,MAAM,CAAA;IACX,mEAAmE;IACnE,KAAK,EAAE,CAAC,CAAA;IACR,2DAA2D;IAC3D,MAAM,EAAE,SAAS,CAAC,EAAE,CAAA;IACpB,kEAAkE;IAClE,QAAQ,EAAE,CAAC,CAAA;IACX,kFAAkF;IAClF,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI;IAC1E;;;OAGG;IACH,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK;SAAG,CAAC,IAAI,CAAC,GAAG,CAAC;KAAE,CAAA;IACpE;;;;OAIG;IACH,QAAQ,EAAE,MAAM,SAAS,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,IAAI,CAAC,CAAA;IAC/C,0EAA0E;IAC1E,UAAU,EAAE,MAAM,CAAC,GAAG,IAAI,CAAA;IAC1B;;;;;;OAMG;IACH,UAAU,EAAE,MAAM;SAAG,CAAC,IAAI,CAAC,GAAG,CAAC;KAAE,CAAA;CAClC,CAAA;AAID,6EAA6E;AAC7E,wBAAgB,sBAAsB,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,CAAC,CAAC,SAAS,MAAM,EACnF,IAAI,EAAE,uBAAuB,CAAC,CAAC,EAAE,CAAC,CAAC,GAClC,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,CAwBxB"}
|
|
@@ -1,53 +1,24 @@
|
|
|
1
|
-
import { createPersistedState,
|
|
2
|
-
|
|
3
|
-
const { key, param, urlValue, storedValue } = input;
|
|
4
|
-
console.warn(
|
|
5
|
-
`[basalt-ui] createSearchParamStore('${key}'): the URL pinned \`${param}=${urlValue}\` (the fallback) while '${storedValue}' was persisted, and nothing has read this store back. A nav link is almost certainly declaring \`search: { ${param}: '${urlValue}' }\` at module scope, which overrides the stored value on every click \u2014 pass the store's own reader instead: \`search: <store>.linkSearch\`. (dev only)`
|
|
6
|
-
);
|
|
7
|
-
}
|
|
1
|
+
import { createPersistedState, field } from "../state.js";
|
|
2
|
+
import { buildSearchStore } from "./search-store.js";
|
|
8
3
|
function createSearchParamStore(opts) {
|
|
9
4
|
const version = opts.version ?? 1;
|
|
10
|
-
|
|
11
|
-
let warned = false;
|
|
12
|
-
const read = () => {
|
|
13
|
-
const raw = readPersistedValue(opts.key, version);
|
|
14
|
-
if (typeof raw !== "string") return null;
|
|
15
|
-
if (opts.values.includes(raw)) return raw;
|
|
16
|
-
return null;
|
|
17
|
-
};
|
|
18
|
-
const readStored = () => {
|
|
19
|
-
readerWired = true;
|
|
20
|
-
return read();
|
|
21
|
-
};
|
|
22
|
-
const linkSearch = () => {
|
|
23
|
-
readerWired = true;
|
|
24
|
-
return { [opts.param]: read() ?? opts.fallback };
|
|
25
|
-
};
|
|
26
|
-
const validateSearch = (search) => {
|
|
27
|
-
const raw = search[opts.param];
|
|
28
|
-
if (typeof raw === "string" && opts.values.includes(raw)) {
|
|
29
|
-
if (!warned && !readerWired && raw === opts.fallback && process.env["NODE_ENV"] !== "production") {
|
|
30
|
-
const stored = read();
|
|
31
|
-
if (stored !== null && stored !== raw) {
|
|
32
|
-
warned = true;
|
|
33
|
-
warnLinkPinsFallback({
|
|
34
|
-
key: opts.key,
|
|
35
|
-
param: opts.param,
|
|
36
|
-
urlValue: raw,
|
|
37
|
-
storedValue: stored
|
|
38
|
-
});
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
return { [opts.param]: raw };
|
|
42
|
-
}
|
|
43
|
-
return { [opts.param]: read() ?? opts.fallback };
|
|
44
|
-
};
|
|
45
|
-
const useStore = createPersistedState({
|
|
5
|
+
const store = buildSearchStore({
|
|
46
6
|
key: opts.key,
|
|
47
7
|
version,
|
|
48
|
-
|
|
8
|
+
fields: { [opts.param]: field.enum(opts.values, opts.fallback) },
|
|
9
|
+
legacyValueField: opts.param
|
|
49
10
|
});
|
|
50
|
-
|
|
11
|
+
const persisted = createPersistedState({ key: opts.key, version, initial: opts.fallback });
|
|
12
|
+
const useStore = () => {
|
|
13
|
+
store.markReaderWired();
|
|
14
|
+
return persisted();
|
|
15
|
+
};
|
|
16
|
+
return {
|
|
17
|
+
validateSearch: (search) => store.validateSearch(search),
|
|
18
|
+
useStore,
|
|
19
|
+
readStored: () => store.readStored()[opts.param] ?? null,
|
|
20
|
+
linkSearch: () => store.linkSearch()
|
|
21
|
+
};
|
|
51
22
|
}
|
|
52
23
|
export {
|
|
53
24
|
createSearchParamStore
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { AnyField, FieldHandle, SearchValues, StoredValues } from '../state.js';
|
|
2
|
+
export type CreateSearchStoreOptions<S extends Record<string, AnyField>> = {
|
|
3
|
+
/** localStorage key (namespaced `basalt:<key>` automatically). One entry per store. */
|
|
4
|
+
key: string;
|
|
5
|
+
/** The fields, built with `field.*`. The key of each is its default URL param name. */
|
|
6
|
+
fields: S;
|
|
7
|
+
/** Envelope version — bump when the field set changes to discard stale localStorage. */
|
|
8
|
+
version?: number;
|
|
9
|
+
};
|
|
10
|
+
export type SearchStore<S extends Record<string, AnyField>> = {
|
|
11
|
+
/**
|
|
12
|
+
* Pass directly to `createFileRoute({ validateSearch })`. Returns every URL-lane param, resolved
|
|
13
|
+
* URL ⊳ localStorage ⊳ fallback — a route wired to it therefore always has the params, which is
|
|
14
|
+
* what makes `use()`'s "does this route own the field" check trivial and exact.
|
|
15
|
+
*/
|
|
16
|
+
validateSearch: (raw: Record<string, unknown>) => SearchValues<S>;
|
|
17
|
+
/**
|
|
18
|
+
* The click-time `search:` value for a nav link. Pass it BY REFERENCE
|
|
19
|
+
* (`search: store.linkSearch`) inside `defineNav` — never a literal object, which pins the
|
|
20
|
+
* fallback on every click and is why one consumer's reader had zero call sites (C10, A2).
|
|
21
|
+
*/
|
|
22
|
+
linkSearch: () => SearchValues<S>;
|
|
23
|
+
/** Plain read for non-React contexts (a redirect, a loader, a guard, a test). */
|
|
24
|
+
readStored: () => Partial<StoredValues<S>>;
|
|
25
|
+
/** The per-field handles every basalt control takes instead of `value`/`onChange` (C2). */
|
|
26
|
+
field: {
|
|
27
|
+
[K in keyof S]: FieldHandle<S[K]>;
|
|
28
|
+
};
|
|
29
|
+
/** Option labels for enum / multi / range fields. Chainable — call it once, at definition. */
|
|
30
|
+
labels: (map: Partial<{
|
|
31
|
+
[K in keyof S]: Record<string, string>;
|
|
32
|
+
}>) => SearchStore<S>;
|
|
33
|
+
/** Every URL-lane param, resolved — the object a page hands to its query. */
|
|
34
|
+
useValues: () => SearchValues<S>;
|
|
35
|
+
/** How many fields differ from their fallback — the `n` in a `Filters (n)` pill. */
|
|
36
|
+
useActiveCount: () => number;
|
|
37
|
+
/** Resets every field to its fallback: one navigate, one storage write. */
|
|
38
|
+
useReset: () => () => void;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* The public store plus the one member only the deprecated wrappers need: `markReaderWired`, so a
|
|
42
|
+
* consumer whose only reader is the wrapper's own `useStore()` still counts as wired and never sees
|
|
43
|
+
* the pinned-link warning it never used to see.
|
|
44
|
+
*
|
|
45
|
+
* @internal — absent from `SearchStore`, so it is invisible on `createSearchStore`'s return type.
|
|
46
|
+
*/
|
|
47
|
+
export type InternalSearchStore<S extends Record<string, AnyField>> = SearchStore<S> & {
|
|
48
|
+
markReaderWired: () => void;
|
|
49
|
+
};
|
|
50
|
+
/**
|
|
51
|
+
* The store, plus the one knob the deprecated wrappers need: `legacyValueField` keeps the
|
|
52
|
+
* enum-only stores' single-value storage layout so an already-persisted selection still resolves.
|
|
53
|
+
* Not exported from the barrel — `createSearchStore` is the public door.
|
|
54
|
+
*/
|
|
55
|
+
export declare function buildSearchStore<const S extends Record<string, AnyField>>(o: CreateSearchStoreOptions<S> & {
|
|
56
|
+
legacyValueField?: string;
|
|
57
|
+
}): InternalSearchStore<S>;
|
|
58
|
+
/**
|
|
59
|
+
* One store per page (or per feature), over typed fields. `key` is the localStorage key; each
|
|
60
|
+
* field's map key is its default URL param name.
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* export const analytics = createSearchStore({
|
|
64
|
+
* key: 'analytics',
|
|
65
|
+
* fields: {
|
|
66
|
+
* range: field.range({ presets: ['7d', '30d', '90d'], fallback: '30d', custom: true }),
|
|
67
|
+
* compare: field.enum(['none', 'previous'], 'none'),
|
|
68
|
+
* channels: field.multi(CHANNELS, []),
|
|
69
|
+
* },
|
|
70
|
+
* }).labels({ range: { '7d': 'Last 7 days', '30d': 'Last 30 days', '90d': 'Last 90 days' } })
|
|
71
|
+
*
|
|
72
|
+
* export const Route = createFileRoute('/analytics')({
|
|
73
|
+
* validateSearch: analytics.validateSearch,
|
|
74
|
+
* loaderDeps: ({ search }) => search,
|
|
75
|
+
* })
|
|
76
|
+
*
|
|
77
|
+
* // in the page: <RangeFilter field={analytics.field.range} />
|
|
78
|
+
* // in the nav: linkOptions({ to: '/analytics', search: analytics.linkSearch })
|
|
79
|
+
*/
|
|
80
|
+
export declare function createSearchStore<const S extends Record<string, AnyField>>(o: CreateSearchStoreOptions<S>): SearchStore<S>;
|
|
81
|
+
//# sourceMappingURL=search-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-store.d.ts","sourceRoot":"","sources":["../../src/router-tanstack/search-store.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAc,YAAY,EAAE,MAAM,UAAU,CAAA;AAI7F,MAAM,MAAM,wBAAwB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI;IACzE,uFAAuF;IACvF,GAAG,EAAE,MAAM,CAAA;IACX,uFAAuF;IACvF,MAAM,EAAE,CAAC,CAAA;IACT,wFAAwF;IACxF,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI;IAC5D;;;;OAIG;IACH,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,YAAY,CAAC,CAAC,CAAC,CAAA;IACjE;;;;OAIG;IACH,UAAU,EAAE,MAAM,YAAY,CAAC,CAAC,CAAC,CAAA;IACjC,iFAAiF;IACjF,UAAU,EAAE,MAAM,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAA;IAC1C,2FAA2F;IAC3F,KAAK,EAAE;SAAG,CAAC,IAAI,MAAM,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;KAAE,CAAA;IAC5C,8FAA8F;IAC9F,MAAM,EAAE,CAAC,GAAG,EAAE,OAAO,CAAC;SAAG,CAAC,IAAI,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;KAAE,CAAC,KAAK,WAAW,CAAC,CAAC,CAAC,CAAA;IACpF,6EAA6E;IAC7E,SAAS,EAAE,MAAM,YAAY,CAAC,CAAC,CAAC,CAAA;IAChC,oFAAoF;IACpF,cAAc,EAAE,MAAM,MAAM,CAAA;IAC5B,2EAA2E;IAC3E,QAAQ,EAAE,MAAM,MAAM,IAAI,CAAA;CAC3B,CAAA;AA4DD;;;;;;GAMG;AACH,MAAM,MAAM,mBAAmB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,WAAW,CAAC,CAAC,CAAC,GAAG;IACrF,eAAe,EAAE,MAAM,IAAI,CAAA;CAC5B,CAAA;AAQD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,EACvE,CAAC,EAAE,wBAAwB,CAAC,CAAC,CAAC,GAAG;IAAE,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7D,mBAAmB,CAAC,CAAC,CAAC,CAoMxB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,EACxE,CAAC,EAAE,wBAAwB,CAAC,CAAC,CAAC,GAC7B,WAAW,CAAC,CAAC,CAAC,CAEhB"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { useNavigate, useSearch } from "@tanstack/react-router";
|
|
2
|
+
import { createStoreCore } from "../state.js";
|
|
3
|
+
function warnLinkPinsFallback(input) {
|
|
4
|
+
const { key, param, urlValue, storedValue } = input;
|
|
5
|
+
console.warn(
|
|
6
|
+
`[basalt-ui] createSearchStore('${key}'): the URL pinned \`${param}=${urlValue}\` (the fallback) while '${storedValue}' was persisted, and nothing has read this store back. A nav link is almost certainly declaring \`search: { ${param}: '${urlValue}' }\` at module scope, which overrides the stored value on every click \u2014 pass the store's own reader instead: \`search: <store>.linkSearch\`. (dev only)`
|
|
7
|
+
);
|
|
8
|
+
}
|
|
9
|
+
function useCurrentSearch() {
|
|
10
|
+
const search = useSearch({ strict: false });
|
|
11
|
+
return typeof search === "object" && search !== null ? search : {};
|
|
12
|
+
}
|
|
13
|
+
function describeValue(value) {
|
|
14
|
+
return typeof value === "string" ? value : JSON.stringify(value);
|
|
15
|
+
}
|
|
16
|
+
function warnWriteHasNowhereToGo(input) {
|
|
17
|
+
const { key, name, param } = input;
|
|
18
|
+
console.warn(
|
|
19
|
+
`[basalt-ui] createSearchStore('${key}'): wrote field '${name}' from a route that does not validate \`${param}\`, and the field is \`persist: false\` \u2014 so the write was dropped. Either render this control on the route wired to \`validateSearch\`, or give the field the localStorage lane (drop \`persist: false\`) so a write from elsewhere survives until the owning route reads it. (dev only)`
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
function isMemoryLane(entry) {
|
|
23
|
+
return !entry.codec.lane.url && !entry.codec.lane.persist;
|
|
24
|
+
}
|
|
25
|
+
function buildSearchStore(o) {
|
|
26
|
+
const core = createStoreCore(o);
|
|
27
|
+
let readerWired = false;
|
|
28
|
+
let warned = false;
|
|
29
|
+
const markReaderWired = () => {
|
|
30
|
+
readerWired = true;
|
|
31
|
+
};
|
|
32
|
+
const nowhereWarned = /* @__PURE__ */ new Set();
|
|
33
|
+
const flatten = (search, record) => {
|
|
34
|
+
const out = {};
|
|
35
|
+
for (const entry of core.urlEntries) {
|
|
36
|
+
Object.assign(out, entry.codec.toSearch(core.resolve(entry, search, record)));
|
|
37
|
+
}
|
|
38
|
+
return out;
|
|
39
|
+
};
|
|
40
|
+
const maybeWarn = (raw, record) => {
|
|
41
|
+
if (warned || readerWired || process.env["NODE_ENV"] === "production") return;
|
|
42
|
+
for (const entry of core.urlEntries) {
|
|
43
|
+
const fromUrl = entry.codec.fromSearch(raw);
|
|
44
|
+
if (fromUrl === null || !entry.codec.equals(fromUrl, entry.codec.fallback)) continue;
|
|
45
|
+
const stored = entry.codec.decode(record[entry.name]);
|
|
46
|
+
if (stored === null || entry.codec.equals(stored, fromUrl)) continue;
|
|
47
|
+
warned = true;
|
|
48
|
+
warnLinkPinsFallback({
|
|
49
|
+
key: o.key,
|
|
50
|
+
param: entry.codec.primary,
|
|
51
|
+
urlValue: describeValue(entry.codec.toSearch(fromUrl)[entry.codec.primary]),
|
|
52
|
+
storedValue: describeValue(entry.codec.toSearch(stored)[entry.codec.primary])
|
|
53
|
+
});
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const validateSearch = (raw) => {
|
|
58
|
+
const record = core.readRecord();
|
|
59
|
+
maybeWarn(raw, record);
|
|
60
|
+
return flatten(raw, record);
|
|
61
|
+
};
|
|
62
|
+
const linkSearch = () => {
|
|
63
|
+
readerWired = true;
|
|
64
|
+
return flatten(null, core.readRecord());
|
|
65
|
+
};
|
|
66
|
+
const readStored = () => {
|
|
67
|
+
readerWired = true;
|
|
68
|
+
return core.readStoredFlat();
|
|
69
|
+
};
|
|
70
|
+
const urlUse = (entry) => () => {
|
|
71
|
+
const search = useCurrentSearch();
|
|
72
|
+
const navigate = useNavigate();
|
|
73
|
+
const [record, setRecord] = core.usePersistedRecord();
|
|
74
|
+
markReaderWired();
|
|
75
|
+
const value = core.resolve(entry, search, record);
|
|
76
|
+
const validated = Object.hasOwn(search, entry.codec.primary);
|
|
77
|
+
return [
|
|
78
|
+
value,
|
|
79
|
+
(next) => {
|
|
80
|
+
if (validated) {
|
|
81
|
+
navigate({
|
|
82
|
+
to: ".",
|
|
83
|
+
search: (prev) => ({ ...prev, ...entry.codec.toSearch(next) }),
|
|
84
|
+
replace: entry.codec.lane.history === "replace",
|
|
85
|
+
// A filter lives halfway down a page as often as it lives in the bar, and the router's
|
|
86
|
+
// default scroll restoration treats this same-route search write as a navigation — so
|
|
87
|
+
// without this a select two screens down jumps the reader back to the top on every
|
|
88
|
+
// change. Never a prop: there is no filter write that WANTS the page to scroll.
|
|
89
|
+
resetScroll: false
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
if (entry.codec.lane.persist) {
|
|
93
|
+
core.writeField(setRecord, entry.name, next);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (validated || nowhereWarned.has(entry.name)) return;
|
|
97
|
+
if (process.env["NODE_ENV"] === "production") return;
|
|
98
|
+
nowhereWarned.add(entry.name);
|
|
99
|
+
warnWriteHasNowhereToGo({ key: o.key, name: entry.name, param: entry.codec.primary });
|
|
100
|
+
}
|
|
101
|
+
];
|
|
102
|
+
};
|
|
103
|
+
const localUse = (entry) => () => {
|
|
104
|
+
const [record, setRecord] = core.usePersistedRecord();
|
|
105
|
+
markReaderWired();
|
|
106
|
+
return [
|
|
107
|
+
core.resolve(entry, null, record),
|
|
108
|
+
(next) => core.writeField(setRecord, entry.name, next)
|
|
109
|
+
];
|
|
110
|
+
};
|
|
111
|
+
const memoryEntries = core.entries.filter(isMemoryLane);
|
|
112
|
+
const field = {};
|
|
113
|
+
for (const entry of core.entries) {
|
|
114
|
+
const use = entry.codec.lane.url ? urlUse(entry) : entry.codec.lane.persist ? localUse(entry) : core.memoryUse(entry);
|
|
115
|
+
field[entry.name] = core.handle(entry, use);
|
|
116
|
+
}
|
|
117
|
+
const useValues = () => {
|
|
118
|
+
const search = useCurrentSearch();
|
|
119
|
+
const [record] = core.usePersistedRecord();
|
|
120
|
+
markReaderWired();
|
|
121
|
+
return flatten(search, record);
|
|
122
|
+
};
|
|
123
|
+
const useActiveCount = () => {
|
|
124
|
+
const search = useCurrentSearch();
|
|
125
|
+
const [record] = core.usePersistedRecord();
|
|
126
|
+
core.useMemoryVersion();
|
|
127
|
+
let count = 0;
|
|
128
|
+
for (const entry of core.entries) {
|
|
129
|
+
const value = isMemoryLane(entry) ? core.readMemoryValue(entry) : core.resolve(entry, entry.codec.lane.url ? search : null, record);
|
|
130
|
+
if (!entry.codec.equals(value, entry.codec.fallback)) count += 1;
|
|
131
|
+
}
|
|
132
|
+
return count;
|
|
133
|
+
};
|
|
134
|
+
const useReset = () => {
|
|
135
|
+
const search = useCurrentSearch();
|
|
136
|
+
const navigate = useNavigate();
|
|
137
|
+
const [, setRecord] = core.usePersistedRecord();
|
|
138
|
+
return () => {
|
|
139
|
+
const validatedEntries = core.urlEntries.filter(
|
|
140
|
+
(entry) => Object.hasOwn(search, entry.codec.primary)
|
|
141
|
+
);
|
|
142
|
+
if (validatedEntries.length > 0) {
|
|
143
|
+
const patch = {};
|
|
144
|
+
for (const entry of validatedEntries) {
|
|
145
|
+
Object.assign(patch, entry.codec.toSearch(entry.codec.fallback));
|
|
146
|
+
}
|
|
147
|
+
navigate({
|
|
148
|
+
to: ".",
|
|
149
|
+
search: (prev) => ({ ...prev, ...patch }),
|
|
150
|
+
replace: true,
|
|
151
|
+
// Same reason as a single field's write above — a `Reset all` pressed from the mobile
|
|
152
|
+
// sheet must not also scroll the page it was pressed on.
|
|
153
|
+
resetScroll: false
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
if (memoryEntries.length > 0) core.resetMemory();
|
|
157
|
+
if (!core.anyPersisted) return;
|
|
158
|
+
const next = { ...core.readRecord() };
|
|
159
|
+
for (const entry of core.entries) {
|
|
160
|
+
if (entry.codec.lane.persist) next[entry.name] = entry.codec.fallback;
|
|
161
|
+
}
|
|
162
|
+
setRecord(next);
|
|
163
|
+
};
|
|
164
|
+
};
|
|
165
|
+
const store = {
|
|
166
|
+
validateSearch,
|
|
167
|
+
linkSearch,
|
|
168
|
+
readStored,
|
|
169
|
+
field,
|
|
170
|
+
labels: (map) => {
|
|
171
|
+
core.setLabels(map);
|
|
172
|
+
return store;
|
|
173
|
+
},
|
|
174
|
+
useValues,
|
|
175
|
+
useActiveCount,
|
|
176
|
+
useReset,
|
|
177
|
+
markReaderWired
|
|
178
|
+
};
|
|
179
|
+
return store;
|
|
180
|
+
}
|
|
181
|
+
function createSearchStore(o) {
|
|
182
|
+
return buildSearchStore(o);
|
|
183
|
+
}
|
|
184
|
+
export {
|
|
185
|
+
buildSearchStore,
|
|
186
|
+
createSearchStore
|
|
187
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-store.router.test.d.ts","sourceRoot":"","sources":["../../src/router-tanstack/search-store.router.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-store.test.d.ts","sourceRoot":"","sources":["../../src/router-tanstack/search-store.test.ts"],"names":[],"mappings":""}
|
|
@@ -10,8 +10,6 @@ export type UseNavOptions<G extends ReadonlyArray<AnyNavGroup>> = {
|
|
|
10
10
|
badges?: Partial<Record<NavItemId<G>, number | ReactNode>>;
|
|
11
11
|
/** Override active detection entirely. */
|
|
12
12
|
isActive?: (item: AnyNavItem) => boolean;
|
|
13
|
-
/** Passed straight through into the returned `mobileNav`. */
|
|
14
|
-
moreExtra?: ReactNode;
|
|
15
13
|
getScrollElement?: () => HTMLElement | null;
|
|
16
14
|
};
|
|
17
15
|
/** Spread straight onto `<BasaltShell {...nav} />` — both keys are `BasaltShellProps` keys. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-nav.d.ts","sourceRoot":"","sources":["../../src/router-tanstack/use-nav.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAe,SAAS,EAAE,MAAM,OAAO,CAAA;AAEnD,OAAO,KAAK,EAAE,eAAe,EAA0B,cAAc,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"use-nav.d.ts","sourceRoot":"","sources":["../../src/router-tanstack/use-nav.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAe,SAAS,EAAE,MAAM,OAAO,CAAA;AAEnD,OAAO,KAAK,EAAE,eAAe,EAA0B,cAAc,EAAE,MAAM,cAAc,CAAA;AAE3F,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAEpF,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,aAAa,CAAC,WAAW,CAAC,IAAI;IAChE;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAA;IAC1D,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,OAAO,CAAA;IACxC,gBAAgB,CAAC,EAAE,MAAM,WAAW,GAAG,IAAI,CAAA;CAC5C,CAAA;AAED,+FAA+F;AAC/F,MAAM,MAAM,UAAU,GAAG;IAAE,QAAQ,EAAE,cAAc,EAAE,CAAC;IAAC,SAAS,EAAE,eAAe,CAAA;CAAE,CAAA;AAEnF;;;;;;GAMG;AACH,wBAAgB,MAAM,CACpB,KAAK,CAAC,CAAC,SAAS,aAAa,CAAC,WAAW,CAAC,EAC1C,KAAK,CAAC,CAAC,SAAS,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAC1C,MAAM,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC,GAAG,UAAU,CAgK9D"}
|