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
|
@@ -0,0 +1,542 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* `basalt-ui/controls` — the filter/tab home surface (docs/CONTROLS-SPEC.md §3).
|
|
3
|
+
*
|
|
4
|
+
* Two form factors per control, ONE mount each, switched by CSS only (C9): the `pill` surface
|
|
5
|
+
* (bordered 30px chip + popover) and the `sheet` surface (44px full-width rows inside the mobile
|
|
6
|
+
* `Filters (n)` Drawer). `48em` / `47.99375em` are the `sm` breakpoint in the exact literal form
|
|
7
|
+
* every other basalt CSS module uses — a media query cannot resolve a custom property, so the
|
|
8
|
+
* breakpoint cannot be a token (see `content/prose.module.css`'s note).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/* ── The pill row (FilterSet, desktop + the mobile inline head) ───────────────────────────────── */
|
|
12
|
+
|
|
13
|
+
/*
|
|
14
|
+
* `flex: 1 1 auto` is what makes `useOverflowFit`'s measurement HONEST, and its absence is what made
|
|
15
|
+
* the fold fire at 1440px with 600px of free space. Left at the flex default (`0 1 auto`) the row
|
|
16
|
+
* sizes to its own CONTENT, so `row.clientWidth` returned exactly Σ(slot widths + gaps) — the fold
|
|
17
|
+
* compared the pills against themselves, went over by a subpixel, and folded the tail on every
|
|
18
|
+
* viewport. Growing the row to the space its container actually offers is the only way the measure
|
|
19
|
+
* can ever mean "does this fit". `min-width: 0` keeps it shrinkable so an OVERFLOWING row still
|
|
20
|
+
* reports the available width rather than the content width. Together with `.pillSlot`'s
|
|
21
|
+
* `flex-shrink: 0` (see below) the two sides of the comparison are now measured independently.
|
|
22
|
+
*/
|
|
23
|
+
.pillRow {
|
|
24
|
+
display: flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
gap: var(--vx-space-control-gap, 0.375rem);
|
|
27
|
+
flex: 1 1 auto;
|
|
28
|
+
min-width: 0;
|
|
29
|
+
flex-wrap: nowrap;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/*
|
|
33
|
+
* Every child stays MOUNTED in the row on every viewport — folding and the mobile `inline` budget
|
|
34
|
+
* hide slots with `display: none` instead of unmounting them. That is what keeps FilterSet's active
|
|
35
|
+
* count and `Reset all` complete: the row is the single registration surface, so a filter that
|
|
36
|
+
* scrolled out of the `inline` budget still reports itself (see `filter-context.tsx`).
|
|
37
|
+
*/
|
|
38
|
+
/*
|
|
39
|
+
* `flex-shrink: 0` is what makes the fold WORK, not a cosmetic choice. A shrinkable slot lets flex
|
|
40
|
+
* squeeze every pill until Σ widths == the row width, so `useOverflowFit` would sum
|
|
41
|
+
* already-compressed boxes, conclude everything fits, and never show `+N` — precisely when the row
|
|
42
|
+
* is overflowing. Incompressible slots report their natural width, so the sum honestly exceeds the
|
|
43
|
+
* budget and the tail folds on the same measure tick. `min-width: 0` stays off deliberately for the
|
|
44
|
+
* same reason.
|
|
45
|
+
*/
|
|
46
|
+
.pillSlot {
|
|
47
|
+
display: inline-flex;
|
|
48
|
+
flex-shrink: 0;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/* Below `sm` only the first `inline` slots are pills; the rest live in the sheet. */
|
|
52
|
+
@media (max-width: 47.99375em) {
|
|
53
|
+
.pillSlot:not([data-inline]) {
|
|
54
|
+
display: none;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/*
|
|
59
|
+
* Folding is a DESKTOP concern only — scoped to `min-width` so a width measured on a wide viewport
|
|
60
|
+
* can never hide a slot the mobile `inline` budget is supposed to keep.
|
|
61
|
+
*/
|
|
62
|
+
@media (min-width: 48em) {
|
|
63
|
+
.pillSlot[data-folded] {
|
|
64
|
+
display: none;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* `+N` (desktop fold) and `Filters (n)` (mobile sheet opener) are each one pill, never both. */
|
|
69
|
+
.foldPill {
|
|
70
|
+
display: none;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
@media (min-width: 48em) {
|
|
74
|
+
.foldPill[data-shown] {
|
|
75
|
+
display: inline-flex;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.sheetPill {
|
|
80
|
+
display: none;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@media (max-width: 47.99375em) {
|
|
84
|
+
.sheetPill {
|
|
85
|
+
display: inline-flex;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* ── FilterPill ───────────────────────────────────────────────────────────────────────────────── */
|
|
90
|
+
|
|
91
|
+
/*
|
|
92
|
+
* The bordered chip. `variant="default" size="ctl"` carries the 30px height, the 10px inset
|
|
93
|
+
* (`--button-padding-x-ctl`) and the control radius from the theme; this module owns what the
|
|
94
|
+
* variant cannot express.
|
|
95
|
+
*
|
|
96
|
+
* **The border is one of those.** `cssVariablesResolver` points
|
|
97
|
+
* `--mantine-color-default-border` at `transparent` on purpose (depth is a shadow, never a hairline
|
|
98
|
+
* — `docs/DESIGN-SPEC.md` §8), so a `variant="default"` Button ships no visible edge at all. A
|
|
99
|
+
* filter pill is the one control that NEEDS one: it is a chip in a row of chips, and without an
|
|
100
|
+
* outline the row reads as loose text. Declared here rather than by relaxing the resolver, which
|
|
101
|
+
* would put a hairline back on every default button in the app.
|
|
102
|
+
*
|
|
103
|
+
* The ≥36px touch target below `sm` (C15) is drawn as a `::before` overlay so the visible box stays
|
|
104
|
+
* 30px.
|
|
105
|
+
*/
|
|
106
|
+
.pill {
|
|
107
|
+
position: relative;
|
|
108
|
+
max-width: 15rem;
|
|
109
|
+
border-color: color-mix(in srgb, var(--vx-ink) 12%, transparent);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/*
|
|
113
|
+
* The inset stays 10px on BOTH edges, section or no section. Mantine divides `--button-padding-x` by
|
|
114
|
+
* 1.5 whenever a Button carries a left/right section (`Button.css`), which is right for a labelled
|
|
115
|
+
* `md` button and wrong here: every pill has a trailing `⇅` and most have a leading glyph, so the
|
|
116
|
+
* division applied to all of them and the whole row rendered at a 6.7px inset — visibly tighter than
|
|
117
|
+
* the buttons in the header above it, for no reason a reader could see. This module is unlayered, so
|
|
118
|
+
* it outranks `@layer mantine` regardless of specificity.
|
|
119
|
+
*/
|
|
120
|
+
.pill[data-with-left-section],
|
|
121
|
+
.pill[data-with-right-section] {
|
|
122
|
+
padding-inline: var(--button-padding-x-ctl);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.pill[data-active] {
|
|
126
|
+
border-color: var(--vx-accent);
|
|
127
|
+
color: var(--vx-ink);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/*
|
|
131
|
+
* Mantine spends `--mantine-spacing-xs` (11px) between a Button's section and its label, which is
|
|
132
|
+
* the BODY tier's gap; a `ctl` chip wants the tier's own 6px so the icon reads as part of the label
|
|
133
|
+
* rather than a separate mark. Both sections, so the trailing `⇅` sits the same distance out.
|
|
134
|
+
*/
|
|
135
|
+
.pill :global(.mantine-Button-section[data-position='left']) {
|
|
136
|
+
margin-inline-end: var(--vx-space-control-gap, 0.375rem);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.pill :global(.mantine-Button-section[data-position='right']) {
|
|
140
|
+
margin-inline-start: var(--vx-space-control-gap, 0.375rem);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/*
|
|
144
|
+
* The leading-icon box carries COLOUR ONLY now. The 16px box, the `display: block` reset on the
|
|
145
|
+
* glyph and the optical centring all live in `theme/icon-slot.module.css`, which every `icon` prop
|
|
146
|
+
* in the framework renders through — this class is composed onto that slot, not instead of it. The
|
|
147
|
+
* `> svg { width: 1rem }` pair that used to live here was the same mechanism written once per
|
|
148
|
+
* component, which is exactly how `BarAction`'s icon slot went un-boxed and let a consumer's
|
|
149
|
+
* `width="24"` glyph set a header row's height.
|
|
150
|
+
*/
|
|
151
|
+
.pillIcon {
|
|
152
|
+
color: var(--vx-muted);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.pill[data-active] .pillIcon {
|
|
156
|
+
color: var(--vx-ink);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
@media (max-width: 47.99375em) {
|
|
160
|
+
/* Mantine's Button root clips to its box; the overlay must escape it to be hit-testable. Loading
|
|
161
|
+
* buttons keep the clip their overlay depends on (same pairing as page-bar.module.css). */
|
|
162
|
+
.pill:not([data-loading]) {
|
|
163
|
+
overflow: visible;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.pill::before {
|
|
167
|
+
content: '';
|
|
168
|
+
position: absolute;
|
|
169
|
+
/* Both operands scale with `--mantine-scale` (same reconstruction the theme uses for every
|
|
170
|
+
* other ctl-tier box, `theme/index.ts`'s `ctlSizeVars`) so the overlay stays centred on — and
|
|
171
|
+
* sized off — the ACTUAL scaled pill box, not its unscaled rem value. */
|
|
172
|
+
inset-block: calc(
|
|
173
|
+
(
|
|
174
|
+
calc(var(--vx-space-control-height-ctl, 1.875rem) * var(--mantine-scale, 1)) -
|
|
175
|
+
calc(var(--vx-space-touch-control-height, 2.25rem) * var(--mantine-scale, 1))
|
|
176
|
+
) /
|
|
177
|
+
2
|
|
178
|
+
);
|
|
179
|
+
inset-inline: 0;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/* Label at the tier's own step and weight (`docs/CONTROLS-SPEC.md` §3) — Mantine's Button label
|
|
184
|
+
* inherits the root's `--button-fz` but carries the body weight, which reads light against the
|
|
185
|
+
* bordered box. */
|
|
186
|
+
.pillLabel {
|
|
187
|
+
overflow: hidden;
|
|
188
|
+
text-overflow: ellipsis;
|
|
189
|
+
white-space: nowrap;
|
|
190
|
+
font-size: var(--vx-text-sm);
|
|
191
|
+
font-weight: 500;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/* Numeric pill labels read mono at the smaller step. The FACE comes from the package-wide
|
|
195
|
+
* `[data-numeric]` law in `styles.css`; the `font-size` is the pill's own decision, which is why
|
|
196
|
+
* this rule exists at all. */
|
|
197
|
+
.pill[data-numeric] .pillLabel {
|
|
198
|
+
font-family: var(--basalt-font-mono);
|
|
199
|
+
font-size: var(--vx-text-xs);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/*
|
|
203
|
+
* Every pill's trailing affordance is the ONE icon in the tier that is deliberately smaller than the
|
|
204
|
+
* leading glyph — 14px, muted (`docs/CONTROLS-SPEC.md` §3). It gets there by overriding the icon
|
|
205
|
+
* slot's box var, never by sizing the SVG: the slot is the only thing that decides a glyph's
|
|
206
|
+
* geometry, so a smaller mark is a smaller BOX.
|
|
207
|
+
*/
|
|
208
|
+
.glyph {
|
|
209
|
+
--vx-space-icon-size: 0.875rem;
|
|
210
|
+
|
|
211
|
+
color: var(--vx-faint);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/* ── Popover bodies ───────────────────────────────────────────────────────────────────────────── */
|
|
215
|
+
|
|
216
|
+
.dropdown {
|
|
217
|
+
min-width: 11rem;
|
|
218
|
+
max-width: 22rem;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
.optionList {
|
|
222
|
+
display: flex;
|
|
223
|
+
flex-direction: column;
|
|
224
|
+
gap: 2px;
|
|
225
|
+
min-width: 0;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/* ── The sheet surface (inside the bottom Drawer) ─────────────────────────────────────────────── */
|
|
229
|
+
|
|
230
|
+
/*
|
|
231
|
+
* One rhythm, one kind of separator. Groups are 12px apart (`--vx-space-stack-md`) and NOTHING
|
|
232
|
+
* between them draws a line: the only hairline in the sheet is the one between two option rows of
|
|
233
|
+
* the SAME group (`.sheetOption`, below), which is what makes it read as a list rather than as a
|
|
234
|
+
* stack of boxed sections. The pre-1.28 sheet had a footer rule, a Drawer header rule and a
|
|
235
|
+
* `Radio.Group` per filter, so a six-filter sheet drew seven lines and none of them grouped
|
|
236
|
+
* anything.
|
|
237
|
+
*/
|
|
238
|
+
.sheetBody {
|
|
239
|
+
display: flex;
|
|
240
|
+
flex-direction: column;
|
|
241
|
+
gap: var(--vx-space-stack-md, 0.75rem);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/* The Drawer header holds the title AND `Reset all` (see `FilterSheet`'s doc), so it is a row that
|
|
245
|
+
* spreads rather than Mantine's default title-plus-close pair. 44px, like every sheet row. */
|
|
246
|
+
.sheetHeader {
|
|
247
|
+
min-height: var(--vx-space-sheet-row-height, 2.75rem);
|
|
248
|
+
padding-block: 0;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.sheetTitle {
|
|
252
|
+
display: flex;
|
|
253
|
+
flex: 1;
|
|
254
|
+
align-items: center;
|
|
255
|
+
justify-content: space-between;
|
|
256
|
+
gap: var(--vx-space-control-gap, 0.375rem);
|
|
257
|
+
min-width: 0;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.sheetTitleText {
|
|
261
|
+
font-family: var(--basalt-font-head);
|
|
262
|
+
font-stretch: 88%;
|
|
263
|
+
font-weight: 550;
|
|
264
|
+
font-size: var(--vx-text-xl);
|
|
265
|
+
color: var(--vx-ink);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
.sheetField {
|
|
269
|
+
display: flex;
|
|
270
|
+
flex-direction: column;
|
|
271
|
+
gap: 2px;
|
|
272
|
+
min-width: 0;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/* ── SheetOptionList / SheetDisclosure ────────────────────────────────────────────────────────── */
|
|
276
|
+
|
|
277
|
+
/* A `<fieldset>` in the option-list case (see `SheetOptionList`), a plain div in the disclosure
|
|
278
|
+
* case — the reset covers both, since a div ignores all of it. */
|
|
279
|
+
.sheetList {
|
|
280
|
+
display: flex;
|
|
281
|
+
flex-direction: column;
|
|
282
|
+
margin: 0;
|
|
283
|
+
padding: 0;
|
|
284
|
+
border: none;
|
|
285
|
+
min-inline-size: 0;
|
|
286
|
+
min-width: 0;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/*
|
|
290
|
+
* The 44px option row (C15). `<label>` in a list, `<button>` in a disclosure — one class, because
|
|
291
|
+
* the two must be indistinguishable: the disclosure IS the list's last entry.
|
|
292
|
+
*
|
|
293
|
+
* `appearance`/`margin`/`border`/`background`/`text-align` reset the `<button>` form back to the
|
|
294
|
+
* `<label>`'s box; a `<label>` ignores all five, so there is no need for a second selector.
|
|
295
|
+
*/
|
|
296
|
+
.sheetOption {
|
|
297
|
+
position: relative;
|
|
298
|
+
display: flex;
|
|
299
|
+
align-items: center;
|
|
300
|
+
gap: var(--mantine-spacing-xs, 0.625rem);
|
|
301
|
+
width: 100%;
|
|
302
|
+
min-height: var(--vx-space-sheet-row-height, 2.75rem);
|
|
303
|
+
appearance: none;
|
|
304
|
+
margin: 0;
|
|
305
|
+
padding: 0;
|
|
306
|
+
border: none;
|
|
307
|
+
background: none;
|
|
308
|
+
text-align: start;
|
|
309
|
+
color: var(--vx-muted);
|
|
310
|
+
cursor: pointer;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/* Hairline BETWEEN rows only — a trailing border on the last row would be the group separator this
|
|
314
|
+
* sheet deliberately does not draw. */
|
|
315
|
+
.sheetOption + .sheetOption,
|
|
316
|
+
.sheetDisclosureBody + .sheetOption,
|
|
317
|
+
.sheetOption + .sheetDisclosureBody {
|
|
318
|
+
border-top: 1px solid color-mix(in srgb, var(--vx-ink) 6%, transparent);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
.sheetOption[data-selected] {
|
|
322
|
+
color: var(--vx-ink);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.sheetOption[data-disabled] {
|
|
326
|
+
color: var(--vx-faint);
|
|
327
|
+
cursor: not-allowed;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
@media (hover: hover) {
|
|
331
|
+
.sheetOption:not([data-disabled]):hover {
|
|
332
|
+
color: var(--vx-ink);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/*
|
|
337
|
+
* The real native radio/checkbox, visually hidden — the row's semantics, not decoration (see
|
|
338
|
+
* `SheetOptionList`'s doc). Not `display: none`: a hidden input is unfocusable, which would take the
|
|
339
|
+
* arrow-key group behaviour with it. Standard visually-hidden clip, and `:focus-visible` on it is
|
|
340
|
+
* what draws the ROW's focus ring below.
|
|
341
|
+
*/
|
|
342
|
+
.sheetOptionInput {
|
|
343
|
+
position: absolute;
|
|
344
|
+
width: 1px;
|
|
345
|
+
height: 1px;
|
|
346
|
+
margin: -1px;
|
|
347
|
+
padding: 0;
|
|
348
|
+
overflow: hidden;
|
|
349
|
+
clip-path: inset(50%);
|
|
350
|
+
white-space: nowrap;
|
|
351
|
+
border: 0;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.sheetOption:has(.sheetOptionInput:focus-visible),
|
|
355
|
+
.sheetOption:focus-visible {
|
|
356
|
+
outline: 2px solid var(--vx-accent);
|
|
357
|
+
outline-offset: -2px;
|
|
358
|
+
border-radius: var(--vx-radius-ctrl);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.sheetOptionLabel {
|
|
362
|
+
flex: 1;
|
|
363
|
+
min-width: 0;
|
|
364
|
+
font-size: var(--vx-text-md);
|
|
365
|
+
overflow: hidden;
|
|
366
|
+
text-overflow: ellipsis;
|
|
367
|
+
white-space: nowrap;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
.sheetOptionCheck {
|
|
371
|
+
display: inline-flex;
|
|
372
|
+
flex: none;
|
|
373
|
+
align-items: center;
|
|
374
|
+
color: var(--vx-accent);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
.sheetDisclosureBody {
|
|
378
|
+
padding-bottom: var(--vx-space-stack-sm, 0.5rem);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/*
|
|
382
|
+
* The group heading — the package's MONO MICRO label (`docs/DESIGN-SPEC.md` §3), the same treatment
|
|
383
|
+
* `shell/app-sidebar.module.css`'s `.sectionLabel` draws for a nav section. It read as a head-font
|
|
384
|
+
* 13.5px line before, which is the same typography as the option rows it labels, so a group heading
|
|
385
|
+
* and its first option were indistinguishable — and the sheet's only remaining structure IS the
|
|
386
|
+
* heading, since it draws no rules between groups.
|
|
387
|
+
*/
|
|
388
|
+
.sheetLabel {
|
|
389
|
+
font-family: var(--basalt-font-mono);
|
|
390
|
+
font-size: var(--vx-text-micro);
|
|
391
|
+
font-weight: 500;
|
|
392
|
+
text-transform: uppercase;
|
|
393
|
+
letter-spacing: 0.08em;
|
|
394
|
+
color: var(--vx-faint);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/*
|
|
398
|
+
* The heading a `Radio.Group`/`Checkbox.Group` renders for itself (Mantine's `Input.Label`) — same
|
|
399
|
+
* typography as `.sheetLabel`, which is what the other sheet fields use. Both surfaces get it: in
|
|
400
|
+
* the popover it is the only place the filter's NAME appears (the pill reads the value), and in the
|
|
401
|
+
* sheet it replaces a `SheetField` heading that could never be programmatically associated —
|
|
402
|
+
* `Radio.Group` overwrites any `aria-labelledby` with its own.
|
|
403
|
+
*/
|
|
404
|
+
.groupLabel {
|
|
405
|
+
font-family: var(--basalt-font-head);
|
|
406
|
+
font-stretch: 88%;
|
|
407
|
+
font-weight: 550;
|
|
408
|
+
font-size: var(--vx-text-sm);
|
|
409
|
+
color: var(--vx-muted);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/* The sheet's `SheetField` heading sits 2px off its list — the mono micro step above is small
|
|
413
|
+
* enough that the default flow gap read as part of the first row. */
|
|
414
|
+
.sheetField > .sheetLabel {
|
|
415
|
+
margin-bottom: 2px;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/* 44px rows — the one sheet dimension C15 pins. */
|
|
419
|
+
.sheetRow {
|
|
420
|
+
display: flex;
|
|
421
|
+
align-items: center;
|
|
422
|
+
gap: var(--mantine-spacing-xs, 0.625rem);
|
|
423
|
+
min-height: var(--vx-space-sheet-row-height, 2.75rem);
|
|
424
|
+
width: 100%;
|
|
425
|
+
border-bottom: 1px solid var(--vx-surface-hairline);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
.sheetRow:last-child {
|
|
429
|
+
border-bottom: none;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/*
|
|
433
|
+
* A 44px row is only a 44px TOUCH TARGET if the `<label>` fills it. Mantine centres a Radio/Checkbox
|
|
434
|
+
* `body` in its root and the label line-height is ~20px, so without these the tappable strip is the
|
|
435
|
+
* middle 20px of the row and the outer 12px top and bottom do nothing (C15's number, not delivered).
|
|
436
|
+
* Passed through `classNames`, never as a global `.sheetRow label` selector — a descendant selector
|
|
437
|
+
* here would also capture a nested control's own labels.
|
|
438
|
+
*/
|
|
439
|
+
.sheetRowBody {
|
|
440
|
+
flex: 1;
|
|
441
|
+
align-items: center;
|
|
442
|
+
min-height: inherit;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
.sheetRowLabel {
|
|
446
|
+
display: flex;
|
|
447
|
+
flex: 1;
|
|
448
|
+
align-items: center;
|
|
449
|
+
min-height: inherit;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/* ── ControlGroup ─────────────────────────────────────────────────────────────────────────────── */
|
|
453
|
+
|
|
454
|
+
/*
|
|
455
|
+
* Adjacent controls joined into one box (`docs/CONTROLS-SPEC.md` §3, `control-group.tsx`).
|
|
456
|
+
*
|
|
457
|
+
* `flex: none` and `nowrap`: a joined set that wrapped would break in the middle of the box it is
|
|
458
|
+
* pretending to be, which is worse than overflowing. It is the same reasoning `.pillSlot` uses —
|
|
459
|
+
* a group is one unit for the purposes of the row's fold arithmetic.
|
|
460
|
+
*/
|
|
461
|
+
.group {
|
|
462
|
+
display: inline-flex;
|
|
463
|
+
align-items: center;
|
|
464
|
+
flex: none;
|
|
465
|
+
flex-wrap: nowrap;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
.group[data-gap='tight'] {
|
|
469
|
+
gap: var(--vx-space-control-gap, 0.375rem);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
.group[data-gap='none'] {
|
|
473
|
+
gap: 0;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/*
|
|
477
|
+
* The hairline BETWEEN two joined children is the one divider in the control tier, and it has to be
|
|
478
|
+
* drawn here because `cssVariablesResolver` points `--mantine-color-default-border` at `transparent`
|
|
479
|
+
* on purpose (depth is a shadow, `docs/DESIGN-SPEC.md` §8). Same 12%-ink value `.pill` uses, so a
|
|
480
|
+
* joined pill row and a joined button row read as the same family.
|
|
481
|
+
*
|
|
482
|
+
* Scoped to `[data-variant='default']` so a `filled` child keeps its fill edge: a border drawn on a
|
|
483
|
+
* filled button paints a rim in a colour that is neither the fill nor the surface.
|
|
484
|
+
*/
|
|
485
|
+
.group[data-gap='none'] > [data-variant='default'] {
|
|
486
|
+
border-color: color-mix(in srgb, var(--vx-ink) 12%, transparent);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/*
|
|
490
|
+
* `-1px` collapses the two adjacent 1px borders into ONE. Without it a joined pair carries a 2px
|
|
491
|
+
* rule down the middle, which reads as a gap that someone forgot to remove rather than as a divider.
|
|
492
|
+
*/
|
|
493
|
+
.group[data-gap='none'] > * + * {
|
|
494
|
+
margin-inline-start: -1px;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/*
|
|
498
|
+
* The radius lives on the OUTER ends only — that single rule is what turns three boxes into one box.
|
|
499
|
+
* `:only-child` is excluded on both ends so a one-child group (a conditional render that dropped the
|
|
500
|
+
* other two) keeps its normal shape instead of losing half its corners.
|
|
501
|
+
*/
|
|
502
|
+
.group[data-gap='none'] > *:not(:first-child):not(:last-child) {
|
|
503
|
+
border-radius: 0;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
.group[data-gap='none'] > *:first-child:not(:only-child) {
|
|
507
|
+
border-start-end-radius: 0;
|
|
508
|
+
border-end-end-radius: 0;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
.group[data-gap='none'] > *:last-child:not(:only-child) {
|
|
512
|
+
border-start-start-radius: 0;
|
|
513
|
+
border-end-start-radius: 0;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/*
|
|
517
|
+
* A hovered or focused child has to paint its FULL border, including the edge it is sharing — the
|
|
518
|
+
* negative margin means the next sibling is drawn over it otherwise, so a focus ring lost its right
|
|
519
|
+
* side and read as a rendering glitch. `position: relative` is what makes `z-index` apply.
|
|
520
|
+
*/
|
|
521
|
+
.group[data-gap='none'] > *:hover,
|
|
522
|
+
.group[data-gap='none'] > *:focus-visible,
|
|
523
|
+
.group[data-gap='none'] > *[data-active] {
|
|
524
|
+
position: relative;
|
|
525
|
+
z-index: 1;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/*
|
|
529
|
+
* `ViewTabs`' phone form past `PHONE_TRACK_MAX` options is a `Select`, and a Mantine input resolves
|
|
530
|
+
* its own width from its container — which in a `WidgetHeader`'s `actions` slot (a `flex: 0 0 auto`
|
|
531
|
+
* inline-flex box) came out at 216px. Measured on the playground's `Controls (mobile)` page at 390px:
|
|
532
|
+
* the section header's title row was 364px wide, the Select took 252px of it with the count tag, and
|
|
533
|
+
* `Customers` rendered as `Cust…`. A tab control that truncates the heading it sits beside has the
|
|
534
|
+
* priority backwards — the heading names the section, the tabs are one of its controls.
|
|
535
|
+
*
|
|
536
|
+
* The bound is the widest single option label plus the chevron, not a fraction of the row: it must be
|
|
537
|
+
* the same box regardless of what is to its left.
|
|
538
|
+
*/
|
|
539
|
+
.phoneSelect {
|
|
540
|
+
max-width: 9rem;
|
|
541
|
+
flex: 0 1 auto;
|
|
542
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed CSS-module declaration (the S4 CSS-modules path). Named string props — not an index
|
|
3
|
+
* signature — so dot access stays verbatim under the package's strict flags.
|
|
4
|
+
*/
|
|
5
|
+
declare const classes: {
|
|
6
|
+
readonly group: string
|
|
7
|
+
readonly pillRow: string
|
|
8
|
+
readonly pillSlot: string
|
|
9
|
+
readonly foldPill: string
|
|
10
|
+
readonly sheetPill: string
|
|
11
|
+
readonly pill: string
|
|
12
|
+
readonly pillIcon: string
|
|
13
|
+
readonly pillLabel: string
|
|
14
|
+
readonly glyph: string
|
|
15
|
+
readonly dropdown: string
|
|
16
|
+
readonly optionList: string
|
|
17
|
+
readonly sheetBody: string
|
|
18
|
+
readonly sheetHeader: string
|
|
19
|
+
readonly sheetTitle: string
|
|
20
|
+
readonly sheetTitleText: string
|
|
21
|
+
readonly sheetField: string
|
|
22
|
+
readonly sheetList: string
|
|
23
|
+
readonly sheetOption: string
|
|
24
|
+
readonly sheetDisclosureBody: string
|
|
25
|
+
readonly sheetOptionInput: string
|
|
26
|
+
readonly sheetOptionLabel: string
|
|
27
|
+
readonly sheetOptionCheck: string
|
|
28
|
+
readonly sheetLabel: string
|
|
29
|
+
readonly groupLabel: string
|
|
30
|
+
readonly sheetRow: string
|
|
31
|
+
readonly sheetRowBody: string
|
|
32
|
+
readonly sheetRowLabel: string
|
|
33
|
+
readonly phoneSelect: string
|
|
34
|
+
}
|
|
35
|
+
export default classes
|