basalt-ui 1.25.0 → 1.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +8 -6
- package/CHANGELOG.md +26 -0
- package/MIGRATING.md +815 -23
- package/README.md +45 -32
- package/agent/rules/basalt-batteries.md +205 -0
- package/agent/rules/basalt-charts.md +125 -555
- package/agent/rules/basalt-controls.md +160 -0
- package/agent/rules/basalt-mantine.md +146 -439
- package/agent/rules/basalt-state.md +118 -96
- package/agent/rules/basalt-tokens.md +126 -288
- package/agent/skills/basalt-app/SKILL.md +70 -195
- package/agent/skills/basalt-charts/SKILL.md +54 -234
- package/agent/skills/basalt-design/SKILL.md +56 -248
- package/agent/templates/CLAUDE-block.md.tpl +31 -40
- package/agent/templates/DESIGN.md.tpl +22 -51
- package/configs/oxlint-plugin.js +1465 -36
- package/configs/oxlint-plugin.test.ts +1190 -11
- package/configs/oxlint.json +11 -3
- package/dist/charts/cursor/resolve.d.ts +18 -0
- package/dist/charts/cursor/resolve.d.ts.map +1 -1
- package/dist/charts/cursor/resolve.js +15 -6
- package/dist/charts/cursor/scope.d.ts +6 -3
- package/dist/charts/cursor/scope.d.ts.map +1 -1
- package/dist/charts/cursor/store.d.ts +5 -1
- package/dist/charts/cursor/store.d.ts.map +1 -1
- package/dist/charts/cursor/store.js +4 -4
- package/dist/charts/hooks/useChartCursor.d.ts.map +1 -1
- package/dist/charts/hooks/useChartCursor.js +9 -8
- package/dist/charts/index.d.ts +2 -2
- package/dist/charts/index.d.ts.map +1 -1
- package/dist/charts/primitives/ChartCard.d.ts +34 -9
- package/dist/charts/primitives/ChartCard.d.ts.map +1 -1
- package/dist/charts/primitives/ChartCard.js +29 -114
- package/dist/charts/primitives/ChartCard.test.d.ts +2 -0
- package/dist/charts/primitives/ChartCard.test.d.ts.map +1 -0
- package/dist/charts/sparklines/BarSparkline.d.ts +26 -2
- package/dist/charts/sparklines/BarSparkline.d.ts.map +1 -1
- package/dist/charts/sparklines/BarSparkline.js +18 -4
- package/dist/cli/check-coverage.test.d.ts +2 -0
- package/dist/cli/check-coverage.test.d.ts.map +1 -0
- package/dist/cli/index.d.ts +67 -4
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +225 -7
- package/dist/connectivity/connectivity-indicator.d.ts +4 -1
- package/dist/connectivity/connectivity-indicator.d.ts.map +1 -1
- package/dist/connectivity/connectivity-indicator.js +1 -1
- package/dist/content/index.d.ts +5 -3
- package/dist/content/index.d.ts.map +1 -1
- package/dist/content/index.js +4 -2
- package/dist/content/prose.module.css +7 -28
- package/dist/controls/actions.d.ts +169 -0
- package/dist/controls/actions.d.ts.map +1 -0
- package/dist/controls/actions.js +287 -0
- package/dist/controls/actions.module.css +62 -0
- package/dist/controls/actions.module.css.d.ts +13 -0
- package/dist/controls/actions.test.d.ts +2 -0
- package/dist/controls/actions.test.d.ts.map +1 -0
- package/dist/controls/actions.type-guard.test.d.ts +2 -0
- package/dist/controls/actions.type-guard.test.d.ts.map +1 -0
- package/dist/controls/compare-filter.d.ts +41 -0
- package/dist/controls/compare-filter.d.ts.map +1 -0
- package/dist/controls/compare-filter.js +23 -0
- package/dist/controls/control-group.d.ts +19 -0
- package/dist/controls/control-group.d.ts.map +1 -0
- package/dist/controls/control-group.js +20 -0
- package/dist/controls/control-group.test.d.ts +2 -0
- package/dist/controls/control-group.test.d.ts.map +1 -0
- package/dist/controls/controls.module.css +542 -0
- package/dist/controls/controls.module.css.d.ts +35 -0
- package/dist/controls/controls.router.test.d.ts +2 -0
- package/dist/controls/controls.router.test.d.ts.map +1 -0
- package/dist/controls/enum-filter.d.ts +39 -0
- package/dist/controls/enum-filter.d.ts.map +1 -0
- package/dist/controls/enum-filter.js +93 -0
- package/dist/controls/filter-context.d.ts +60 -0
- package/dist/controls/filter-context.d.ts.map +1 -0
- package/dist/controls/filter-context.js +69 -0
- package/dist/controls/filter-pill.d.ts +28 -0
- package/dist/controls/filter-pill.d.ts.map +1 -0
- package/dist/controls/filter-pill.js +70 -0
- package/dist/controls/filter-set.d.ts +13 -0
- package/dist/controls/filter-set.d.ts.map +1 -0
- package/dist/controls/filter-set.js +125 -0
- package/dist/controls/filter-set.test.d.ts +2 -0
- package/dist/controls/filter-set.test.d.ts.map +1 -0
- package/dist/controls/filter-sheet.d.ts +117 -0
- package/dist/controls/filter-sheet.d.ts.map +1 -0
- package/dist/controls/filter-sheet.js +146 -0
- package/dist/controls/glyphs.d.ts +27 -0
- package/dist/controls/glyphs.d.ts.map +1 -0
- package/dist/controls/glyphs.js +49 -0
- package/dist/controls/index.d.ts +20 -0
- package/dist/controls/index.d.ts.map +1 -0
- package/dist/controls/index.js +46 -0
- package/dist/controls/multi-select-filter.d.ts +23 -0
- package/dist/controls/multi-select-filter.d.ts.map +1 -0
- package/dist/controls/multi-select-filter.js +89 -0
- package/dist/controls/number-filter.d.ts +26 -0
- package/dist/controls/number-filter.d.ts.map +1 -0
- package/dist/controls/number-filter.js +143 -0
- package/dist/controls/peer-boundary.test.d.ts +2 -0
- package/dist/controls/peer-boundary.test.d.ts.map +1 -0
- package/dist/controls/props-contract.test.d.ts +2 -0
- package/dist/controls/props-contract.test.d.ts.map +1 -0
- package/dist/controls/range-filter.d.ts +43 -0
- package/dist/controls/range-filter.d.ts.map +1 -0
- package/dist/controls/range-filter.js +135 -0
- package/dist/controls/range-filter.type-guard.test.d.ts +2 -0
- package/dist/controls/range-filter.type-guard.test.d.ts.map +1 -0
- package/dist/controls/search-filter.d.ts +10 -0
- package/dist/controls/search-filter.d.ts.map +1 -0
- package/dist/controls/search-filter.js +81 -0
- package/dist/controls/select-filter.d.ts +74 -0
- package/dist/controls/select-filter.d.ts.map +1 -0
- package/dist/controls/select-filter.js +10 -0
- package/dist/controls/sync-button.d.ts +38 -0
- package/dist/controls/sync-button.d.ts.map +1 -0
- package/dist/controls/sync-button.js +119 -0
- package/dist/controls/sync-button.module.css +63 -0
- package/dist/controls/sync-button.module.css.d.ts +11 -0
- package/dist/controls/sync-button.test.d.ts +2 -0
- package/dist/controls/sync-button.test.d.ts.map +1 -0
- package/dist/controls/toggle-filter.d.ts +9 -0
- package/dist/controls/toggle-filter.d.ts.map +1 -0
- package/dist/controls/toggle-filter.js +42 -0
- package/dist/controls/view-tabs.d.ts +23 -0
- package/dist/controls/view-tabs.d.ts.map +1 -0
- package/dist/controls/view-tabs.js +59 -0
- package/dist/controls-dates/date-range-picker.d.ts +4 -0
- package/dist/controls-dates/date-range-picker.d.ts.map +1 -0
- package/dist/controls-dates/date-range-picker.js +18 -0
- package/dist/controls-dates/index.d.ts +9 -0
- package/dist/controls-dates/index.d.ts.map +1 -0
- package/dist/controls-dates/index.js +4 -0
- package/dist/dashboard/delta-badge.d.ts +6 -12
- package/dist/dashboard/delta-badge.d.ts.map +1 -1
- package/dist/dashboard/delta-badge.js +1 -50
- package/dist/dashboard/index.d.ts +1 -1
- package/dist/dashboard/index.d.ts.map +1 -1
- package/dist/dashboard/index.js +3 -1
- package/dist/dashboard/settings-section.d.ts +6 -4
- package/dist/dashboard/settings-section.d.ts.map +1 -1
- package/dist/dashboard/settings-section.js +23 -16
- package/dist/dashboard/settings-section.module.css +10 -0
- package/dist/dashboard/settings-section.module.css.d.ts +1 -0
- package/dist/dashboard/settings-section.test.d.ts +2 -0
- package/dist/dashboard/settings-section.test.d.ts.map +1 -0
- package/dist/dashboard/stat-card.d.ts +95 -9
- package/dist/dashboard/stat-card.d.ts.map +1 -1
- package/dist/dashboard/stat-card.js +108 -49
- package/dist/dashboard/stat-card.module.css +153 -0
- package/dist/dashboard/stat-card.module.css.d.ts +15 -0
- package/dist/data/data-table.d.ts +37 -15
- package/dist/data/data-table.d.ts.map +1 -1
- package/dist/data/data-table.js +96 -58
- package/dist/guard/grace.test.d.ts +20 -0
- package/dist/guard/grace.test.d.ts.map +1 -0
- package/dist/guard/index.d.ts +66 -3
- package/dist/guard/index.d.ts.map +1 -1
- package/dist/guard/index.js +78 -7
- package/dist/guard/types.d.ts +3 -3
- package/dist/guard/types.d.ts.map +1 -1
- package/dist/index.d.ts +13 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -10
- package/dist/nav/types.d.ts +78 -2
- package/dist/nav/types.d.ts.map +1 -1
- package/dist/notifications/bell.d.ts +4 -1
- package/dist/notifications/bell.d.ts.map +1 -1
- package/dist/notifications/index.d.ts +1 -1
- package/dist/router-tanstack/field.d.ts +14 -0
- package/dist/router-tanstack/field.d.ts.map +1 -0
- package/dist/router-tanstack/field.js +4 -0
- package/dist/router-tanstack/index.d.ts +6 -2
- package/dist/router-tanstack/index.d.ts.map +1 -1
- package/dist/router-tanstack/index.js +4 -0
- package/dist/router-tanstack/multi-search-param-store.d.ts +4 -52
- package/dist/router-tanstack/multi-search-param-store.d.ts.map +1 -1
- package/dist/router-tanstack/multi-search-param-store.js +19 -27
- package/dist/router-tanstack/search-param-store.d.ts +3 -87
- package/dist/router-tanstack/search-param-store.d.ts.map +1 -1
- package/dist/router-tanstack/search-param-store.js +16 -45
- package/dist/router-tanstack/search-store.d.ts +84 -0
- package/dist/router-tanstack/search-store.d.ts.map +1 -0
- package/dist/router-tanstack/search-store.js +271 -0
- package/dist/router-tanstack/search-store.router.test.d.ts +2 -0
- package/dist/router-tanstack/search-store.router.test.d.ts.map +1 -0
- package/dist/router-tanstack/search-store.test.d.ts +2 -0
- package/dist/router-tanstack/search-store.test.d.ts.map +1 -0
- package/dist/router-tanstack/use-nav.d.ts +0 -2
- package/dist/router-tanstack/use-nav.d.ts.map +1 -1
- package/dist/router-tanstack/use-nav.js +34 -12
- package/dist/router-tanstack/use-nav.test.d.ts +2 -0
- package/dist/router-tanstack/use-nav.test.d.ts.map +1 -0
- package/dist/section/index.d.ts +2 -0
- package/dist/section/index.d.ts.map +1 -0
- package/dist/section/index.js +4 -0
- package/dist/section/section.d.ts +24 -0
- package/dist/section/section.d.ts.map +1 -0
- package/dist/section/section.js +126 -0
- package/dist/section/section.module.css +104 -0
- package/dist/section/section.module.css.d.ts +11 -0
- package/dist/section/section.test.d.ts +2 -0
- package/dist/section/section.test.d.ts.map +1 -0
- package/dist/shell/app-breadcrumbs.d.ts.map +1 -1
- package/dist/shell/app-breadcrumbs.js +18 -15
- package/dist/shell/app-header.module.css +77 -37
- package/dist/shell/app-header.module.css.d.ts +2 -1
- package/dist/shell/app-mobile-nav.d.ts +9 -2
- package/dist/shell/app-mobile-nav.d.ts.map +1 -1
- package/dist/shell/app-mobile-nav.js +98 -11
- package/dist/shell/app-mobile-nav.module.css +8 -0
- package/dist/shell/app-mobile-nav.module.css.d.ts +1 -0
- package/dist/shell/app-sidebar.d.ts +55 -28
- package/dist/shell/app-sidebar.d.ts.map +1 -1
- package/dist/shell/app-sidebar.js +116 -67
- package/dist/shell/app-sidebar.module.css +303 -20
- package/dist/shell/app-sidebar.module.css.d.ts +19 -1
- package/dist/shell/index.d.ts +55 -21
- package/dist/shell/index.d.ts.map +1 -1
- package/dist/shell/index.js +40 -18
- package/dist/shell/mobile-nav-model.d.ts +13 -2
- package/dist/shell/mobile-nav-model.d.ts.map +1 -1
- package/dist/shell/mobile-nav-model.js +15 -1
- package/dist/shell/nav-count-badge.d.ts +1 -1
- package/dist/shell/page-bar.d.ts +51 -0
- package/dist/shell/page-bar.d.ts.map +1 -0
- package/dist/shell/page-bar.js +154 -0
- package/dist/shell/page-bar.module.css +178 -0
- package/dist/shell/page-bar.module.css.d.ts +17 -0
- package/dist/shell/page-bar.test.d.ts +2 -0
- package/dist/shell/page-bar.test.d.ts.map +1 -0
- package/dist/shell/sidebar-block-model.d.ts +48 -0
- package/dist/shell/sidebar-block-model.d.ts.map +1 -0
- package/dist/shell/sidebar-block-model.js +39 -0
- package/dist/shell/sidebar-blocks.d.ts +32 -0
- package/dist/shell/sidebar-blocks.d.ts.map +1 -0
- package/dist/shell/sidebar-blocks.js +169 -0
- package/dist/shell/sidebar-search.d.ts +13 -1
- package/dist/shell/sidebar-search.d.ts.map +1 -1
- package/dist/shell/sidebar-search.js +34 -1
- package/dist/shell/sidebar-search.module.css +26 -0
- package/dist/shell/sidebar-search.module.css.d.ts +2 -0
- package/dist/state/fields.d.ts +565 -0
- package/dist/state/fields.d.ts.map +1 -0
- package/dist/state/fields.js +405 -0
- package/dist/state/fields.test.d.ts +2 -0
- package/dist/state/fields.test.d.ts.map +1 -0
- package/dist/state/persisted.d.ts +60 -0
- package/dist/state/persisted.d.ts.map +1 -0
- package/dist/state/persisted.js +123 -0
- package/dist/state/persisted.test.d.ts +2 -0
- package/dist/state/persisted.test.d.ts.map +1 -0
- package/dist/state.d.ts +11 -56
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +14 -120
- package/dist/styles.css +13 -0
- package/dist/surfaces.d.ts +106 -24
- package/dist/surfaces.d.ts.map +1 -1
- package/dist/surfaces.js +156 -19
- package/dist/theme/controls.module.css +16 -1
- package/dist/theme/ctl-theme.d.ts +32 -0
- package/dist/theme/ctl-theme.d.ts.map +1 -0
- package/dist/theme/ctl-theme.js +54 -0
- package/dist/theme/ctl-theme.test.d.ts +2 -0
- package/dist/theme/ctl-theme.test.d.ts.map +1 -0
- package/dist/theme/ctl-tier-coverage.test.d.ts +2 -0
- package/dist/theme/ctl-tier-coverage.test.d.ts.map +1 -0
- package/dist/theme/divider-law.test.d.ts +2 -0
- package/dist/theme/divider-law.test.d.ts.map +1 -0
- package/dist/theme/icon-slot.d.ts +44 -0
- package/dist/theme/icon-slot.d.ts.map +1 -0
- package/dist/theme/icon-slot.js +21 -0
- package/dist/theme/icon-slot.module.css +47 -0
- package/dist/theme/icon-slot.module.css.d.ts +8 -0
- package/dist/theme/icon-slot.test.d.ts +2 -0
- package/dist/theme/icon-slot.test.d.ts.map +1 -0
- package/dist/theme/index.d.ts +1 -0
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/index.js +82 -5
- package/dist/theme/layout-rhythm-css.test.d.ts +2 -0
- package/dist/theme/layout-rhythm-css.test.d.ts.map +1 -0
- package/dist/theme/segmented-control.module.css +20 -0
- package/dist/theme/shadow-surfaces.test.d.ts.map +1 -1
- package/dist/tokens/index.d.ts +12 -0
- package/dist/tokens/index.d.ts.map +1 -1
- package/dist/tokens/index.js +38 -8
- package/dist/tokens/palette.d.ts +97 -61
- package/dist/tokens/palette.d.ts.map +1 -1
- package/dist/tokens/palette.js +76 -38
- package/dist/tokens.css +10 -2
- package/dist/widget-header/delta-badge.d.ts +13 -0
- package/dist/widget-header/delta-badge.d.ts.map +1 -0
- package/dist/widget-header/delta-badge.js +29 -0
- package/dist/widget-header/delta-badge.test.d.ts +2 -0
- package/dist/widget-header/delta-badge.test.d.ts.map +1 -0
- package/dist/widget-header/index.d.ts +3 -0
- package/dist/widget-header/index.d.ts.map +1 -0
- package/dist/widget-header/index.js +6 -0
- package/dist/widget-header/no-mantine.test.d.ts +2 -0
- package/dist/widget-header/no-mantine.test.d.ts.map +1 -0
- package/dist/widget-header/widget-header.d.ts +67 -0
- package/dist/widget-header/widget-header.d.ts.map +1 -0
- package/dist/widget-header/widget-header.js +89 -0
- package/dist/widget-header/widget-header.module.css +350 -0
- package/dist/widget-header/widget-header.module.css.d.ts +25 -0
- package/dist/widget-header/widget-header.test.d.ts +2 -0
- package/dist/widget-header/widget-header.test.d.ts.map +1 -0
- package/llms.txt +30 -17
- package/package.json +14 -1
- package/src/charts/cursor/resolve.test.ts +29 -1
- package/src/charts/cursor/resolve.ts +38 -6
- package/src/charts/cursor/scope.tsx +6 -3
- package/src/charts/cursor/store.test.ts +19 -1
- package/src/charts/cursor/store.ts +10 -5
- package/src/charts/hooks/useChartCursor.ts +16 -8
- package/src/charts/index.ts +2 -2
- package/src/charts/primitives/CartesianChart.test.tsx +124 -0
- package/src/charts/primitives/ChartCard.test.tsx +66 -0
- package/src/charts/primitives/ChartCard.tsx +86 -146
- package/src/charts/sparklines/BarSparkline.tsx +43 -5
- package/src/cli/check-coverage.test.ts +297 -0
- package/src/cli/check-theme.test.ts +38 -14
- package/src/cli/index.ts +392 -16
- package/src/cli/init-sync.test.ts +97 -0
- package/src/connectivity/connectivity-indicator.tsx +16 -9
- package/src/content/index.ts +16 -3
- package/src/content/prose.module.css +7 -28
- package/src/content/prose.module.css.test.ts +8 -24
- package/src/controls/actions.module.css +62 -0
- package/src/controls/actions.module.css.d.ts +13 -0
- package/src/controls/actions.test.tsx +252 -0
- package/src/controls/actions.tsx +655 -0
- package/src/controls/actions.type-guard.test.ts +63 -0
- package/src/controls/compare-filter.tsx +64 -0
- package/src/controls/control-group.test.tsx +229 -0
- package/src/controls/control-group.tsx +63 -0
- package/src/controls/controls.module.css +542 -0
- package/src/controls/controls.module.css.d.ts +35 -0
- package/src/controls/controls.router.test.tsx +1053 -0
- package/src/controls/enum-filter.tsx +170 -0
- package/src/controls/filter-context.tsx +158 -0
- package/src/controls/filter-pill.tsx +120 -0
- package/src/controls/filter-set.test.tsx +472 -0
- package/src/controls/filter-set.tsx +225 -0
- package/src/controls/filter-sheet.tsx +285 -0
- package/src/controls/glyphs.tsx +81 -0
- package/src/controls/index.ts +49 -0
- package/src/controls/multi-select-filter.tsx +140 -0
- package/src/controls/number-filter.tsx +291 -0
- package/src/controls/peer-boundary.test.ts +85 -0
- package/src/controls/props-contract.test.tsx +137 -0
- package/src/controls/range-filter.tsx +237 -0
- package/src/controls/range-filter.type-guard.test.tsx +122 -0
- package/src/controls/search-filter.tsx +123 -0
- package/src/controls/select-filter.tsx +89 -0
- package/src/controls/sync-button.module.css +63 -0
- package/src/controls/sync-button.module.css.d.ts +11 -0
- package/src/controls/sync-button.test.tsx +183 -0
- package/src/controls/sync-button.tsx +197 -0
- package/src/controls/toggle-filter.tsx +60 -0
- package/src/controls/view-tabs.tsx +110 -0
- package/src/controls-dates/date-range-picker.tsx +42 -0
- package/src/controls-dates/index.ts +8 -0
- package/src/dashboard/delta-badge.tsx +4 -74
- package/src/dashboard/index.ts +6 -1
- package/src/dashboard/settings-section.module.css +10 -0
- package/src/dashboard/settings-section.module.css.d.ts +1 -0
- package/src/dashboard/settings-section.test.tsx +56 -0
- package/src/dashboard/settings-section.tsx +33 -30
- package/src/dashboard/stat-card.module.css +153 -0
- package/src/dashboard/stat-card.module.css.d.ts +15 -0
- package/src/dashboard/stat-card.test.tsx +298 -1
- package/src/dashboard/stat-card.tsx +289 -67
- package/src/data/data-table.test.tsx +96 -11
- package/src/data/data-table.tsx +228 -84
- package/src/guard/check-source.test.ts +159 -13
- package/src/guard/grace.test.ts +158 -0
- package/src/guard/index.ts +185 -29
- package/src/guard/types.ts +4 -2
- package/src/index.ts +51 -5
- package/src/nav/types.ts +84 -2
- package/src/notifications/bell.tsx +6 -3
- package/src/notifications/index.ts +1 -1
- package/src/router-tanstack/field.ts +35 -0
- package/src/router-tanstack/index.ts +28 -2
- package/src/router-tanstack/multi-search-param-store.test.ts +71 -3
- package/src/router-tanstack/multi-search-param-store.ts +46 -77
- package/src/router-tanstack/search-param-store.ts +42 -159
- package/src/router-tanstack/search-store.router.test.tsx +882 -0
- package/src/router-tanstack/search-store.test.ts +578 -0
- package/src/router-tanstack/search-store.ts +546 -0
- package/src/router-tanstack/use-nav.test.tsx +187 -0
- package/src/router-tanstack/use-nav.ts +72 -14
- package/src/section/index.ts +1 -0
- package/src/section/section.module.css +104 -0
- package/src/section/section.module.css.d.ts +11 -0
- package/src/section/section.test.tsx +204 -0
- package/src/section/section.tsx +220 -0
- package/src/shell/app-breadcrumbs.tsx +44 -31
- package/src/shell/app-header.module.css +77 -37
- package/src/shell/app-header.module.css.d.ts +2 -1
- package/src/shell/app-mobile-nav.module.css +8 -0
- package/src/shell/app-mobile-nav.module.css.d.ts +1 -0
- package/src/shell/app-mobile-nav.tsx +147 -8
- package/src/shell/app-sidebar-account.tsx +2 -2
- package/src/shell/app-sidebar.module.css +303 -20
- package/src/shell/app-sidebar.module.css.d.ts +19 -1
- package/src/shell/app-sidebar.test.tsx +456 -41
- package/src/shell/app-sidebar.tsx +276 -140
- package/src/shell/index.test.tsx +291 -5
- package/src/shell/index.tsx +137 -38
- package/src/shell/mobile-nav-model.test.ts +228 -7
- package/src/shell/mobile-nav-model.ts +53 -3
- package/src/shell/nav-count-badge.tsx +1 -1
- package/src/shell/page-bar.module.css +178 -0
- package/src/shell/page-bar.module.css.d.ts +17 -0
- package/src/shell/page-bar.test.tsx +316 -0
- package/src/shell/page-bar.tsx +315 -0
- package/src/shell/sidebar-block-model.ts +83 -0
- package/src/shell/sidebar-blocks.tsx +301 -0
- package/src/shell/sidebar-search.module.css +26 -0
- package/src/shell/sidebar-search.module.css.d.ts +2 -0
- package/src/shell/sidebar-search.tsx +71 -2
- package/src/state/fields.test.tsx +512 -0
- package/src/state/fields.ts +1150 -0
- package/src/state/persisted.test.ts +91 -0
- package/src/state/persisted.ts +261 -0
- package/src/state.ts +52 -240
- package/src/styles.css +13 -0
- package/src/surfaces.ts +204 -36
- package/src/theme/controls.module.css +16 -1
- package/src/theme/ctl-theme.test.tsx +275 -0
- package/src/theme/ctl-theme.tsx +138 -0
- package/src/theme/ctl-tier-coverage.test.ts +170 -0
- package/src/theme/density-relations.test.ts +106 -51
- package/src/theme/divider-law.test.ts +259 -0
- package/src/theme/icon-slot.module.css +47 -0
- package/src/theme/icon-slot.module.css.d.ts +8 -0
- package/src/theme/icon-slot.test.tsx +275 -0
- package/src/theme/icon-slot.tsx +59 -0
- package/src/theme/index.ts +165 -3
- package/src/theme/layout-rhythm-css.test.ts +72 -0
- package/src/theme/radius.test.ts +11 -1
- package/src/theme/segmented-control.module.css +20 -0
- package/src/theme/shadow-surfaces.test.ts +20 -7
- package/src/theme/spacing.test.ts +75 -27
- package/src/theme/use-basalt-spacing.ts +2 -2
- package/src/tokens/density.test.ts +7 -25
- package/src/tokens/index.ts +48 -8
- package/src/tokens/palette.ts +107 -73
- package/src/widget-header/delta-badge.test.tsx +60 -0
- package/src/widget-header/delta-badge.tsx +57 -0
- package/src/widget-header/index.ts +2 -0
- package/src/widget-header/no-mantine.test.ts +33 -0
- package/src/widget-header/widget-header.module.css +350 -0
- package/src/widget-header/widget-header.module.css.d.ts +25 -0
- package/src/widget-header/widget-header.test.tsx +187 -0
- package/src/widget-header/widget-header.tsx +213 -0
- package/agent/rules/basalt-agent.md +0 -452
- package/agent/rules/basalt-app.md +0 -246
- package/agent/rules/basalt-commands.md +0 -320
- package/agent/rules/basalt-content.md +0 -409
- package/agent/rules/basalt-data.md +0 -329
- package/agent/rules/basalt-forms.md +0 -186
- package/agent/rules/basalt-notifications.md +0 -264
- package/agent/rules/basalt-query.md +0 -187
- package/agent/rules/basalt-router.md +0 -336
- package/dist/content/article-filter-bar.d.ts +0 -40
- package/dist/content/article-filter-bar.d.ts.map +0 -1
- package/dist/content/article-filter-bar.js +0 -56
- package/dist/shell/page-header.d.ts +0 -13
- package/dist/shell/page-header.d.ts.map +0 -1
- package/dist/shell/page-header.js +0 -23
- package/src/content/article-filter-bar.tsx +0 -88
- package/src/shell/page-header.tsx +0 -35
package/dist/tokens/palette.js
CHANGED
|
@@ -158,7 +158,24 @@ const SPACE_ANCHORS_BASE = {
|
|
|
158
158
|
* (both read {@link CONTROL_HEIGHT_BASE}), so a Button/ActionIcon placed beside a `size="md"`
|
|
159
159
|
* Input tracks it at every density level instead of only coinciding at level 0 (the defect this
|
|
160
160
|
* anchor fixes — Mantine's own `--button-height-md`/`--ai-size` are static, density-blind). */
|
|
161
|
-
controlHeight: CONTROL_HEIGHT_BASE
|
|
161
|
+
controlHeight: CONTROL_HEIGHT_BASE,
|
|
162
|
+
/** The `size="icon"` count-tag height (`docs/CONTROLS-SPEC.md` §5) — inline chip / table-cell
|
|
163
|
+
* count badge. Floored at 18px in {@link deriveSpacing} (same "negative level can't collapse a
|
|
164
|
+
* real control below a legible/tappable minimum" reasoning as `sidebarSearchTriggerHeight`'s WCAG
|
|
165
|
+
* floor, one notch tighter since a count tag is a badge, not a primary interactive target). */
|
|
166
|
+
controlHeightTag: 20,
|
|
167
|
+
/** The `size="icon"` ActionIcon height (`docs/CONTROLS-SPEC.md` §5) — `WidgetHeader
|
|
168
|
+
* tier="widget"` actions. Floored at 22px in {@link deriveSpacing}. */
|
|
169
|
+
controlHeightWidget: 24,
|
|
170
|
+
/** The `size="ctl"` Mantine tier's resolved height (`docs/CONTROLS-SPEC.md` §5, C5) —
|
|
171
|
+
* `PageBar`/`Section`/table toolbar/sidebar-block controls. Floored at 28px in
|
|
172
|
+
* {@link deriveSpacing}. */
|
|
173
|
+
controlHeightCtl: 30,
|
|
174
|
+
/** The touch hit-area size (`::before`) every home control expands to below `sm` (C15,
|
|
175
|
+
* `docs/CONTROLS-SPEC.md` §5) — independent of the visible `controlHeightCtl` box, same shape as
|
|
176
|
+
* `mobileNavBarHeight`/`mobileNavRowHeight`'s Apple HIG 44pt / WCAG 2.5.5 floors elsewhere in this
|
|
177
|
+
* table. Floored at 30px in {@link deriveSpacing} (C15's "floor 30 at density −3"). */
|
|
178
|
+
touchControlHeight: 36
|
|
162
179
|
};
|
|
163
180
|
const SPACE_SCALE_BASE = {
|
|
164
181
|
xs: 11,
|
|
@@ -171,14 +188,13 @@ const SPACE_STEP_BASE = {
|
|
|
171
188
|
/** Timeline `defaultProps.bulletSize`. */
|
|
172
189
|
timelineBullet: 22,
|
|
173
190
|
// ── Shared across ≥2 sites (structural — must render at the same value) ──────────────────────
|
|
174
|
-
// `stickyHeaderClearance
|
|
175
|
-
//
|
|
176
|
-
//
|
|
177
|
-
//
|
|
178
|
-
//
|
|
179
|
-
//
|
|
180
|
-
//
|
|
181
|
-
// still carries both keys — see that type's own doc — they're just not part of this BASE table.
|
|
191
|
+
// `stickyHeaderClearance` USED to live here as an independent base literal (84) — it doesn't any
|
|
192
|
+
// more. It is DERIVED, post-`step`, from the AppShell header it exists to clear
|
|
193
|
+
// (`appShellHeaderHeight` below) instead (see {@link deriveSpacing}'s doc for why): an independent
|
|
194
|
+
// literal could drift from that header, which is exactly what happened. `SpaceValues.step` still
|
|
195
|
+
// carries the key — see that type's own doc — it is just not part of this BASE table. The
|
|
196
|
+
// `stickyHeaderClearanceMobile` sibling went with the two-row mobile header in 1.26.0: the header
|
|
197
|
+
// is one 48px row at every viewport now, so one clearance covers both.
|
|
182
198
|
/** NavLink leftSection icon-to-label gap — shared by `theme/nav-link.module.css` (every render
|
|
183
199
|
* path) and `shell/app-sidebar.module.css`'s own `.link` rule (belt-and-suspenders on the same
|
|
184
200
|
* DOM), and reused verbatim for `.footerBtn`/`.accountRow`'s icon gap (their own doc comments call
|
|
@@ -375,35 +391,28 @@ const SPACE_STEP_BASE = {
|
|
|
375
391
|
sidebarAccountMenuWidth: 220,
|
|
376
392
|
/** Settings-menu `<Menu width={…}>` (`app-sidebar.tsx`). */
|
|
377
393
|
sidebarSettingsMenuWidth: 200,
|
|
378
|
-
// ── shell/app-header.module.css ───────────────────────────────────────────────────────────────
|
|
379
|
-
/** Mobile two-row header's page-actions row height. */
|
|
380
|
-
appHeaderMobileActionsHeight: 52,
|
|
381
394
|
// ── shell/index.tsx (AppShell dimensions) ──────────────────────────────────────────────
|
|
382
395
|
/** AppShell desktop header bar height — sized to hold one row of `size="md"` controls, so it
|
|
383
396
|
* tracks `controlHeight`. Its level-0 coincidence with `appShellNavbarRailWidth` below is a
|
|
384
397
|
* coincidence, not a law: this is a horizontal bar's HEIGHT (governed by control height), that
|
|
385
398
|
* is a vertical rail's WIDTH (governed by icon footprint). They stay separate entries. */
|
|
399
|
+
/** AppShell header bar height — ONE value at every viewport since 1.26.0 (law C14,
|
|
400
|
+
* `docs/CONTROLS-SPEC.md` §2.1). The pre-1.26.0 `appShellHeaderMobileHeight` (97) existed only
|
|
401
|
+
* because the mobile header wrapped to a second, always-reserved page-actions row; `PageBar`
|
|
402
|
+
* folds that row's overflow into a kebab and moves its filters/tabs into the page flow, so the
|
|
403
|
+
* bar is 48px on a phone too and there is no sum to keep in step any more. */
|
|
386
404
|
appShellHeaderHeight: 48,
|
|
387
|
-
/** AppShell
|
|
388
|
-
*
|
|
389
|
-
*
|
|
390
|
-
* budget collapses 52px -> 12px across the level range.
|
|
405
|
+
/** AppShell navbar width, expanded — ONE entry for both the `base` (mobile, where the navbar is
|
|
406
|
+
* permanently collapsed and unused — see `MobileNav`) and the expanded `sm` value: the same
|
|
407
|
+
* `.root` at full width, genuinely one concept.
|
|
391
408
|
*
|
|
392
|
-
*
|
|
393
|
-
*
|
|
394
|
-
*
|
|
395
|
-
*
|
|
396
|
-
*
|
|
397
|
-
*
|
|
398
|
-
|
|
399
|
-
* `stickyHeaderClearance*` already is — post-`step`, from its own addends rather than as an
|
|
400
|
-
* independent literal — would make the drift impossible instead of merely re-tuned. That is the
|
|
401
|
-
* same refactor, and the same reasoning, this PR applied to the clearances; it is worth doing to
|
|
402
|
-
* this one too, and it stays a follow-up only because it moves every non-zero level's value. */
|
|
403
|
-
appShellHeaderMobileHeight: 97,
|
|
404
|
-
/** AppShell navbar width, expanded — ONE entry for both the `base` (mobile drawer) and the
|
|
405
|
-
* expanded `sm` value: the same `.root` at full width, genuinely one concept. */
|
|
406
|
-
appShellNavbarWidth: 216,
|
|
409
|
+
* 256, up from 216. At 216 the column was 196px of usable text after `.root`'s 10px inset a side,
|
|
410
|
+
* and the sidebar carries more than nav rows: a block row is `label · meta`, an account row is
|
|
411
|
+
* `avatar · name · plan`, and a `Recents` entry is a sentence. Every one of them was ellipsizing
|
|
412
|
+
* in the second word. 256 is also the width the shell's own dropdowns already assume
|
|
413
|
+
* (`sidebarAccountMenuWidth` 220 + the row inset), so the menu no longer overhangs the column it
|
|
414
|
+
* belongs to. */
|
|
415
|
+
appShellNavbarWidth: 256,
|
|
407
416
|
/** AppShell navbar width, collapsed icon rail. Separate from `appShellHeaderHeight` above
|
|
408
417
|
* despite sharing 48 at level 0 (see that entry's note). */
|
|
409
418
|
appShellNavbarRailWidth: 48,
|
|
@@ -482,7 +491,33 @@ const SPACE_STEP_BASE = {
|
|
|
482
491
|
/** `data/virtual-list.tsx`'s skeleton row vertical inset. */
|
|
483
492
|
virtualRowInsetY: 8,
|
|
484
493
|
/** `data/virtual-list.tsx`'s skeleton row horizontal inset. */
|
|
485
|
-
virtualRowInsetX: 12
|
|
494
|
+
virtualRowInsetX: 12,
|
|
495
|
+
// ── Controls — homes/tiers (`docs/CONTROLS-SPEC.md` §5) ──────────────────────────────────────
|
|
496
|
+
/** `PageBar` row height (row 1 or row 2, each measured independently — the bar's own overall
|
|
497
|
+
* height is the sum published as `--basalt-page-bar-h`, computed by `PageBar` itself, not a
|
|
498
|
+
* static token). */
|
|
499
|
+
pageBarRowHeight: 40,
|
|
500
|
+
/** `WidgetHeader tier="section"` row height. */
|
|
501
|
+
sectionHeaderHeight: 36,
|
|
502
|
+
/** `WidgetHeader tier="widget"` row height. */
|
|
503
|
+
widgetHeaderHeight: 28,
|
|
504
|
+
/** Sidebar block list-item row height. */
|
|
505
|
+
sidebarBlockRowHeight: 32,
|
|
506
|
+
/** Gap between adjacent controls inside a home (filter pills, action buttons). */
|
|
507
|
+
controlGap: 6,
|
|
508
|
+
/** Mobile bottom-sheet row height (the `Filters (n)` drawer, a block's More-sheet row) — Apple
|
|
509
|
+
* HIG 44pt / WCAG 2.5.5 AAA, same floor family as `mobileNavRowHeight`. */
|
|
510
|
+
sheetRowHeight: 44,
|
|
511
|
+
/** `BasaltDataTable`'s header row. Its own entry rather than a reuse of `sectionHeaderHeight`
|
|
512
|
+
* (which is 36 too at level 0): one is a heading's box, this is a table's `th`, and a density
|
|
513
|
+
* pass that wants denser table rows must not be forced to shrink every section header with them.
|
|
514
|
+
* Mantine sizes both `th` and `td` from ONE `verticalSpacing` prop, so a 36/40 pair is
|
|
515
|
+
* unreachable through it — both are applied in `theme/index.ts`'s `Table.extend` as JS numbers,
|
|
516
|
+
* which is why (like `progressBarSize`) neither is emitted as a `--vx-*` var. */
|
|
517
|
+
tableHeaderHeight: 36,
|
|
518
|
+
/** `BasaltDataTable`'s body row — one step taller than the header, so the mono uppercase `th`
|
|
519
|
+
* reads as a label band over roomier data rows rather than as the first row of the data. */
|
|
520
|
+
tableRowHeight: 40
|
|
486
521
|
};
|
|
487
522
|
const SPACE_FIXED = {
|
|
488
523
|
/** Timeline `defaultProps.lineWidth`; also used for 1px borders. */
|
|
@@ -530,18 +565,21 @@ function deriveSpacing(level) {
|
|
|
530
565
|
anchors.stackMd = stackUnit * 3;
|
|
531
566
|
anchors.stackLg = stackUnit * 4;
|
|
532
567
|
anchors.stackXl = stackUnit * 6;
|
|
568
|
+
anchors.controlHeightTag = Math.max(18, anchors.controlHeightTag);
|
|
569
|
+
anchors.controlHeightWidget = Math.max(22, anchors.controlHeightWidget);
|
|
570
|
+
anchors.controlHeightCtl = Math.max(28, anchors.controlHeightCtl);
|
|
571
|
+
anchors.touchControlHeight = Math.max(30, anchors.touchControlHeight);
|
|
533
572
|
const mappedStep = mapSpaceGroup(SPACE_STEP_BASE, level, multiplier);
|
|
534
573
|
mappedStep.sidebarSearchTriggerHeight = Math.max(24, mappedStep.sidebarSearchTriggerHeight);
|
|
535
574
|
mappedStep.mobileNavBarHeight = Math.max(48, mappedStep.mobileNavBarHeight);
|
|
536
575
|
mappedStep.mobileNavRowHeight = Math.max(44, mappedStep.mobileNavRowHeight);
|
|
576
|
+
mappedStep.sheetRowHeight = Math.max(44, mappedStep.sheetRowHeight);
|
|
537
577
|
const step = {
|
|
538
578
|
...mappedStep,
|
|
539
|
-
//
|
|
540
|
-
//
|
|
541
|
-
//
|
|
542
|
-
|
|
543
|
-
stickyHeaderClearance: mappedStep.appShellHeaderHeight + anchors.stackMd,
|
|
544
|
-
stickyHeaderClearanceMobile: mappedStep.appShellHeaderMobileHeight + anchors.stackMd
|
|
579
|
+
// DERIVED from the header it clears, plus density-tracking breathing room — see this function's
|
|
580
|
+
// doc (third bullet) for the full rationale, and `theme/spacing.test.ts` for why
|
|
581
|
+
// `stickyHeaderClearance` alone is exempt from the level-0 byte-identity gate.
|
|
582
|
+
stickyHeaderClearance: mappedStep.appShellHeaderHeight + anchors.stackMd
|
|
545
583
|
};
|
|
546
584
|
return {
|
|
547
585
|
anchors,
|
package/dist/tokens.css
CHANGED
|
@@ -10,13 +10,16 @@
|
|
|
10
10
|
--vx-space-row-line-height: 1.35;
|
|
11
11
|
--vx-space-input-height: 2.625rem;
|
|
12
12
|
--vx-space-control-height: 2.625rem;
|
|
13
|
+
--vx-space-control-height-tag: 1.25rem;
|
|
14
|
+
--vx-space-control-height-widget: 1.5rem;
|
|
15
|
+
--vx-space-control-height-ctl: 1.875rem;
|
|
16
|
+
--vx-space-touch-control-height: 2.25rem;
|
|
13
17
|
--vx-space-stack-xs: 4px;
|
|
14
18
|
--vx-space-stack-sm: 8px;
|
|
15
19
|
--vx-space-stack-md: 12px;
|
|
16
20
|
--vx-space-stack-lg: 16px;
|
|
17
21
|
--vx-space-stack-xl: 24px;
|
|
18
22
|
--vx-space-sticky-header-clearance: 60px;
|
|
19
|
-
--vx-space-sticky-header-clearance-mobile: 109px;
|
|
20
23
|
--vx-space-nav-icon-gap: 10px;
|
|
21
24
|
--vx-space-sidebar-region-gap: 10px;
|
|
22
25
|
--vx-space-prose-quote-inset-y: 2px;
|
|
@@ -93,7 +96,6 @@
|
|
|
93
96
|
--vx-space-sidebar-child-list-indent: 15px;
|
|
94
97
|
--vx-space-sidebar-child-row-inset-y: 4px;
|
|
95
98
|
--vx-space-sidebar-child-row-indent: 12px;
|
|
96
|
-
--vx-space-app-header-mobile-actions-height: 52px;
|
|
97
99
|
--vx-space-mobile-nav-tab-gap: 3px;
|
|
98
100
|
--vx-space-mobile-nav-icon-size: 24px;
|
|
99
101
|
--vx-space-mobile-nav-tab-inset-y: 2px;
|
|
@@ -113,6 +115,12 @@
|
|
|
113
115
|
--vx-space-stat-card-gap: 8px;
|
|
114
116
|
--vx-space-virtual-row-inset-y: 8px;
|
|
115
117
|
--vx-space-virtual-row-inset-x: 12px;
|
|
118
|
+
--vx-space-page-bar-row-height: 2.5rem;
|
|
119
|
+
--vx-space-section-header-height: 2.25rem;
|
|
120
|
+
--vx-space-widget-header-height: 1.75rem;
|
|
121
|
+
--vx-space-sidebar-block-row-height: 2rem;
|
|
122
|
+
--vx-space-control-gap: 6px;
|
|
123
|
+
--vx-space-sheet-row-height: 2.75rem;
|
|
116
124
|
--vx-prose-measure: 72ch;
|
|
117
125
|
--vx-fill-gray: #717176;
|
|
118
126
|
--vx-fill-red: #b7514e;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type DeltaBadgeProps = {
|
|
2
|
+
/** Signed delta driving tone (positive/negative/zero) and, by default, the label magnitude. */
|
|
3
|
+
value: number;
|
|
4
|
+
/** Formats the value into the label text. Defaults to `${Math.abs(value).toFixed(1)}%`. */
|
|
5
|
+
format?: (value: number) => string;
|
|
6
|
+
/** Render the ▲/▼ direction glyph. Defaults to `true`; a zero value never shows a glyph. */
|
|
7
|
+
withGlyph?: boolean;
|
|
8
|
+
/** Optional comparison timeframe rendered directly after the value in a dimmer shade of the same
|
|
9
|
+
* tone (e.g. `MoM`, `WoW`, `YTD`) — states what the delta is measured against without a hover. */
|
|
10
|
+
period?: string | undefined;
|
|
11
|
+
};
|
|
12
|
+
export declare function DeltaBadge({ value, format, withGlyph, period, }: DeltaBadgeProps): import("react").JSX.Element;
|
|
13
|
+
//# sourceMappingURL=delta-badge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delta-badge.d.ts","sourceRoot":"","sources":["../../src/widget-header/delta-badge.tsx"],"names":[],"mappings":"AAsBA,MAAM,MAAM,eAAe,GAAG;IAC5B,+FAA+F;IAC/F,KAAK,EAAE,MAAM,CAAA;IACb,2FAA2F;IAC3F,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;IAClC,4FAA4F;IAC5F,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;sGACkG;IAClG,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC5B,CAAA;AAID,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,MAAsB,EACtB,SAAgB,EAChB,MAAM,GACP,EAAE,eAAe,+BAejB"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { alpha, VX } from "../tokens/index.js";
|
|
3
|
+
import classes from "./widget-header.module.css";
|
|
4
|
+
const defaultFormat = (value) => `${Math.abs(value).toFixed(1)}%`;
|
|
5
|
+
function DeltaBadge({
|
|
6
|
+
value,
|
|
7
|
+
format = defaultFormat,
|
|
8
|
+
withGlyph = true,
|
|
9
|
+
period
|
|
10
|
+
}) {
|
|
11
|
+
const tone = value > 0 ? VX.status.good : value < 0 ? VX.status.bad : VX.faint;
|
|
12
|
+
const glyph = value > 0 ? "\u25B2" : value < 0 ? "\u25BC" : void 0;
|
|
13
|
+
const showGlyph = withGlyph && glyph !== void 0;
|
|
14
|
+
return /* @__PURE__ */ jsxs(
|
|
15
|
+
"span",
|
|
16
|
+
{
|
|
17
|
+
className: classes.deltaBadge,
|
|
18
|
+
style: { backgroundColor: alpha(tone, 0.13), color: tone },
|
|
19
|
+
children: [
|
|
20
|
+
showGlyph && /* @__PURE__ */ jsx("span", { className: classes.deltaGlyph, children: glyph }),
|
|
21
|
+
format(value),
|
|
22
|
+
period !== void 0 && /* @__PURE__ */ jsx("span", { className: classes.deltaPeriod, children: period })
|
|
23
|
+
]
|
|
24
|
+
}
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
export {
|
|
28
|
+
DeltaBadge
|
|
29
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delta-badge.test.d.ts","sourceRoot":"","sources":["../../src/widget-header/delta-badge.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/widget-header/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACtE,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-mantine.test.d.ts","sourceRoot":"","sources":["../../src/widget-header/no-mantine.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
export type WidgetHeaderProps = {
|
|
3
|
+
/** `section` renders an `<h2>` at the section-header height; `widget` renders an `<h3>` at the
|
|
4
|
+
* tighter icon-tier height, display-only. */
|
|
5
|
+
tier: 'section' | 'widget';
|
|
6
|
+
/** Head-font title (88% stretch, weight 550). */
|
|
7
|
+
title: string;
|
|
8
|
+
/** Optional leading icon, rendered before the title. Decorative — hidden from assistive tech. */
|
|
9
|
+
icon?: ReactNode;
|
|
10
|
+
/** Optional muted line rendered below the title row. */
|
|
11
|
+
subtitle?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Renders an info glyph BESIDE the heading (never inside it — this text would otherwise become
|
|
14
|
+
* part of the heading's accessible name, and an `info` paragraph read out in every headings list
|
|
15
|
+
* is what that cost). The glyph is named `More information`; the text itself reaches assistive
|
|
16
|
+
* tech through `aria-describedby` on a `role="tooltip"` bubble that opens on hover, focus and
|
|
17
|
+
* click — so a keyboard user gets it too. Mantine-free: a plain state bubble, not a Tooltip.
|
|
18
|
+
*/
|
|
19
|
+
info?: string;
|
|
20
|
+
/** Pre-formatted metric value (mono, hero size). Renders on its own row with `delta`, directly
|
|
21
|
+
* under the title row — never inline with the title. */
|
|
22
|
+
value?: string;
|
|
23
|
+
/**
|
|
24
|
+
* The value's unit, rendered immediately after it on the hero row: muted, mono, `--vx-text-sm`.
|
|
25
|
+
*
|
|
26
|
+
* It exists because `value` is a pre-formatted `string` and a KPI's unit is not part of the
|
|
27
|
+
* number: `412` and `TSS` are two facts at two weights, and jamming them into one string paints
|
|
28
|
+
* the unit at the hero's 24px — which reads as a second numeral. `subtitle` was the only place a
|
|
29
|
+
* unit could go before this, and a unit on its own line under the value is a different claim (the
|
|
30
|
+
* BASIS: `7-day rolling`), so cards using both had to pick one.
|
|
31
|
+
*
|
|
32
|
+
* Never a substitute for the number's own formatting: a thousands separator, a currency symbol or
|
|
33
|
+
* a `%` belong in `value`, where they are part of how the numeral reads.
|
|
34
|
+
*/
|
|
35
|
+
unit?: string;
|
|
36
|
+
/** Signed delta rendered via `DeltaBadge`, on the same hero-metric row as `value`. */
|
|
37
|
+
delta?: number;
|
|
38
|
+
/** Comparison timeframe forwarded to `DeltaBadge` (e.g. `MoM`). */
|
|
39
|
+
deltaPeriod?: string;
|
|
40
|
+
/**
|
|
41
|
+
* Formats `delta` into the chip's label — forwarded to `DeltaBadge`'s `format`. Defaults to
|
|
42
|
+
* `${Math.abs(delta).toFixed(1)}%`.
|
|
43
|
+
*
|
|
44
|
+
* It exists because not every delta is a percentage: a pace card's trend is `0:12 /km` and a
|
|
45
|
+
* throughput card's is `0.3 km/h`, and the default printed both as a percent — a wrong unit on a
|
|
46
|
+
* KPI, which is worse than no chip. A FUNCTION rather than a label string, so the number stays the
|
|
47
|
+
* number: `delta` still drives the tone and the glyph, and there is exactly one place the sign is
|
|
48
|
+
* decided.
|
|
49
|
+
*
|
|
50
|
+
* The value arrives SIGNED, so a formatter that wants to print the sign itself (`−0:12 /km`) can —
|
|
51
|
+
* pair it with `deltaGlyph={false}` so the ▼ does not say the same thing twice.
|
|
52
|
+
*/
|
|
53
|
+
deltaFormat?: (delta: number) => string;
|
|
54
|
+
/** Render `DeltaBadge`'s ▲/▼ glyph. Defaults to `true`; a zero delta never shows one. Pass
|
|
55
|
+
* `false` when `deltaFormat` prints the sign itself. */
|
|
56
|
+
deltaGlyph?: boolean;
|
|
57
|
+
/** Trend visual slot, rendered below the metric row. Carries `data-placement="right"` so a
|
|
58
|
+
* wave-3 composer's `bleed` layout can select it. */
|
|
59
|
+
sparkline?: ReactNode;
|
|
60
|
+
/** Mono count tag rendered after the title (C11 — every table/list states its count). `0` is a
|
|
61
|
+
* real count and renders, distinct from omitting the prop entirely. */
|
|
62
|
+
count?: number;
|
|
63
|
+
/** Right-aligned slot (`margin-inline-start: auto`) — the C1/C5 home for header actions. */
|
|
64
|
+
actions?: ReactNode;
|
|
65
|
+
};
|
|
66
|
+
export declare function WidgetHeader({ tier, title, icon, subtitle, info, value, unit, delta, deltaPeriod, deltaFormat, deltaGlyph, sparkline, count, actions, }: WidgetHeaderProps): import("react").JSX.Element;
|
|
67
|
+
//# sourceMappingURL=widget-header.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"widget-header.d.ts","sourceRoot":"","sources":["../../src/widget-header/widget-header.tsx"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAKtC,MAAM,MAAM,iBAAiB,GAAG;IAC9B;iDAC6C;IAC7C,IAAI,EAAE,SAAS,GAAG,QAAQ,CAAA;IAC1B,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAA;IACb,iGAAiG;IACjG,IAAI,CAAC,EAAE,SAAS,CAAA;IAChB,wDAAwD;IACxD,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;4DACwD;IACxD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;;;;;;;;OAWG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,sFAAsF;IACtF,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;;;;;;;;;OAYG;IACH,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;IACvC;4DACwD;IACxD,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB;yDACqD;IACrD,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB;2EACuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,4FAA4F;IAC5F,OAAO,CAAC,EAAE,SAAS,CAAA;CACpB,CAAA;AAyDD,wBAAgB,YAAY,CAAC,EAC3B,IAAI,EACJ,KAAK,EACL,IAAI,EACJ,QAAQ,EACR,IAAI,EACJ,KAAK,EACL,IAAI,EACJ,KAAK,EACL,WAAW,EACX,WAAW,EACX,UAAU,EACV,SAAS,EACT,KAAK,EACL,OAAO,GACR,EAAE,iBAAiB,+BA6CnB"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useId, useRef, useState } from "react";
|
|
3
|
+
import { IconSlot } from "../theme/icon-slot.js";
|
|
4
|
+
import { DeltaBadge } from "./delta-badge.js";
|
|
5
|
+
import classes from "./widget-header.module.css";
|
|
6
|
+
function InfoGlyph({ text }) {
|
|
7
|
+
const [open, setOpen] = useState(false);
|
|
8
|
+
const tipId = useId();
|
|
9
|
+
const triggerRef = useRef(null);
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (!open) return;
|
|
12
|
+
const handlePointerDown = (event) => {
|
|
13
|
+
if (triggerRef.current?.contains(event.target)) return;
|
|
14
|
+
setOpen(false);
|
|
15
|
+
};
|
|
16
|
+
document.addEventListener("pointerdown", handlePointerDown);
|
|
17
|
+
return () => document.removeEventListener("pointerdown", handlePointerDown);
|
|
18
|
+
}, [open]);
|
|
19
|
+
return /* @__PURE__ */ jsxs("span", { className: classes.info, children: [
|
|
20
|
+
/* @__PURE__ */ jsx(
|
|
21
|
+
"button",
|
|
22
|
+
{
|
|
23
|
+
ref: triggerRef,
|
|
24
|
+
type: "button",
|
|
25
|
+
className: classes.infoTrigger,
|
|
26
|
+
"aria-label": "More information",
|
|
27
|
+
"aria-describedby": open ? tipId : void 0,
|
|
28
|
+
"data-open": open,
|
|
29
|
+
onMouseEnter: () => setOpen(true),
|
|
30
|
+
onMouseLeave: () => setOpen(false),
|
|
31
|
+
onFocus: () => setOpen(true),
|
|
32
|
+
onBlur: () => setOpen(false),
|
|
33
|
+
onClick: () => setOpen(true),
|
|
34
|
+
onKeyDown: (event) => {
|
|
35
|
+
if (event.key === "Escape") setOpen(false);
|
|
36
|
+
},
|
|
37
|
+
children: /* @__PURE__ */ jsx("svg", { width: 11, height: 11, viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M12 0C5.373 0 0 5.373 0 12s5.373 12 12 12 12-5.373 12-12S18.627 0 12 0zm0 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3zm0 5a1 1 0 0 1 1 1v7a1 1 0 1 1-2 0v-7a1 1 0 0 1 1-1z" }) })
|
|
38
|
+
}
|
|
39
|
+
),
|
|
40
|
+
open && /* @__PURE__ */ jsx("span", { id: tipId, role: "tooltip", className: classes.infoBubble, children: text })
|
|
41
|
+
] });
|
|
42
|
+
}
|
|
43
|
+
function WidgetHeader({
|
|
44
|
+
tier,
|
|
45
|
+
title,
|
|
46
|
+
icon,
|
|
47
|
+
subtitle,
|
|
48
|
+
info,
|
|
49
|
+
value,
|
|
50
|
+
unit,
|
|
51
|
+
delta,
|
|
52
|
+
deltaPeriod,
|
|
53
|
+
deltaFormat,
|
|
54
|
+
deltaGlyph,
|
|
55
|
+
sparkline,
|
|
56
|
+
count,
|
|
57
|
+
actions
|
|
58
|
+
}) {
|
|
59
|
+
const Heading = tier === "section" ? "h2" : "h3";
|
|
60
|
+
return /* @__PURE__ */ jsxs("div", { className: classes.root, "data-tier": tier, children: [
|
|
61
|
+
/* @__PURE__ */ jsxs("div", { className: classes.titleRow, children: [
|
|
62
|
+
/* @__PURE__ */ jsxs(Heading, { className: classes.heading, children: [
|
|
63
|
+
icon !== void 0 && /* @__PURE__ */ jsx(IconSlot, { className: classes.icon, children: icon }),
|
|
64
|
+
/* @__PURE__ */ jsx("span", { className: classes.titleText, children: title })
|
|
65
|
+
] }),
|
|
66
|
+
info !== void 0 && /* @__PURE__ */ jsx(InfoGlyph, { text: info }),
|
|
67
|
+
count !== void 0 && /* @__PURE__ */ jsx("span", { className: classes.count, children: count }),
|
|
68
|
+
actions !== void 0 && /* @__PURE__ */ jsx("span", { className: classes.actions, children: actions })
|
|
69
|
+
] }),
|
|
70
|
+
(value !== void 0 || delta !== void 0) && /* @__PURE__ */ jsxs("div", { className: classes.metrics, children: [
|
|
71
|
+
value !== void 0 && /* @__PURE__ */ jsx("span", { className: classes.value, children: value }),
|
|
72
|
+
value !== void 0 && unit !== void 0 && /* @__PURE__ */ jsx("span", { className: classes.unit, children: unit }),
|
|
73
|
+
delta !== void 0 && /* @__PURE__ */ jsx(
|
|
74
|
+
DeltaBadge,
|
|
75
|
+
{
|
|
76
|
+
value: delta,
|
|
77
|
+
period: deltaPeriod,
|
|
78
|
+
...deltaFormat !== void 0 && { format: deltaFormat },
|
|
79
|
+
...deltaGlyph !== void 0 && { withGlyph: deltaGlyph }
|
|
80
|
+
}
|
|
81
|
+
)
|
|
82
|
+
] }),
|
|
83
|
+
subtitle !== void 0 && /* @__PURE__ */ jsx("span", { className: classes.subtitle, children: subtitle }),
|
|
84
|
+
sparkline !== void 0 && /* @__PURE__ */ jsx("div", { className: classes.sparkline, "data-placement": "right", children: sparkline })
|
|
85
|
+
] });
|
|
86
|
+
}
|
|
87
|
+
export {
|
|
88
|
+
WidgetHeader
|
|
89
|
+
};
|