basalt-ui 1.25.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 +18 -0
- package/MIGRATING.md +546 -20
- 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 +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/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 +37 -15
- package/dist/data/data-table.d.ts.map +1 -1
- package/dist/data/data-table.js +88 -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 +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/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 +96 -11
- package/src/data/data-table.tsx +220 -84
- 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 -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
|
@@ -1,117 +1,134 @@
|
|
|
1
1
|
---
|
|
2
2
|
source: basalt-ui
|
|
3
|
-
description:
|
|
3
|
+
description: Where each kind of state lives in a basalt-ui app — createSearchStore over typed fields (URL > localStorage > fallback), the lanes, FieldHandle, linkSearch by reference, defineNav/useNav, createPersistedState. Partly enforced by basalt/search-literal-link, basalt/use-search-from-literal and the localstorage-theme guard kind.
|
|
4
4
|
paths:
|
|
5
5
|
- 'src/**'
|
|
6
6
|
- 'apps/**/src/**'
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
<!-- basalt:coverage -->
|
|
10
|
+
<!-- GENERATED from src/surfaces.ts — `basalt-ui check-coverage --write`. Do not hand-edit. -->
|
|
11
|
+
<!-- backed by: guard kinds — localstorage-theme · oxlint rules — basalt/search-literal-link, basalt/use-search-from-literal -->
|
|
12
|
+
<!-- not guarded: — -->
|
|
13
|
+
<!-- /basalt:coverage -->
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
guard-enforced (`basalt-ui check-theme` bans `localStorage.getItem('theme')`); the rest is **advisory**.
|
|
15
|
+
# Basalt State — stores, lanes, nav
|
|
13
16
|
|
|
14
|
-
|
|
17
|
+
A store is defined wherever the feature lives (`src/lib/`, `src/features/…`), not only under
|
|
18
|
+
`src/routes/**` — which is why this rule loads across the whole source tree.
|
|
15
19
|
|
|
16
|
-
|
|
20
|
+
## Where state goes
|
|
17
21
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
- **UI preferences that must survive navigation but aren't URL-worthy** (sidebar collapsed, panel
|
|
26
|
-
layout, draft filters) → `createPersistedState` from `basalt-ui/state` — the framework's own
|
|
27
|
-
versioned localStorage primitive (see below). `BasaltShell` persists its own collapse state
|
|
28
|
-
through that same primitive since 1.21.0; use `createPersistedState` for app-level preferences.
|
|
29
|
-
Reach for a third-party store only when complex cross-component state genuinely warrants it (see
|
|
30
|
-
escape hatch below).
|
|
22
|
+
| Kind | Home |
|
|
23
|
+
| ------------------------------------------------------------------- | ------------------------------------------------------------------------ |
|
|
24
|
+
| server data | TanStack Query (basalt-batteries.md) |
|
|
25
|
+
| anything a control reads or writes — filter, tab, range, pagination | a **field** on `createSearchStore` / `createLocalStore` |
|
|
26
|
+
| color scheme | `useMantineColorScheme()` — never a store, never `localStorage['theme']` |
|
|
27
|
+
| a preference that must survive navigation but is not URL-worthy | `createPersistedState` (`basalt-ui/state`) |
|
|
28
|
+
| network status | `useConnectivity()` — auto-mounted by `BasaltProvider` |
|
|
31
29
|
|
|
32
|
-
|
|
30
|
+
**Never `useState` for a filter, a tab, a range or a view** (law C3). It resets on navigation, it
|
|
31
|
+
cannot be linked, and it is the state a basalt control refuses to take (`value`/`onChange` do not
|
|
32
|
+
exist on one). Reach for a third-party store only for genuinely shared mutable state with no owning
|
|
33
|
+
component; basalt ships and depends on none.
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
`false` when offline. Backed by `useSyncExternalStore` + `window.online`/`offline` events.
|
|
36
|
-
SSR-safe — server snapshot is `true` (optimistic). Exported from both `basalt-ui` (root) and
|
|
37
|
-
`basalt-ui/state`.
|
|
35
|
+
## `createSearchStore` — one factory over typed fields
|
|
38
36
|
|
|
39
37
|
```ts
|
|
40
|
-
import {
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
38
|
+
import { createSearchStore, field } from 'basalt-ui/router-tanstack'
|
|
39
|
+
|
|
40
|
+
export const analytics = createSearchStore({
|
|
41
|
+
key: 'analytics',
|
|
42
|
+
fields: {
|
|
43
|
+
range: field.range({ presets: ['7d', '30d', '90d'], fallback: '30d', custom: true }),
|
|
44
|
+
channels: field.multi(CHANNELS, []),
|
|
45
|
+
tab: field.enum(['overview', 'detail'], 'overview', { persist: false }),
|
|
46
|
+
compact: field.boolean(false, { url: false }),
|
|
47
|
+
},
|
|
48
|
+
}).labels({ range: { '7d': 'Last 7 days', '30d': 'Last 30 days', '90d': 'Last 90 days' } })
|
|
44
49
|
```
|
|
45
50
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
- **The URL is the truth; the localStorage mirror is a fallback UNDER it.** Every field resolves
|
|
52
|
+
URL ⊳ localStorage ⊳ fallback, identically for every field kind (law C4). A deep link therefore
|
|
53
|
+
wins over the mirror — that is the whole difference from the enum-only pair it replaced, whose
|
|
54
|
+
reader WAS the localStorage state, so a shared link opened on the wrong window.
|
|
55
|
+
- **Lanes are declared once, at definition**: `{ url, persist, history }`. `url: false` is the
|
|
56
|
+
local-only lane (a per-card select, a compact toggle); `persist: false` is the URL-only lane
|
|
57
|
+
(pagination, a tab that should not follow you to another feature). `createLocalStore`
|
|
58
|
+
(`basalt-ui/state`) is the same field vocabulary with no router at all.
|
|
59
|
+
- **Option LABELS come from `.labels()`, once, at definition** — never a per-control prop and never a
|
|
60
|
+
lookup table in the page.
|
|
61
|
+
- **`validateSearch: store.validateSearch`** on the route, in the function form. It returns every
|
|
62
|
+
URL-lane param unconditionally, which is what makes the store's "does this route own the field"
|
|
63
|
+
check exact. A route with a genuinely wider search shape hand-writes `validateSearch` and COMPOSES
|
|
64
|
+
the store into it (`{ ...store.validateSearch(raw), ...rest }`) — there is no schema-backed store
|
|
65
|
+
variant, and none is coming.
|
|
66
|
+
- **A write from outside the owning route persists only**, and `validateSearch` picks it up on the
|
|
67
|
+
next visit. Two different stores using one param name on overlapping routes read as one owner;
|
|
68
|
+
presence in the search is all a store can see without the router naming the declarer.
|
|
69
|
+
- **`field.range` keeps its three URL params** (preset + from/to, renamable) so existing loaders and
|
|
70
|
+
deep links keep their shape; `handle.toWindow(value)` is the projection into query params — never a
|
|
71
|
+
hand-written `presetToParams`.
|
|
72
|
+
|
|
73
|
+
## Reading and writing
|
|
74
|
+
|
|
75
|
+
- **A page reads `store.useValues()`, or takes the value as a PROP.** Never
|
|
76
|
+
`useSearch({ from: '<literal>' })` — a sibling or child route fails that `from`, and it is
|
|
77
|
+
`basalt/use-search-from-literal`. Basalt's own controls read through the `FieldHandle`, which uses
|
|
78
|
+
the non-strict search internally, so a control renders on any matched route with no `from` at all.
|
|
79
|
+
- **A `FieldHandle` is the whole read/write surface** a control needs: `use()` returns
|
|
80
|
+
`[value, setValue]` and the setter owns the navigate AND the persist. So a control never receives
|
|
81
|
+
`value`/`onChange` (law C2) and a page never writes a navigate for a store field. Where you DO hand-write
|
|
82
|
+
one — a route with its own search shape — use the reducer form, `navigate({ search: (prev) => ({ ...prev, … }) })`,
|
|
83
|
+
so unrelated params survive.
|
|
84
|
+
- **`useActiveCount()` / `useReset()`** are what a `Filters (n)` pill and its `Reset all` derive
|
|
85
|
+
from. Never hand-count either.
|
|
86
|
+
|
|
87
|
+
## Nav links carry the store BY REFERENCE
|
|
52
88
|
|
|
53
89
|
```ts
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
// 1. Define the hook once (version: increment when the shape changes):
|
|
57
|
-
export const usePanelLayout = createPersistedState({
|
|
58
|
-
key: 'panel-layout',
|
|
59
|
-
version: 1,
|
|
60
|
-
initial: 'split' as 'split' | 'stacked',
|
|
61
|
-
})
|
|
62
|
-
|
|
63
|
-
// 2. Use in any component — no provider, no context:
|
|
64
|
-
const [layout, setLayout] = usePanelLayout()
|
|
90
|
+
link: linkOptions({ to: '/dashboard', search: analytics.linkSearch })
|
|
65
91
|
```
|
|
66
92
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
import
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
),
|
|
110
|
-
)
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
basalt-ui does **not** ship or depend on Zustand — it is a consumer choice. Resist putting
|
|
114
|
-
query results, derived data, or theme scheme in any store.
|
|
115
|
-
|
|
116
|
-
> **Forms** are covered by `basalt-forms.md` — see `./forms` (useBasaltForm, field, FormErrorSummary,
|
|
117
|
-
> useFormDraft). `@mantine/form` is an optional peer; install it with `bun add @mantine/form`.
|
|
93
|
+
**Pass the function, never call it, never inline an object.** It is a click-time thunk, so arriving
|
|
94
|
+
from anywhere restores the last selection; a module-scope literal (`search: { range: '30d' }`) pins
|
|
95
|
+
the fallback on every click and is why one consumer's reader had zero call sites while every
|
|
96
|
+
individual piece looked correct. `search: true` is a type error against a store-backed route.
|
|
97
|
+
`basalt/search-literal-link` catches the literal, and in dev `validateSearch` warns once when the URL
|
|
98
|
+
pins the fallback, something else is persisted, and no reader has ever been called.
|
|
99
|
+
|
|
100
|
+
## The typed nav definition
|
|
101
|
+
|
|
102
|
+
The whole navigation — desktop sidebar and mobile bar — is declared ONCE with `defineNav` /
|
|
103
|
+
`navGroup` in a **leaf** module (`src/lib/nav.tsx`) that never imports `routeTree.gen` or
|
|
104
|
+
`__root.tsx`, so palettes and redirects can import it without closing a cycle. `useNav(NAV)` resolves
|
|
105
|
+
it against the live router and returns `{ sections, mobileNav }` — both `BasaltShell` props, so
|
|
106
|
+
spread it. `navTarget(NAV, id)` is one destination's link options, typed per id, for a `<Link>`, a
|
|
107
|
+
`navigate()` or a `redirect()`. `flattenNav` is the leaf every other surface reads (e.g. projecting
|
|
108
|
+
the nav into Spotlight in one `.map()`).
|
|
109
|
+
|
|
110
|
+
- **Route options live under `link:`, wrapped in TanStack's own `linkOptions`** — never spread flat
|
|
111
|
+
onto the item. A flat shape validates `to` by assignability, which does no excess-property
|
|
112
|
+
checking, so a typo'd metadata key compiles silently. `id`/`label`/`short`/`icon`/`mobile`/
|
|
113
|
+
`disabled`/`exact` ride outside `link`.
|
|
114
|
+
- **Nesting is `children`**; `mobile` places the destination on the bar (basalt-mantine.md).
|
|
115
|
+
- **Without the `Register` module augmentation, `defineNav` validates NOTHING and reports zero
|
|
116
|
+
errors** — `RegisteredRouter` falls back to `AnyRouter`, every `to` widens to `string`, and the API
|
|
117
|
+
looks like it is working while catching nothing. Verify it once by changing a `to` to garbage and
|
|
118
|
+
confirming the compile error lists the real route paths. The router's errors here are large; read
|
|
119
|
+
the union for the intended path and fix the string. **Never reach for `as never`** to quiet one —
|
|
120
|
+
the checking is the entire point.
|
|
121
|
+
- Whether a MISSING `search` is caught depends on the schema's OUTPUT type: with every key required
|
|
122
|
+
(what a store or a defaulted Zod object produces) TanStack raises and the compiler catches it. With
|
|
123
|
+
every key optional, a forgotten `search` compiles — diff the target table by hand there.
|
|
124
|
+
- `staticData` (`title` / `icon` / `navSection`) drives `useRouterBreadcrumbs` and needs the
|
|
125
|
+
generated route tree; everything else in the bridge works against a hand-written router.
|
|
126
|
+
|
|
127
|
+
## `createPersistedState` — the localStorage primitive
|
|
128
|
+
|
|
129
|
+
Call it once at module scope; use the returned hook anywhere, with no provider. SSR-safe, cross-tab
|
|
130
|
+
through the `storage` event, versioned — bump `version` when the shape changes and stale values fall
|
|
131
|
+
back to `initial`. Keys are namespaced `basalt:<key>` automatically, and `readPersistedValue(key, v)`
|
|
132
|
+
is the non-React read (how you mirror the shell's own collapse state). Pass a Standard Schema to
|
|
133
|
+
validate what comes back. Every basalt module that persists — the shell's collapse, a `Section`
|
|
134
|
+
fold, a sidebar block, a form draft, the notification history — persists through this one primitive.
|