basalt-ui 1.30.2 → 1.32.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 +1 -1
- package/CHANGELOG.md +54 -0
- package/MIGRATING.md +256 -12
- package/agent/rules/basalt-controls.md +19 -19
- package/agent/rules/basalt-mantine.md +5 -5
- package/configs/oxlint-plugin.js +371 -4
- package/configs/oxlint-plugin.test.ts +327 -2
- package/configs/oxlint.json +2 -1
- package/dist/agent-chat/composer.d.ts.map +1 -1
- package/dist/agent-chat/composer.js +41 -43
- package/dist/agent-chat/thread-workspace.d.ts +2 -2
- package/dist/agent-chat/thread-workspace.d.ts.map +1 -1
- package/dist/agent-chat/thread-workspace.js +3 -4
- package/dist/agent-chat/use-keyboard-inset.d.ts +2 -0
- package/dist/agent-chat/use-keyboard-inset.d.ts.map +1 -0
- package/dist/agent-chat/use-keyboard-inset.js +34 -0
- package/dist/charts/cursor/touch-pin.d.ts +45 -0
- package/dist/charts/cursor/touch-pin.d.ts.map +1 -0
- package/dist/charts/cursor/touch-pin.js +79 -0
- package/dist/charts/hooks/use-discrete-cursor.d.ts +66 -0
- package/dist/charts/hooks/use-discrete-cursor.d.ts.map +1 -0
- package/dist/charts/hooks/use-discrete-cursor.js +198 -0
- package/dist/charts/hooks/use-hysteresis.d.ts +18 -0
- package/dist/charts/hooks/use-hysteresis.d.ts.map +1 -0
- package/dist/charts/hooks/use-hysteresis.js +12 -0
- package/dist/charts/hooks/useBandPlot.d.ts +7 -0
- package/dist/charts/hooks/useBandPlot.d.ts.map +1 -1
- package/dist/charts/hooks/useBandPlot.js +62 -18
- package/dist/charts/hooks/useChartCursor.d.ts +40 -11
- package/dist/charts/hooks/useChartCursor.d.ts.map +1 -1
- package/dist/charts/hooks/useChartCursor.js +102 -11
- package/dist/charts/index.d.ts +0 -1
- package/dist/charts/index.d.ts.map +1 -1
- package/dist/charts/index.js +0 -10
- package/dist/charts/kinds/BandStrip.d.ts.map +1 -1
- package/dist/charts/kinds/BandStrip.js +47 -82
- package/dist/charts/kinds/Donut.d.ts +9 -3
- package/dist/charts/kinds/Donut.d.ts.map +1 -1
- package/dist/charts/kinds/Donut.js +110 -48
- package/dist/charts/kinds/DualPanel.d.ts.map +1 -1
- package/dist/charts/kinds/DualPanel.js +138 -145
- package/dist/charts/kinds/Heatmap.d.ts +7 -0
- package/dist/charts/kinds/Heatmap.d.ts.map +1 -1
- package/dist/charts/kinds/Heatmap.js +37 -16
- package/dist/charts/kinds/MirroredBars.d.ts.map +1 -1
- package/dist/charts/kinds/MirroredBars.js +68 -111
- package/dist/charts/kinds/band-chrome.d.ts +31 -0
- package/dist/charts/kinds/band-chrome.d.ts.map +1 -0
- package/dist/charts/kinds/band-chrome.js +71 -0
- package/dist/charts/kinds/donut-layout.d.ts +47 -0
- package/dist/charts/kinds/donut-layout.d.ts.map +1 -0
- package/dist/charts/kinds/donut-layout.js +52 -0
- package/dist/charts/layout/auto-margin.d.ts +7 -2
- package/dist/charts/layout/auto-margin.d.ts.map +1 -1
- package/dist/charts/layout/auto-margin.js +12 -3
- package/dist/charts/layout/end-labels.d.ts +64 -0
- package/dist/charts/layout/end-labels.d.ts.map +1 -0
- package/dist/charts/layout/end-labels.js +76 -0
- package/dist/charts/primitives/Axes.d.ts +32 -4
- package/dist/charts/primitives/Axes.d.ts.map +1 -1
- package/dist/charts/primitives/Axes.js +62 -16
- package/dist/charts/primitives/CartesianChart.d.ts +7 -6
- package/dist/charts/primitives/CartesianChart.d.ts.map +1 -1
- package/dist/charts/primitives/CartesianChart.js +264 -145
- package/dist/charts/primitives/ChartCard.d.ts +0 -14
- package/dist/charts/primitives/ChartCard.d.ts.map +1 -1
- package/dist/charts/primitives/ChartCard.js +56 -21
- package/dist/charts/primitives/ChartFrame.d.ts +28 -22
- package/dist/charts/primitives/ChartFrame.d.ts.map +1 -1
- package/dist/charts/primitives/ChartFrame.js +116 -34
- package/dist/charts/primitives/ChartLegend.d.ts +19 -15
- package/dist/charts/primitives/ChartLegend.d.ts.map +1 -1
- package/dist/charts/primitives/ChartLegend.js +86 -73
- package/dist/charts/primitives/ChartTooltip.d.ts +5 -0
- package/dist/charts/primitives/ChartTooltip.d.ts.map +1 -1
- package/dist/charts/primitives/ChartTooltip.js +20 -4
- package/dist/charts/primitives/Crosshair.js +2 -2
- package/dist/charts/primitives/HoverOverlay.d.ts +29 -9
- package/dist/charts/primitives/HoverOverlay.d.ts.map +1 -1
- package/dist/charts/primitives/HoverOverlay.js +54 -27
- package/dist/charts/primitives/HoverOverlay.module.css +13 -0
- package/dist/charts/primitives/HoverOverlay.module.css.d.ts +8 -0
- package/dist/charts/primitives/chart-card-context.d.ts +33 -0
- package/dist/charts/primitives/chart-card-context.d.ts.map +1 -0
- package/dist/charts/primitives/chart-card-context.js +18 -0
- package/dist/charts/primitives/chart-frame-layout.d.ts +93 -113
- package/dist/charts/primitives/chart-frame-layout.d.ts.map +1 -1
- package/dist/charts/primitives/chart-frame-layout.js +75 -34
- package/dist/charts/primitives/chart-layout.d.ts +112 -0
- package/dist/charts/primitives/chart-layout.d.ts.map +1 -0
- package/dist/charts/primitives/chart-layout.js +175 -0
- package/dist/charts/primitives/chart-tier.d.ts +13 -11
- package/dist/charts/primitives/chart-tier.d.ts.map +1 -1
- package/dist/charts/primitives/chart-tier.js +42 -13
- package/dist/charts/primitives/legend-disclosure.d.ts +27 -0
- package/dist/charts/primitives/legend-disclosure.d.ts.map +1 -0
- package/dist/charts/primitives/legend-disclosure.js +153 -0
- package/dist/charts/series.d.ts +4 -1
- package/dist/charts/series.d.ts.map +1 -1
- package/dist/charts/utils/ticks.d.ts +27 -8
- package/dist/charts/utils/ticks.d.ts.map +1 -1
- package/dist/charts/utils/ticks.js +35 -11
- package/dist/common/errors.d.ts +11 -1
- package/dist/common/errors.d.ts.map +1 -1
- package/dist/common/errors.js +16 -2
- package/dist/common/hit-floor.d.ts +10 -0
- package/dist/common/hit-floor.d.ts.map +1 -0
- package/dist/common/hit-floor.js +6 -0
- package/dist/{shell → common}/isomorphic-layout-effect.d.ts +4 -3
- package/dist/common/isomorphic-layout-effect.d.ts.map +1 -0
- package/dist/common/use-measured-widths.d.ts +37 -0
- package/dist/common/use-measured-widths.d.ts.map +1 -0
- package/dist/common/use-measured-widths.js +51 -0
- package/dist/common/use-media-query.d.ts +6 -0
- package/dist/common/use-media-query.d.ts.map +1 -0
- package/dist/common/use-media-query.js +40 -0
- package/dist/common/validate.d.ts +9 -0
- package/dist/common/validate.d.ts.map +1 -1
- package/dist/common/validate.js +9 -4
- package/dist/content/article-layout.d.ts +4 -2
- package/dist/content/article-layout.d.ts.map +1 -1
- package/dist/content/article-layout.js +43 -3
- package/dist/content/article-layout.module.css +45 -4
- package/dist/content/article-layout.module.css.d.ts +3 -0
- package/dist/content/code-block.d.ts.map +1 -1
- package/dist/content/code-block.js +40 -2
- package/dist/content/code-block.module.css +32 -2
- package/dist/content/prose.module.css +13 -8
- package/dist/controls/actions.d.ts +29 -6
- package/dist/controls/actions.d.ts.map +1 -1
- package/dist/controls/actions.js +158 -27
- package/dist/controls/actions.module.css +14 -1
- package/dist/controls/actions.module.css.d.ts +1 -0
- package/dist/controls/controls.module.css +13 -31
- package/dist/controls/enum-filter.js +2 -2
- package/dist/controls/filter-context.d.ts +10 -0
- package/dist/controls/filter-context.d.ts.map +1 -1
- package/dist/controls/filter-context.js +2 -0
- package/dist/controls/filter-pill.d.ts.map +1 -1
- package/dist/controls/filter-pill.js +1 -0
- package/dist/controls/index.d.ts +1 -1
- package/dist/controls/index.d.ts.map +1 -1
- package/dist/controls/index.js +0 -2
- package/dist/controls/multi-select-filter.js +2 -2
- package/dist/controls/sync-button.module.css +2 -1
- package/dist/dashboard/section.d.ts.map +1 -1
- package/dist/dashboard/section.js +1 -0
- package/dist/dashboard/section.module.css +1 -26
- package/dist/dashboard/stat-card.d.ts +1 -1
- package/dist/dashboard/stat-card.d.ts.map +1 -1
- package/dist/dashboard/stat-card.js +4 -1
- package/dist/dashboard/stat-card.module.css +6 -9
- package/dist/dashboard/stat-group.module.css +33 -66
- package/dist/dashboard/widget-grid.d.ts.map +1 -1
- package/dist/dashboard/widget-grid.module.css +11 -38
- package/dist/dashboard/widget-header.d.ts +14 -4
- package/dist/dashboard/widget-header.d.ts.map +1 -1
- package/dist/dashboard/widget-header.js +23 -6
- package/dist/dashboard/widget-header.module.css +145 -133
- package/dist/dashboard/widget-header.module.css.d.ts +2 -0
- package/dist/data/data-table-state.d.ts +83 -0
- package/dist/data/data-table-state.d.ts.map +1 -0
- package/dist/data/data-table-state.js +139 -0
- package/dist/data/data-table.d.ts +56 -2
- package/dist/data/data-table.d.ts.map +1 -1
- package/dist/data/data-table.js +436 -336
- package/dist/data/data-table.module.css +94 -0
- package/dist/data/data-table.module.css.d.ts +11 -0
- package/dist/data/virtual-list.d.ts.map +1 -1
- package/dist/data/virtual-list.js +10 -0
- package/dist/forms/form-layout.d.ts.map +1 -1
- package/dist/forms/form-layout.js +3 -3
- package/dist/forms/form-layout.module.css +20 -5
- package/dist/forms/form-layout.module.css.d.ts +1 -0
- package/dist/guard/index.d.ts +8 -2
- package/dist/guard/index.d.ts.map +1 -1
- package/dist/guard/index.js +68 -2
- package/dist/guard/types.d.ts +3 -3
- package/dist/guard/types.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/notifications/center.d.ts.map +1 -1
- package/dist/provider/index.d.ts +20 -1
- package/dist/provider/index.d.ts.map +1 -1
- package/dist/provider/index.js +30 -8
- package/dist/shell/app-brand.d.ts.map +1 -1
- package/dist/shell/app-brand.js +1 -0
- package/dist/shell/app-brand.module.css +2 -2
- package/dist/shell/app-header.module.css +18 -8
- package/dist/shell/app-main.module.css +54 -3
- package/dist/shell/app-main.module.css.d.ts +1 -0
- package/dist/shell/app-mobile-nav.module.css +16 -4
- package/dist/shell/app-sidebar.module.css +4 -6
- package/dist/shell/aside-docking.d.ts +31 -0
- package/dist/shell/aside-docking.d.ts.map +1 -0
- package/dist/shell/aside-docking.js +19 -0
- package/dist/shell/index.d.ts +1 -0
- package/dist/shell/index.d.ts.map +1 -1
- package/dist/shell/index.js +56 -16
- package/dist/shell/mobile-nav-model.d.ts +1 -1
- package/dist/shell/page-aside.d.ts +22 -3
- package/dist/shell/page-aside.d.ts.map +1 -1
- package/dist/shell/page-aside.js +27 -13
- package/dist/shell/page-bar.d.ts.map +1 -1
- package/dist/shell/page-bar.js +10 -5
- package/dist/shell/page-bar.module.css +10 -34
- package/dist/shell/use-breakpoint.d.ts +3 -4
- package/dist/shell/use-breakpoint.d.ts.map +1 -1
- package/dist/shell/use-breakpoint.js +3 -25
- package/dist/shell/use-size-class.d.ts +6 -0
- package/dist/shell/use-size-class.d.ts.map +1 -0
- package/dist/shell/use-size-class.js +19 -0
- package/dist/state/persisted-or-local.d.ts +4 -1
- package/dist/state/persisted-or-local.d.ts.map +1 -1
- package/dist/state/persisted-or-local.js +4 -3
- package/dist/state/persisted.d.ts +10 -0
- package/dist/state/persisted.d.ts.map +1 -1
- package/dist/state/persisted.js +44 -14
- package/dist/styles.css +41 -0
- package/dist/surfaces.d.ts +4 -4
- package/dist/surfaces.d.ts.map +1 -1
- package/dist/surfaces.js +11 -3
- package/dist/theme/controls.module.css +7 -0
- package/dist/theme/ctl-theme.d.ts +1 -0
- package/dist/theme/ctl-theme.d.ts.map +1 -1
- package/dist/theme/ctl-theme.js +12 -4
- package/dist/theme/floating.module.css +37 -0
- package/dist/theme/floating.module.css.d.ts +3 -0
- package/dist/theme/index.d.ts +2 -2
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/index.js +34 -5
- package/dist/theme/nav-link.module.css +7 -0
- package/dist/theme-lab/derive-controls.d.ts.map +1 -1
- package/dist/tokens/index.d.ts +7 -16
- package/dist/tokens/index.d.ts.map +1 -1
- package/dist/tokens/index.js +23 -28
- package/dist/tokens/palette.d.ts +5 -27
- package/dist/tokens/palette.d.ts.map +1 -1
- package/dist/tokens/palette.js +8 -30
- package/dist/tokens/size-classes.d.ts +40 -0
- package/dist/tokens/size-classes.d.ts.map +1 -0
- package/dist/tokens/size-classes.js +29 -0
- package/dist/tokens.css +8 -4
- package/llms.txt +3 -3
- package/package.json +18 -17
- package/src/agent-chat/composer.tsx +74 -47
- package/src/agent-chat/thread-workspace.tsx +8 -11
- package/src/agent-chat/use-keyboard-inset.ts +68 -0
- package/src/charts/cursor/touch-pin.ts +138 -0
- package/src/charts/hooks/use-discrete-cursor.ts +335 -0
- package/src/charts/hooks/use-hysteresis.ts +26 -0
- package/src/charts/hooks/useBandPlot.ts +90 -27
- package/src/charts/hooks/useChartCursor.ts +211 -26
- package/src/charts/index.ts +0 -8
- package/src/charts/kinds/BandStrip.tsx +25 -61
- package/src/charts/kinds/Donut.tsx +153 -62
- package/src/charts/kinds/DualPanel.tsx +21 -26
- package/src/charts/kinds/Heatmap.tsx +61 -22
- package/src/charts/kinds/MirroredBars.tsx +23 -65
- package/src/charts/kinds/band-chrome.tsx +91 -0
- package/src/charts/kinds/donut-layout.ts +82 -0
- package/src/charts/layout/auto-margin.ts +24 -5
- package/src/charts/layout/end-labels.ts +135 -0
- package/src/charts/primitives/Axes.tsx +112 -21
- package/src/charts/primitives/CartesianChart.tsx +282 -111
- package/src/charts/primitives/ChartCard.tsx +119 -48
- package/src/charts/primitives/ChartFrame.tsx +204 -60
- package/src/charts/primitives/ChartLegend.tsx +115 -78
- package/src/charts/primitives/ChartTooltip.tsx +24 -3
- package/src/charts/primitives/Crosshair.tsx +2 -2
- package/src/charts/primitives/HoverOverlay.module.css +13 -0
- package/src/charts/primitives/HoverOverlay.module.css.d.ts +8 -0
- package/src/charts/primitives/HoverOverlay.tsx +62 -20
- package/src/charts/primitives/chart-card-context.ts +46 -0
- package/src/charts/primitives/chart-frame-layout.ts +207 -182
- package/src/charts/primitives/chart-layout.ts +318 -0
- package/src/charts/primitives/chart-tier.tsx +66 -21
- package/src/charts/primitives/legend-disclosure.tsx +177 -0
- package/src/charts/series.ts +4 -1
- package/src/charts/utils/ticks.ts +95 -19
- package/src/common/errors.ts +25 -1
- package/src/common/hit-floor.ts +9 -0
- package/src/{shell → common}/isomorphic-layout-effect.ts +4 -3
- package/src/common/use-measured-widths.ts +88 -0
- package/src/common/use-media-query.ts +56 -0
- package/src/common/validate.ts +17 -4
- package/src/content/article-layout.module.css +45 -4
- package/src/content/article-layout.module.css.d.ts +3 -0
- package/src/content/article-layout.tsx +60 -5
- package/src/content/code-block.module.css +32 -2
- package/src/content/code-block.tsx +47 -3
- package/src/content/prose.module.css +13 -8
- package/src/controls/actions.module.css +14 -1
- package/src/controls/actions.module.css.d.ts +1 -0
- package/src/controls/actions.tsx +223 -75
- package/src/controls/controls.module.css +13 -31
- package/src/controls/enum-filter.tsx +2 -2
- package/src/controls/filter-context.tsx +11 -0
- package/src/controls/filter-pill.tsx +1 -0
- package/src/controls/index.ts +0 -1
- package/src/controls/multi-select-filter.tsx +2 -2
- package/src/controls/sync-button.module.css +2 -1
- package/src/dashboard/section.module.css +1 -26
- package/src/dashboard/section.tsx +1 -0
- package/src/dashboard/stat-card.module.css +6 -9
- package/src/dashboard/stat-card.tsx +6 -3
- package/src/dashboard/stat-group.module.css +33 -66
- package/src/dashboard/widget-grid.module.css +11 -38
- package/src/dashboard/widget-grid.tsx +7 -6
- package/src/dashboard/widget-header.module.css +145 -133
- package/src/dashboard/widget-header.module.css.d.ts +2 -0
- package/src/dashboard/widget-header.tsx +45 -11
- package/src/data/data-table-state.ts +218 -0
- package/src/data/data-table.module.css +94 -0
- package/src/data/data-table.module.css.d.ts +11 -0
- package/src/data/data-table.tsx +547 -299
- package/src/data/virtual-list.tsx +31 -0
- package/src/forms/form-layout.module.css +20 -5
- package/src/forms/form-layout.module.css.d.ts +1 -0
- package/src/forms/form-layout.tsx +12 -10
- package/src/guard/index.ts +188 -3
- package/src/guard/types.ts +3 -2
- package/src/index.ts +2 -0
- package/src/notifications/center.tsx +3 -0
- package/src/provider/index.tsx +60 -7
- package/src/shell/app-brand.module.css +2 -2
- package/src/shell/app-brand.tsx +1 -0
- package/src/shell/app-header.module.css +18 -8
- package/src/shell/app-main.module.css +54 -3
- package/src/shell/app-main.module.css.d.ts +1 -0
- package/src/shell/app-mobile-nav.module.css +16 -4
- package/src/shell/app-sidebar.module.css +4 -6
- package/src/shell/aside-docking.ts +54 -0
- package/src/shell/index.tsx +178 -129
- package/src/shell/mobile-nav-model.ts +1 -1
- package/src/shell/page-aside.tsx +70 -21
- package/src/shell/page-bar.module.css +10 -34
- package/src/shell/page-bar.tsx +10 -5
- package/src/shell/use-breakpoint.ts +9 -45
- package/src/shell/use-size-class.ts +31 -0
- package/src/state/persisted-or-local.ts +10 -4
- package/src/state/persisted.ts +76 -17
- package/src/styles.css +41 -0
- package/src/surfaces.ts +9 -1
- package/src/theme/controls.module.css +7 -0
- package/src/theme/ctl-theme.tsx +15 -3
- package/src/theme/floating.module.css +37 -0
- package/src/theme/floating.module.css.d.ts +3 -0
- package/src/theme/index.ts +46 -8
- package/src/theme/nav-link.module.css +7 -0
- package/src/theme-lab/derive-controls.tsx +2 -0
- package/src/tokens/index.ts +20 -30
- package/src/tokens/palette.ts +6 -28
- package/src/tokens/size-classes.ts +46 -0
- package/dist/shell/isomorphic-layout-effect.d.ts.map +0 -1
- /package/dist/{shell → common}/isomorphic-layout-effect.js +0 -0
|
@@ -31,7 +31,7 @@ import type { ReactNode } from 'react'
|
|
|
31
31
|
import type { BasaltProps } from '../common/props'
|
|
32
32
|
import type { FieldOption } from '../state'
|
|
33
33
|
import classes from './controls.module.css'
|
|
34
|
-
import { useFilterRegistration, useFilterSurface } from './filter-context'
|
|
34
|
+
import { POPOVER_ROW_HIT_GAP, useFilterRegistration, useFilterSurface } from './filter-context'
|
|
35
35
|
import { FilterPill } from './filter-pill'
|
|
36
36
|
import { useControlName } from './filter-sheet'
|
|
37
37
|
import { PanelChoice, PanelRow } from './panel-row'
|
|
@@ -147,7 +147,7 @@ export function EnumFilter<T extends string>({
|
|
|
147
147
|
setValue(next as T)
|
|
148
148
|
}}
|
|
149
149
|
>
|
|
150
|
-
<Stack gap={
|
|
150
|
+
<Stack gap={POPOVER_ROW_HIT_GAP} style={{ '--vx-hit-gap': 'var(--stack-gap)' }}>
|
|
151
151
|
{options.map((option) => (
|
|
152
152
|
<Radio
|
|
153
153
|
key={option.value}
|
|
@@ -32,6 +32,17 @@ import {
|
|
|
32
32
|
} from 'react'
|
|
33
33
|
import type { ReactNode } from 'react'
|
|
34
34
|
|
|
35
|
+
/**
|
|
36
|
+
* The real gap a popover row (`EnumFilter`'s `Radio.Group`, `MultiSelectFilter`'s `Checkbox.Group`)
|
|
37
|
+
* needs so its `[data-basalt-hit]::after` overlay can reach the full 44px coarse floor with no
|
|
38
|
+
* overlap into the next row — same derivation as the chart legend's dots mode (`DOTS_HIT_GAP`):
|
|
39
|
+
* `hit - rowHeight - 2 + 4` headroom, rowHeight being Mantine's default `Radio`/`Checkbox` label row
|
|
40
|
+
* (~21px). A bare `gap={2}` left the `--vx-hit-gap` cap able to buy only ~4px of the 44
|
|
41
|
+
* (code-foundations F1). Shared rather than duplicated per file: both popover rows share the exact
|
|
42
|
+
* same row height and floor, so one drift point beats two hand-kept copies.
|
|
43
|
+
*/
|
|
44
|
+
export const POPOVER_ROW_HIT_GAP = 25
|
|
45
|
+
|
|
35
46
|
/**
|
|
36
47
|
* Which form a control renders. Provided by `FilterSet` (`'pill'` / `'sheet'`) and by `PageAside`
|
|
37
48
|
* (`'panel'`); `'pill'` when there is neither.
|
|
@@ -71,6 +71,7 @@ export function FilterPill({
|
|
|
71
71
|
variant="default"
|
|
72
72
|
size="ctl"
|
|
73
73
|
className={cx(classes.pill, className)}
|
|
74
|
+
data-basalt-hit
|
|
74
75
|
classNames={{ label: classes.pillLabel }}
|
|
75
76
|
{...(style !== undefined && { style })}
|
|
76
77
|
{...(active === true && { 'data-active': true })}
|
package/src/controls/index.ts
CHANGED
|
@@ -30,7 +30,7 @@ import { assertRequiredProps } from '../common/validate'
|
|
|
30
30
|
import type { FieldHandle, MultiField } from '../state'
|
|
31
31
|
import type { FilterOption } from './select-filter'
|
|
32
32
|
import classes from './controls.module.css'
|
|
33
|
-
import { useFilterRegistration, useFilterSurface } from './filter-context'
|
|
33
|
+
import { POPOVER_ROW_HIT_GAP, useFilterRegistration, useFilterSurface } from './filter-context'
|
|
34
34
|
import { FilterPill } from './filter-pill'
|
|
35
35
|
import { CheckGlyph, useControlName } from './filter-sheet'
|
|
36
36
|
import { PanelRow } from './panel-row'
|
|
@@ -143,7 +143,7 @@ export function MultiSelectFilter<T extends string>(props: MultiSelectFilterProp
|
|
|
143
143
|
setValue(next as readonly T[])
|
|
144
144
|
}}
|
|
145
145
|
>
|
|
146
|
-
<Stack gap={
|
|
146
|
+
<Stack gap={POPOVER_ROW_HIT_GAP} style={{ '--vx-hit-gap': 'var(--stack-gap)' }}>
|
|
147
147
|
{options.map((option) => (
|
|
148
148
|
<Checkbox
|
|
149
149
|
key={option.value}
|
|
@@ -45,7 +45,8 @@
|
|
|
45
45
|
* width itself, pinned to the `ctl` height so the box is square. This module is unlayered, so it
|
|
46
46
|
* outranks `@layer mantine` regardless of specificity.
|
|
47
47
|
*/
|
|
48
|
-
|
|
48
|
+
/* theme-allow raw-media-query — the control's own C9 icon-only swap at the compact size class */
|
|
49
|
+
@media (max-width: 52.49375em) {
|
|
49
50
|
.label,
|
|
50
51
|
.age {
|
|
51
52
|
display: none;
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* query at all).
|
|
19
19
|
*/
|
|
20
20
|
.root {
|
|
21
|
+
container: basalt-card / inline-size;
|
|
21
22
|
display: flex;
|
|
22
23
|
flex-direction: column;
|
|
23
24
|
gap: var(--vx-space-section-gap, 0.75rem);
|
|
@@ -95,29 +96,3 @@
|
|
|
95
96
|
.chevron[data-open='false'] svg {
|
|
96
97
|
transform: rotate(-90deg);
|
|
97
98
|
}
|
|
98
|
-
|
|
99
|
-
/*
|
|
100
|
-
* Law C15 — the chevron is a 12px glyph in a 20px box, which is a fine mouse target and an
|
|
101
|
-
* unusable thumb one. Below `sm` an `::after` overlay lifts the HIT area to
|
|
102
|
-
* `--vx-space-touch-control-height` (36px at level 0) while the visible glyph stays put — the same
|
|
103
|
-
* overlay `shell/page-bar.module.css` draws for the bar's own controls. `overflow: visible` is part
|
|
104
|
-
* of the fix, not tidying: an overlay that extends past the box is clipped by any `overflow:
|
|
105
|
-
* hidden` on the host (which is what made the identical overlay a no-op on Mantine's Button roots).
|
|
106
|
-
*/
|
|
107
|
-
@media (max-width: 47.99375em) {
|
|
108
|
-
.chevron {
|
|
109
|
-
overflow: visible;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
.chevron::after {
|
|
113
|
-
content: '';
|
|
114
|
-
position: absolute;
|
|
115
|
-
top: 50%;
|
|
116
|
-
left: 50%;
|
|
117
|
-
translate: -50% -50%;
|
|
118
|
-
width: 100%;
|
|
119
|
-
height: 100%;
|
|
120
|
-
min-width: var(--vx-space-touch-control-height, 2.25rem);
|
|
121
|
-
min-height: var(--vx-space-touch-control-height, 2.25rem);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* StatCard's sparkline placement (docs/CONTROLS-SPEC.md §2.2). `bleed` (default) keeps the
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* below `sm` — CSS only for the sparkline's own box, `.metricsRow` below for the row it sits in
|
|
7
|
-
* (`47.99375em` is Mantine's own complement of `min-width: 48em`, same value
|
|
8
|
-
* `content/prose.module.css` derives it from).
|
|
2
|
+
* StatCard's sparkline placement (docs/CONTROLS-SPEC.md §2.2). `bleed` (default) keeps the full-width
|
|
3
|
+
* row beneath the hero value, bled past the card's inset padding. `right` sits the sparkline beside
|
|
4
|
+
* the BREAKDOWN row and collapses back to `bleed`'s stacked layout when the card itself is narrower
|
|
5
|
+
* than 480px (`container: basalt-card`, set on the Card root in `stat-card.tsx`).
|
|
9
6
|
*/
|
|
10
7
|
|
|
11
8
|
.body {
|
|
@@ -131,7 +128,7 @@
|
|
|
131
128
|
}
|
|
132
129
|
|
|
133
130
|
/* Asks for `StatCard`'s `SPARKLINE_RIGHT_WIDTH`/`_HEIGHT` (handed down as custom properties, so this
|
|
134
|
-
* rule and the
|
|
131
|
+
* rule and the narrow-card reset below can both reach them). `align-self: flex-end` is the one alignment
|
|
135
132
|
* this restructure keeps at the SPARKLINE's own level rather than the row's: `.metricsRow` does not
|
|
136
133
|
* set `align-items: flex-end` itself, because a card with no breakdown would then need nothing to
|
|
137
134
|
* anchor against — only the sparkline opts into sitting at the row's bottom edge, which matters once
|
|
@@ -146,7 +143,7 @@
|
|
|
146
143
|
overflow: hidden;
|
|
147
144
|
}
|
|
148
145
|
|
|
149
|
-
@
|
|
146
|
+
@container basalt-card (max-width: 479.9px) {
|
|
150
147
|
.metricsRow {
|
|
151
148
|
flex-direction: column;
|
|
152
149
|
align-items: stretch;
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*
|
|
12
12
|
* `sparklinePlacement` decides where the trend visual sits: `'bleed'` (default) keeps the historic
|
|
13
13
|
* full-width row beneath the hero value, bled past the card's own inset padding; `'right'` sits it
|
|
14
|
-
* beside the hero row, the reference-design look.
|
|
14
|
+
* beside the hero row, the reference-design look. In a card narrower than 480px, `'right'` collapses back to the
|
|
15
15
|
* `'bleed'` layout — CSS only, no JS branch (`stat-card.module.css`).
|
|
16
16
|
*
|
|
17
17
|
* `info` and `subtitle` are forwarded to that same `WidgetHeader`, and a hero KPI usually wants
|
|
@@ -277,7 +277,7 @@ export type StatCardProps = BasaltProps &
|
|
|
277
277
|
*/
|
|
278
278
|
sparkline?: ReactNode | ((size: StatCardSparklineSize) => ReactNode)
|
|
279
279
|
/** Where `sparkline` sits. `'bleed'` (default) is today's full-width row bled to the card edges;
|
|
280
|
-
* `'right'` sits it beside the hero value row. Collapses to `'bleed'`
|
|
280
|
+
* `'right'` sits it beside the hero value row. Collapses to `'bleed'` in a card narrower than 480px. */
|
|
281
281
|
sparklinePlacement?: 'bleed' | 'right'
|
|
282
282
|
/** Header-right slot (e.g. a ghost "..." menu trigger) — wrapped in `CtlSlot tier="widget"`, so a
|
|
283
283
|
* raw `ActionIcon` with no `size` lands on the 24px step the 28px header row holds (C1/C5). */
|
|
@@ -357,7 +357,7 @@ export function StatCard({
|
|
|
357
357
|
)}
|
|
358
358
|
{...(!bleeds && {
|
|
359
359
|
// CUSTOM PROPERTIES, not `flexBasis`/`height` directly. A React inline style beats every
|
|
360
|
-
// stylesheet rule, so an inline `flexBasis: 72` also applied
|
|
360
|
+
// stylesheet rule, so an inline `flexBasis: 72` also applied in a narrow card — where `'right'`
|
|
361
361
|
// collapses `.metricsRow` to a COLUMN and flex-basis is therefore the main-axis HEIGHT.
|
|
362
362
|
// The mobile sparkline rendered in a 72px-tall box holding 26px of bars, which is the dead
|
|
363
363
|
// band under every KPI value on a phone. Handed to CSS as values instead, the media query
|
|
@@ -400,6 +400,9 @@ export function StatCard({
|
|
|
400
400
|
// Anchors the tone rail. Set unconditionally so a card's stacking context does not change
|
|
401
401
|
// depending on whether it happens to have crossed a threshold this render.
|
|
402
402
|
position: 'relative',
|
|
403
|
+
// The card's own width drives its chrome (`widget-header.module.css`, `.metricsRow`).
|
|
404
|
+
containerType: 'inline-size',
|
|
405
|
+
containerName: 'basalt-card',
|
|
403
406
|
...style,
|
|
404
407
|
}}
|
|
405
408
|
data-tone={tone}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* StatGroup's column law and its optional rail, in CSS (law C9).
|
|
3
3
|
*
|
|
4
4
|
* **The law keys on the CONTAINER, not the viewport.** A viewport breakpoint answers the wrong
|
|
5
|
-
* question — the same one `
|
|
6
|
-
*
|
|
5
|
+
* question — the same one `resolveContainerClass` refuses to ask (`tokens/size-classes.ts`): the
|
|
6
|
+
* shell has regions that change the AVAILABLE width with the viewport held still (a
|
|
7
7
|
* `PageAside` claiming its 300px, the sidebar collapsing 256px → its 48px rail, a consumer's own
|
|
8
8
|
* split layout), and `@media` cannot see any of them. Measured defect: a `PageAside` mounted on a
|
|
9
9
|
* 1512px desktop left the KPI row ~956px wide, `@media` still resolved `lg`, and four cells of
|
|
@@ -15,25 +15,24 @@
|
|
|
15
15
|
* one: a query with no container resolves to false, so a shell-only context would have silently
|
|
16
16
|
* pinned every non-shell consumer to the base count.
|
|
17
17
|
*
|
|
18
|
-
* The
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
18
|
+
* The literals are the container-class law (`CONTAINER_CLASSES`, `tokens/size-classes.ts`): the
|
|
19
|
+
* `sm` count opens at `wide` (800px), not at the viewport-era 768. Two are StatGroup's own and say
|
|
20
|
+
* so: 260px (one column, below) and 1200px, where the full `cols` count opens. The class table
|
|
21
|
+
* stops at 800, and 800 is too early for a full KPI row — four cells of ~190px clamp a value a real
|
|
22
|
+
* dashboard prints (`tests/layout/page-aside.layout.test.ts` measures ~195px against the 844px row
|
|
23
|
+
* a claimed aside leaves). Conditions are px, never `em`: `em` inside a `@container` condition
|
|
24
|
+
* resolves against the CONTAINER's font-size, so a consumer panel with smaller text would silently
|
|
25
|
+
* move the boundary. A condition cannot read a custom property, so the numbers are written; the
|
|
26
|
+
* COUNTS are custom properties the component sets per instance.
|
|
23
27
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* condition resolves against the CONTAINER's font-size rather than the root's, so a consumer panel
|
|
28
|
-
* with smaller text would silently move the breakpoint. px is the only spelling that cannot drift.
|
|
29
|
-
* (`47.99375em` → `767.9px`, `74.99375em` → `1199.9px`; the same complements `stat-card.module.css`
|
|
30
|
-
* uses.) A condition still cannot read a custom property either way, so the numbers are written;
|
|
31
|
-
* the COUNTS are custom properties the component sets per instance.
|
|
28
|
+
* No viewport fallback: basalt's own CSS already requires `color-mix()` (Safari 16.2, Chrome 111,
|
|
29
|
+
* Firefox 113), and every one of those parses `@container` — a `@supports not (container-type)`
|
|
30
|
+
* block is unreachable in any browser that renders basalt at all.
|
|
32
31
|
*/
|
|
33
32
|
|
|
34
33
|
.container {
|
|
35
34
|
container-type: inline-size;
|
|
36
|
-
container-name: basalt-
|
|
35
|
+
container-name: basalt-grid;
|
|
37
36
|
}
|
|
38
37
|
|
|
39
38
|
.root {
|
|
@@ -44,13 +43,26 @@
|
|
|
44
43
|
gap: var(--vx-space-stack-md);
|
|
45
44
|
}
|
|
46
45
|
|
|
47
|
-
|
|
46
|
+
/* 260px is StatGroup's own literal (docs/DESIGN-CORE.md § Layout, elevation, shapes), not a container class: one column below it,
|
|
47
|
+
* so every cell leads a row and the rail draws no leading hairline at all. */
|
|
48
|
+
@container basalt-grid (max-width: 259.9px) {
|
|
49
|
+
.root {
|
|
50
|
+
grid-template-columns: minmax(0, 1fr);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.root[data-divided] > *:nth-child(n) {
|
|
54
|
+
border-inline-start: 0;
|
|
55
|
+
padding-inline-start: 0;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@container basalt-grid (min-width: 800px) {
|
|
48
60
|
.root {
|
|
49
61
|
grid-template-columns: repeat(var(--basalt-stat-group-cols-sm), minmax(0, 1fr));
|
|
50
62
|
}
|
|
51
63
|
}
|
|
52
64
|
|
|
53
|
-
@container basalt-
|
|
65
|
+
@container basalt-grid (min-width: 1200px) {
|
|
54
66
|
.root {
|
|
55
67
|
grid-template-columns: repeat(var(--basalt-stat-group-cols-lg), minmax(0, 1fr));
|
|
56
68
|
}
|
|
@@ -71,14 +83,14 @@
|
|
|
71
83
|
padding-inline-start: var(--vx-space-stack-md);
|
|
72
84
|
}
|
|
73
85
|
|
|
74
|
-
@container basalt-
|
|
86
|
+
@container basalt-grid (max-width: 799.9px) {
|
|
75
87
|
.root[data-divided] > *:nth-child(2n + 1) {
|
|
76
88
|
border-inline-start: 0;
|
|
77
89
|
padding-inline-start: 0;
|
|
78
90
|
}
|
|
79
91
|
}
|
|
80
92
|
|
|
81
|
-
@container basalt-
|
|
93
|
+
@container basalt-grid (min-width: 800px) and (max-width: 1199.9px) {
|
|
82
94
|
.root[data-divided][data-sm-cols='2'] > *:nth-child(2n + 1),
|
|
83
95
|
.root[data-divided][data-sm-cols='3'] > *:nth-child(3n + 1) {
|
|
84
96
|
border-inline-start: 0;
|
|
@@ -86,7 +98,7 @@
|
|
|
86
98
|
}
|
|
87
99
|
}
|
|
88
100
|
|
|
89
|
-
@container basalt-
|
|
101
|
+
@container basalt-grid (min-width: 1200px) {
|
|
90
102
|
.root[data-divided][data-cols='2'] > *:nth-child(2n + 1),
|
|
91
103
|
.root[data-divided][data-cols='3'] > *:nth-child(3n + 1),
|
|
92
104
|
.root[data-divided][data-cols='4'] > *:nth-child(4n + 1),
|
|
@@ -95,48 +107,3 @@
|
|
|
95
107
|
padding-inline-start: 0;
|
|
96
108
|
}
|
|
97
109
|
}
|
|
98
|
-
|
|
99
|
-
/*
|
|
100
|
-
* The pre-container-query fallback — Safari < 16, Chrome < 106, Firefox < 110. Verbatim the law
|
|
101
|
-
* this file shipped before, keyed on the viewport, and reachable ONLY where `@container` is not.
|
|
102
|
-
* A browser that cannot parse `container-type` also cannot parse the `@container` blocks above, so
|
|
103
|
-
* the two sets are never live at once.
|
|
104
|
-
*/
|
|
105
|
-
@supports not (container-type: inline-size) {
|
|
106
|
-
@media (min-width: 48em) {
|
|
107
|
-
.root {
|
|
108
|
-
grid-template-columns: repeat(var(--basalt-stat-group-cols-sm), minmax(0, 1fr));
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
@media (min-width: 75em) {
|
|
113
|
-
.root {
|
|
114
|
-
grid-template-columns: repeat(var(--basalt-stat-group-cols-lg), minmax(0, 1fr));
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
@media (max-width: 47.99375em) {
|
|
119
|
-
.root[data-divided] > *:nth-child(2n + 1) {
|
|
120
|
-
border-inline-start: 0;
|
|
121
|
-
padding-inline-start: 0;
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
@media (min-width: 48em) and (max-width: 74.99375em) {
|
|
126
|
-
.root[data-divided][data-sm-cols='2'] > *:nth-child(2n + 1),
|
|
127
|
-
.root[data-divided][data-sm-cols='3'] > *:nth-child(3n + 1) {
|
|
128
|
-
border-inline-start: 0;
|
|
129
|
-
padding-inline-start: 0;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
@media (min-width: 75em) {
|
|
134
|
-
.root[data-divided][data-cols='2'] > *:nth-child(2n + 1),
|
|
135
|
-
.root[data-divided][data-cols='3'] > *:nth-child(3n + 1),
|
|
136
|
-
.root[data-divided][data-cols='4'] > *:nth-child(4n + 1),
|
|
137
|
-
.root[data-divided][data-cols='5'] > *:nth-child(5n + 1) {
|
|
138
|
-
border-inline-start: 0;
|
|
139
|
-
padding-inline-start: 0;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
@@ -15,18 +15,19 @@
|
|
|
15
15
|
* container. A span resolved against the viewport while the tracks follow the container is exactly
|
|
16
16
|
* the phantom-track defect `WidgetGrid.Item`'s context clamp exists to prevent.
|
|
17
17
|
*
|
|
18
|
-
* The literals
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
18
|
+
* The literals are the container-class law, as in `stat-group.module.css`: the `sm` count opens
|
|
19
|
+
* at `wide` (800px); 1200px, where the full `cols` count opens, is the grid's own boundary above
|
|
20
|
+
* the class table's top step. px, never `em` (an `em` condition resolves against the container's
|
|
21
|
+
* font-size). A condition cannot read a custom property, so the numbers are written; the COUNTS
|
|
22
|
+
* are custom properties, set once per instance by the component — three hand-written `repeat()`
|
|
23
|
+
* blocks would have to enumerate every `cols` value, and the whole point of this primitive is that
|
|
24
|
+
* a consumer states one desktop number and basalt owns the rest. No viewport fallback, for the
|
|
25
|
+
* reason `stat-group.module.css` states: nothing that renders basalt lacks `@container`.
|
|
25
26
|
*/
|
|
26
27
|
|
|
27
28
|
.container {
|
|
28
29
|
container-type: inline-size;
|
|
29
|
-
container-name: basalt-
|
|
30
|
+
container-name: basalt-grid;
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
.root {
|
|
@@ -47,7 +48,7 @@
|
|
|
47
48
|
min-width: 0;
|
|
48
49
|
}
|
|
49
50
|
|
|
50
|
-
@container basalt-
|
|
51
|
+
@container basalt-grid (min-width: 800px) {
|
|
51
52
|
.root {
|
|
52
53
|
grid-template-columns: repeat(var(--basalt-widget-grid-cols-sm), minmax(0, 1fr));
|
|
53
54
|
}
|
|
@@ -57,7 +58,7 @@
|
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
60
|
|
|
60
|
-
@container basalt-
|
|
61
|
+
@container basalt-grid (min-width: 1200px) {
|
|
61
62
|
.root {
|
|
62
63
|
grid-template-columns: repeat(var(--basalt-widget-grid-cols-lg), minmax(0, 1fr));
|
|
63
64
|
}
|
|
@@ -66,31 +67,3 @@
|
|
|
66
67
|
grid-column: span var(--basalt-widget-grid-span-lg);
|
|
67
68
|
}
|
|
68
69
|
}
|
|
69
|
-
|
|
70
|
-
/*
|
|
71
|
-
* The pre-container-query fallback — Safari < 16, Chrome < 106, Firefox < 110. Verbatim the law
|
|
72
|
-
* this file shipped before, keyed on the viewport, and reachable ONLY where `@container` is not: a
|
|
73
|
-
* browser that cannot parse `container-type` cannot parse the blocks above either, so the two sets
|
|
74
|
-
* are never live at once.
|
|
75
|
-
*/
|
|
76
|
-
@supports not (container-type: inline-size) {
|
|
77
|
-
@media (min-width: 48em) {
|
|
78
|
-
.root {
|
|
79
|
-
grid-template-columns: repeat(var(--basalt-widget-grid-cols-sm), minmax(0, 1fr));
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
.item {
|
|
83
|
-
grid-column: span var(--basalt-widget-grid-span-sm);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
@media (min-width: 75em) {
|
|
88
|
-
.root {
|
|
89
|
-
grid-template-columns: repeat(var(--basalt-widget-grid-cols-lg), minmax(0, 1fr));
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
.item {
|
|
93
|
-
grid-column: span var(--basalt-widget-grid-span-lg);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* **`cols` is the DESKTOP count, and it is the only number a consumer states.** The law is
|
|
11
11
|
* `base 1 → sm min(cols, 2) → lg cols`: a phone gets one column because a dashboard card holds a
|
|
12
12
|
* chart; a tablet gets at most two because a third makes every chart narrower than
|
|
13
|
-
* `
|
|
13
|
+
* `CONTAINER_CLASSES.regular`; the full count lands at `lg`. Mantine's `cols={{ … }}` object is
|
|
14
14
|
* deliberately NOT forwarded — a responsive object on the public prop is exactly the seam that let
|
|
15
15
|
* five call sites disagree.
|
|
16
16
|
*
|
|
@@ -19,12 +19,13 @@
|
|
|
19
19
|
* ACTUALLY has. The shell moves that width without moving the viewport — a `PageAside` claiming its
|
|
20
20
|
* 300px, the sidebar collapsing 256px → its 48px rail, a consumer's split pane — and a `@media`
|
|
21
21
|
* query sees none of it: it kept three chart columns in a 956px content box and every chart in the
|
|
22
|
-
* row went narrower than `
|
|
23
|
-
* avoid. See `widget-grid.module.css`'s header for the fallback.
|
|
22
|
+
* row went narrower than `CONTAINER_CLASSES.regular`, which is the exact condition the `lg` rung
|
|
23
|
+
* exists to avoid. See `widget-grid.module.css`'s header for the fallback.
|
|
24
24
|
*
|
|
25
|
-
* **This is the sanctioned place `lg` enters the package.**
|
|
26
|
-
*
|
|
27
|
-
*
|
|
25
|
+
* **This is the sanctioned place `lg` enters the package.** A consumer never writes a
|
|
26
|
+
* breakpoint — component layout keys on the container's own width
|
|
27
|
+
* (`docs/DESIGN-CORE.md` § Layout, elevation, shapes); `WidgetGrid` and `StatGroup` own their `lg`
|
|
28
|
+
* container rung internally so nobody else has to.
|
|
28
29
|
*
|
|
29
30
|
* `WidgetGrid.Item` is for the one card that is wider than the rest — a hero chart beside two
|
|
30
31
|
* stacked panels. `span` is likewise the DESKTOP span and is CLAMPED to the live column count at
|