basalt-ui 1.31.0 → 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/CHANGELOG.md +23 -0
- package/MIGRATING.md +101 -17
- package/agent/rules/basalt-mantine.md +4 -4
- package/configs/oxlint-plugin.js +159 -42
- package/configs/oxlint-plugin.test.ts +182 -0
- package/dist/charts/kinds/BandStrip.d.ts.map +1 -1
- package/dist/charts/kinds/BandStrip.js +18 -66
- package/dist/charts/kinds/DualPanel.d.ts.map +1 -1
- package/dist/charts/kinds/DualPanel.js +5 -26
- package/dist/charts/kinds/MirroredBars.d.ts.map +1 -1
- package/dist/charts/kinds/MirroredBars.js +10 -68
- 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/primitives/CartesianChart.d.ts.map +1 -1
- package/dist/charts/primitives/CartesianChart.js +49 -76
- package/dist/charts/primitives/ChartCard.d.ts.map +1 -1
- package/dist/charts/primitives/ChartCard.js +5 -23
- package/dist/charts/primitives/ChartFrame.d.ts.map +1 -1
- package/dist/charts/primitives/ChartFrame.js +23 -40
- package/dist/charts/primitives/ChartLegend.d.ts.map +1 -1
- package/dist/charts/primitives/ChartLegend.js +5 -133
- 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 +16 -1
- package/dist/charts/primitives/HoverOverlay.d.ts +24 -9
- package/dist/charts/primitives/HoverOverlay.d.ts.map +1 -1
- package/dist/charts/primitives/HoverOverlay.js +17 -1
- package/dist/charts/primitives/chart-card-context.d.ts +17 -13
- package/dist/charts/primitives/chart-card-context.d.ts.map +1 -1
- package/dist/charts/primitives/chart-card-context.js +10 -5
- package/dist/charts/primitives/chart-frame-layout.d.ts.map +1 -1
- package/dist/charts/primitives/chart-frame-layout.js +25 -31
- 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/controls/controls.module.css +5 -0
- package/dist/controls/sync-button.module.css +1 -0
- package/dist/dashboard/stat-group.module.css +19 -64
- package/dist/dashboard/widget-grid.module.css +11 -38
- 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 +33 -2
- package/dist/data/data-table.d.ts.map +1 -1
- package/dist/data/data-table.js +179 -277
- package/dist/forms/form-layout.module.css +3 -13
- package/dist/guard/index.d.ts.map +1 -1
- package/dist/guard/index.js +6 -5
- package/dist/notifications/center.d.ts.map +1 -1
- package/dist/provider/index.d.ts.map +1 -1
- package/dist/provider/index.js +12 -10
- 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 +0 -11
- package/dist/shell/index.d.ts.map +1 -1
- package/dist/shell/index.js +13 -14
- package/dist/shell/use-breakpoint.d.ts +1 -1
- package/dist/theme/floating.module.css +1 -0
- package/dist/theme-lab/derive-controls.d.ts.map +1 -1
- package/llms.txt +2 -2
- package/package.json +2 -1
- package/src/charts/kinds/BandStrip.tsx +18 -64
- package/src/charts/kinds/DualPanel.tsx +4 -24
- package/src/charts/kinds/MirroredBars.tsx +12 -66
- package/src/charts/kinds/band-chrome.tsx +91 -0
- package/src/charts/primitives/CartesianChart.tsx +79 -122
- package/src/charts/primitives/ChartCard.tsx +5 -27
- package/src/charts/primitives/ChartFrame.tsx +37 -76
- package/src/charts/primitives/ChartLegend.tsx +7 -154
- package/src/charts/primitives/ChartTooltip.tsx +16 -0
- package/src/charts/primitives/HoverOverlay.tsx +52 -21
- package/src/charts/primitives/chart-card-context.ts +25 -16
- package/src/charts/primitives/chart-frame-layout.ts +44 -56
- package/src/charts/primitives/legend-disclosure.tsx +177 -0
- package/src/controls/controls.module.css +5 -0
- package/src/controls/sync-button.module.css +1 -0
- package/src/dashboard/stat-group.module.css +19 -64
- package/src/dashboard/widget-grid.module.css +11 -38
- package/src/data/data-table-state.ts +218 -0
- package/src/data/data-table.tsx +127 -218
- package/src/forms/form-layout.module.css +3 -13
- package/src/guard/index.ts +21 -16
- package/src/notifications/center.tsx +3 -0
- package/src/provider/index.tsx +18 -17
- package/src/shell/aside-docking.ts +54 -0
- package/src/shell/index.tsx +15 -37
- package/src/shell/use-breakpoint.ts +2 -2
- package/src/theme/floating.module.css +1 -0
- package/src/theme-lab/derive-controls.tsx +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,26 @@
|
|
|
1
|
+
# [1.32.0](https://github.com/jkrumm/basalt-ui/compare/v1.31.0...v1.32.0) (2026-09-30)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* build BasaltDataTable cards only in card mode, guard the routed-prop lookup ([4024e83](https://github.com/jkrumm/basalt-ui/commit/4024e8333c83cb4808507929f47246209e67a00a))
|
|
7
|
+
* exempt a container Grid only when its breakpoints map resolves ([d6d9bda](https://github.com/jkrumm/basalt-ui/commit/d6d9bdaa7eb693a01166d121fdc5bb95002bb09d))
|
|
8
|
+
* honour maxHeight in BasaltDataTable's card projection ([3b59a2f](https://github.com/jkrumm/basalt-ui/commit/3b59a2f5304969e0dcadfa77b1ff375fd0f1d048))
|
|
9
|
+
* key StatGroup and WidgetGrid on the container-class law ([db6e130](https://github.com/jkrumm/basalt-ui/commit/db6e130d050d562926fce63e7f1a5e3d0aeb45f8))
|
|
10
|
+
* move raw-media-query's promotion to 1.33.0 with its AST twin ([ac2641c](https://github.com/jkrumm/basalt-ui/commit/ac2641c4ac1fcb42b2381758ae9a2b20809ce630))
|
|
11
|
+
* move useBreakpoint's removal to 1.33.0 and correct its replacement ([a2c356b](https://github.com/jkrumm/basalt-ui/commit/a2c356bd1979960b8b9fc26eb8341cc84d3e88ee))
|
|
12
|
+
* narrow the container-grid exemption to the props Mantine routes ([d547022](https://github.com/jkrumm/basalt-ui/commit/d5470226008984fba39849062c0ee0abbac178cc))
|
|
13
|
+
* prune ignored dirs during the doc-drift repo walk instead of after it ([a4647dc](https://github.com/jkrumm/basalt-ui/commit/a4647dcd380f74f7ac73989fa6857d2041d16a23))
|
|
14
|
+
* read only width clauses when judging a shell/ media query ([3f14b7f](https://github.com/jkrumm/basalt-ui/commit/3f14b7f342c64c9f2b7b1b04887930f37f695f01))
|
|
15
|
+
* say legend.maxRows changed unit in its deprecation warning ([29ad3a5](https://github.com/jkrumm/basalt-ui/commit/29ad3a5183648a0edc71250b22a996fa818edfb8))
|
|
16
|
+
* stop warning legend-slot contention on a same-commit owner hand-off ([af18cfa](https://github.com/jkrumm/basalt-ui/commit/af18cfad7c3d9747a7cc6c0a117db34bbb8cd531))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### Features
|
|
20
|
+
|
|
21
|
+
* give basalt/raw-breakpoint a reachable container-grid answer ([2bf4a22](https://github.com/jkrumm/basalt-ui/commit/2bf4a2256fff9b08adcd6c3716b92993b4fdb40a))
|
|
22
|
+
* project BasaltDataTable rows as cards on the table's own width ([f201b2a](https://github.com/jkrumm/basalt-ui/commit/f201b2ac81726fc47b2adb5660fd42ce2c881b3e))
|
|
23
|
+
|
|
1
24
|
# [1.31.0](https://github.com/jkrumm/basalt-ui/compare/v1.30.2...v1.31.0) (2026-09-28)
|
|
2
25
|
|
|
3
26
|
|
package/MIGRATING.md
CHANGED
|
@@ -66,18 +66,18 @@ There is one row per SURFACE, not per export, and a surface earns a row once any
|
|
|
66
66
|
shipped lefthook preset both changed in 1.30.0 with no row that owned them — which is how a
|
|
67
67
|
consumer read this index, found nothing, and diffed a KPI row that had silently gone 4-up → 2-up.
|
|
68
68
|
|
|
69
|
-
| Surface | 1.27.0 | 1.28.0 | 1.29.0 | 1.30.0 | 1.30.1 | 1.30.2 | 1.31.0 | Unreleased |
|
|
70
|
-
| ----------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------- | ------ | --------------------------------------------------------------------------------------------------------- | ---------- |
|
|
71
|
-
| **tokens** (`./tokens`) | — | `--vx-divider` → `rgba()` on both schemes (§ Shell) | `--vx-space-touch-target` added (§ Additions) | eight spacing numbers (§ Chrome) | — | — | `--vx-hit` replaces the touch vars; `SIZE_CLASSES` (§ Unreleased) | — |
|
|
72
|
-
| **charts** (`./charts`) | — | phone tier, `curve`, formatters, `state`, log axis (§ preamble) | `ChartState.empty: string`, `AxisBottomNumeric` (§ Additions) | responsive `height`, `legend.maxRows` (§ Charts) | `height` reaches the kinds; `maxRows` beats the `fill` fit (§ Charts) | — | container-class tier + `height` keys (§ Unreleased) | — |
|
|
73
|
-
| **shell** (`.`) | — | scrollport, region seams, **the brand left the sidebar** (§§ scrollport, brand, Shell) | `PageTitle`, `BasaltDevDock`, `useBreakpoint` (§ Additions) | More popover, aside pill, the responsive gutter, `useBasaltSpacing` (§ Chrome) | — | — | `theme.breakpoints` derived, `useSizeClass`, `data-basalt-host`, `useBreakpoint` on notice (§ Unreleased) | — |
|
|
74
|
-
| **controls** (`./controls`) | `NumberFilter`, `field.number` (§ Controls) | sheet renders panel rows; `PanelRow`, `SliderControl` (§ `basalt-ui/controls`) | — | — | — | — | — | — |
|
|
75
|
-
| **forms** (`./forms`) | — | `field` → `inputProps`, **`inputProps` drops `key`**, the layout tier (§ `inputProps`) | `field` DELETED — and the `--fix` recipe no longer works (§ Consolidation) | — | — | — | — | — |
|
|
76
|
-
| **data** (`./data/table`) | — | root is a `<div>`, row selection, `getItemKey` required (§ `basalt-ui/data`) | `./data` + `./query` + `./connectivity` dropped (§ Consolidation) | — | — | — | — | — |
|
|
77
|
-
| **dashboard** (`.`) | `StatCard`: `unit`, `breakdown`, delta format (§ `StatCard`) | `StatGroup`, `WidgetGrid`, query-aware `StatCard` — additive | — | **the column law keys on the CONTAINER; `cols={4}` is 2-up at `sm`** (§ Dashboard) | — | — | — | — |
|
|
78
|
-
| **toolchain** (`./configs/*`) | — | — | the shipped lefthook preset's `check-theme` BROKE — the CLI resolver stopped ascending (§ CLI) | the preset's default bin, and the `root:` recipe (§ Toolchain) | — | — | — | — |
|
|
79
|
-
| **CLI** (`basalt-ui`) | — | — | **resolver stops relocating; `doctor` loses 6 of 10 checks** (§ CLI) | — | — | — | — | — |
|
|
80
|
-
| **guards** | five rules → `error` (§ Guards) | six new ids at `warn` (§ preamble) | `query-dual-import` retired in 1.29.1 (§ Guards) | four rules → `error` (§ Guards) | — | — | — | — |
|
|
69
|
+
| Surface | 1.27.0 | 1.28.0 | 1.29.0 | 1.30.0 | 1.30.1 | 1.30.2 | 1.31.0 | 1.32.0 | Unreleased |
|
|
70
|
+
| ----------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- | --------------------------------------------------------------------- | ------ | --------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ---------- |
|
|
71
|
+
| **tokens** (`./tokens`) | — | `--vx-divider` → `rgba()` on both schemes (§ Shell) | `--vx-space-touch-target` added (§ Additions) | eight spacing numbers (§ Chrome) | — | — | `--vx-hit` replaces the touch vars; `SIZE_CLASSES` (§ Unreleased) | — | — |
|
|
72
|
+
| **charts** (`./charts`) | — | phone tier, `curve`, formatters, `state`, log axis (§ preamble) | `ChartState.empty: string`, `AxisBottomNumeric` (§ Additions) | responsive `height`, `legend.maxRows` (§ Charts) | `height` reaches the kinds; `maxRows` beats the `fill` fit (§ Charts) | — | container-class tier + `height` keys (§ Unreleased) | — | — |
|
|
73
|
+
| **shell** (`.`) | — | scrollport, region seams, **the brand left the sidebar** (§§ scrollport, brand, Shell) | `PageTitle`, `BasaltDevDock`, `useBreakpoint` (§ Additions) | More popover, aside pill, the responsive gutter, `useBasaltSpacing` (§ Chrome) | — | — | `theme.breakpoints` derived, `useSizeClass`, `data-basalt-host`, `useBreakpoint` on notice (§ Unreleased) | `useBreakpoint` removal → 1.33.0; `useSizeClass` is shell-only (§ Unreleased) | — |
|
|
74
|
+
| **controls** (`./controls`) | `NumberFilter`, `field.number` (§ Controls) | sheet renders panel rows; `PanelRow`, `SliderControl` (§ `basalt-ui/controls`) | — | — | — | — | — | — | — |
|
|
75
|
+
| **forms** (`./forms`) | — | `field` → `inputProps`, **`inputProps` drops `key`**, the layout tier (§ `inputProps`) | `field` DELETED — and the `--fix` recipe no longer works (§ Consolidation) | — | — | — | — | — | — |
|
|
76
|
+
| **data** (`./data/table`) | — | root is a `<div>`, row selection, `getItemKey` required (§ `basalt-ui/data`) | `./data` + `./query` + `./connectivity` dropped (§ Consolidation) | — | — | — | — | — | — |
|
|
77
|
+
| **dashboard** (`.`) | `StatCard`: `unit`, `breakdown`, delta format (§ `StatCard`) | `StatGroup`, `WidgetGrid`, query-aware `StatCard` — additive | — | **the column law keys on the CONTAINER; `cols={4}` is 2-up at `sm`** (§ Dashboard) | — | — | — | — | — |
|
|
78
|
+
| **toolchain** (`./configs/*`) | — | — | the shipped lefthook preset's `check-theme` BROKE — the CLI resolver stopped ascending (§ CLI) | the preset's default bin, and the `root:` recipe (§ Toolchain) | — | — | — | — | — |
|
|
79
|
+
| **CLI** (`basalt-ui`) | — | — | **resolver stops relocating; `doctor` loses 6 of 10 checks** (§ CLI) | — | — | — | — | — | — |
|
|
80
|
+
| **guards** | five rules → `error` (§ Guards) | six new ids at `warn` (§ preamble) | `query-dual-import` retired in 1.29.1 (§ Guards) | four rules → `error` (§ Guards) | — | — | — | `raw-breakpoint`: the container-grid answer, `error` at 1.33.0 (§ Unreleased) | — |
|
|
81
81
|
|
|
82
82
|
---
|
|
83
83
|
|
|
@@ -86,6 +86,88 @@ consumer read this index, found nothing, and diffed a KPI row that had silently
|
|
|
86
86
|
_Nothing yet. Author the next section under this heading as `## Unreleased — <title>`; the
|
|
87
87
|
release renames it and opens a new one here._
|
|
88
88
|
|
|
89
|
+
## 1.32.0 — `basalt/raw-breakpoint` gets its answer
|
|
90
|
+
|
|
91
|
+
### The C1 pair (`control-outside-home` / `raw-selection-control`) — `error` at 1.33.0, the last extension
|
|
92
|
+
|
|
93
|
+
Re-measured 2026-09-30: basalt's own tree 0, the fleet ~33 (image-gen 11, rb 7, image-share 6,
|
|
94
|
+
weatherorb 5, email-gateway 4, argo 2). Clear them on 1.32.0 while they still warn — the remedies
|
|
95
|
+
are unchanged (§ 1.31.0 below: a `PageBar` home, `basalt-ui/forms` rows, bound `FieldHandle`s, or a
|
|
96
|
+
reasoned `theme-allow`). 1.33.0 promotes all four ids — this pair plus `raw-breakpoint` and
|
|
97
|
+
`raw-media-query` — together.
|
|
98
|
+
|
|
99
|
+
### `basalt/raw-breakpoint`
|
|
100
|
+
|
|
101
|
+
1.31.0 shipped this rule (`warn`) with a message that said "reach for a container query" and named
|
|
102
|
+
no primitive, and this file never mentioned it. It flags four shapes; each has a concrete target
|
|
103
|
+
now. **Severity: `warn`, promotes to `error` at 1.33.0** (moved from 1.32.0 — this is the first
|
|
104
|
+
minor with a documented answer). A `theme-allow raw-breakpoint — <reason>` waives one occurrence.
|
|
105
|
+
|
|
106
|
+
**Its CSS twin, the `raw-media-query` guard kind** (`basalt-ui check-theme`), enforces the same law
|
|
107
|
+
in `.css`: a width `@media` outside `shell/**`, an `@container` name other than `basalt-card` /
|
|
108
|
+
`basalt-form` / `basalt-main` / `basalt-grid` or at a width off a `CONTAINER_CLASSES` boundary, and
|
|
109
|
+
a pointer query other than `coarse`/`fine`. Same `warn`, and it moved with the rule — **`error` at
|
|
110
|
+
1.33.0** (was 1.32.0). `theme-allow raw-media-query — <reason>` waives one line.
|
|
111
|
+
|
|
112
|
+
**The law.** `useSizeClass()` is for **shell chrome**. A page swapping its OWN layout — a column
|
|
113
|
+
count, a table for a card list, a row for a stack — is a **container** decision, keyed on
|
|
114
|
+
`CONTAINER_CLASSES` (`basalt-ui/tokens`: compact 240 · regular 480 · wide 800), not the viewport.
|
|
115
|
+
The primitive is Mantine 9's own `type="container"` grid. Verified against `@mantine/core` 9.3
|
|
116
|
+
source, which is what the rule's exemption is built on:
|
|
117
|
+
|
|
118
|
+
- `SimpleGrid type="container"` wraps itself in a `container: simple-grid / inline-size` div (no
|
|
119
|
+
ancestor needed) and writes **each key verbatim** into `@container simple-grid (min-width: <key>)`.
|
|
120
|
+
Keys are CSS lengths — `'480px'`, not `480` (unitless is invalid) and not `sm` (never resolved
|
|
121
|
+
through `theme.breakpoints`; emits a dead query). The rule flags `sm`-style keys there.
|
|
122
|
+
- `Grid type="container"` only goes container **when it also gets a `breakpoints` map**; without
|
|
123
|
+
one it silently renders viewport media queries (flagged). The map is typed
|
|
124
|
+
`Record<MantineSize, string>` — all five `xs`–`xl`, no custom names — and `Grid.Col` keys resolve
|
|
125
|
+
through it, so `sm` there means whatever width the map gives it (exempt).
|
|
126
|
+
|
|
127
|
+
| Shape (what it flags) | Replace with |
|
|
128
|
+
| ----------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
129
|
+
| responsive object on a Mantine prop — `SimpleGrid cols={{ base, sm }}` | `SimpleGrid type="container"` with px keys (below) |
|
|
130
|
+
| `Grid.Col span={{ base, lg }}` | `Grid type="container"` + a `breakpoints` map onto container widths; spans keyed through it |
|
|
131
|
+
| `Flex direction={{ base: 'column', sm: 'row' }}` | the container `SimpleGrid` (equal columns); a plain `Group` (wraps by default) for intrinsic-width items; or a CSS module: `container: basalt-grid / inline-size` on the parent, `@container basalt-grid (min-width: 480px)` on the child |
|
|
132
|
+
| `visibleFrom`/`hiddenFrom` outside a shell home or a control's C9 swap | the same container rule, `display` toggled in the CSS module — or drop the swap |
|
|
133
|
+
| `useMediaQuery`/`useMatches`/`useViewportSize` (`@mantine/*`), `window.matchMedia`/`innerWidth` | shell chrome: `useSizeClass()`; a page's layout: one of the above |
|
|
134
|
+
|
|
135
|
+
```tsx
|
|
136
|
+
// before — viewport breakpoints
|
|
137
|
+
<SimpleGrid cols={{ base: 1, sm: 3 }}>…</SimpleGrid>
|
|
138
|
+
<Grid><Grid.Col span={{ base: 12, lg: 4 }}>…</Grid.Col></Grid>
|
|
139
|
+
|
|
140
|
+
// after — the grid's own width
|
|
141
|
+
import { CONTAINER_CLASSES as C } from 'basalt-ui/tokens'
|
|
142
|
+
<SimpleGrid type="container" cols={{ base: 1, [`${C.regular}px`]: 3 }}>…</SimpleGrid>
|
|
143
|
+
const px = (n: number) => `${n}px`
|
|
144
|
+
const containerBreakpoints = { xs: px(C.compact), sm: px(C.regular), md: px(C.wide), lg: px(C.wide), xl: px(C.wide) }
|
|
145
|
+
<Grid type="container" breakpoints={containerBreakpoints}>
|
|
146
|
+
<Grid.Col span={{ base: 12, md: 4 }}>…</Grid.Col>
|
|
147
|
+
</Grid>
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Pick the container key by the grid's own width, not by the viewport key it replaces: a grid inside a
|
|
151
|
+
page with an aside or a sidebar is narrower than the viewport, which is the point.
|
|
152
|
+
|
|
153
|
+
### `StatGroup` / `WidgetGrid` — `sm` opens at 800px, container name `basalt-grid`
|
|
154
|
+
|
|
155
|
+
Both grids now key on the container-class law basalt ships: the `sm` column count opens at the
|
|
156
|
+
`wide` class (**800px** of the grid's own width, was 768); the full `cols` count still opens at
|
|
157
|
+
1200px. A grid 768–799px wide now renders its base count (StatGroup 2, WidgetGrid 1). The
|
|
158
|
+
container they declare is renamed `basalt-stat-group`/`basalt-widget-grid` → **`basalt-grid`** — only
|
|
159
|
+
a consumer rule written against the old names needs editing. The `@supports not (container-type)`
|
|
160
|
+
viewport fallbacks (these two and `FormRow`'s) are gone: every browser that parses basalt's
|
|
161
|
+
`color-mix()` also parses `@container`.
|
|
162
|
+
|
|
163
|
+
### `useBreakpoint` — removal moved to 1.33.0, and the 1.31.0 replacement line was half wrong
|
|
164
|
+
|
|
165
|
+
`useBreakpoint('sm')` → `useSizeClass() !== 'compact'` holds for **shell chrome only**. A page
|
|
166
|
+
swapping its own layout on it (argo's table ↔ card list) is a container decision — see above. Note
|
|
167
|
+
that `useSizeClass()` answers `'compact'` on the first frame (the server snapshot,
|
|
168
|
+
`<BasaltProvider sizeClassHint>`) where `useBreakpoint` returned `undefined`, so an
|
|
169
|
+
`isLg === true` guard written for that `undefined` can go.
|
|
170
|
+
|
|
89
171
|
## 1.31.0 — size classes and the pointer tier
|
|
90
172
|
|
|
91
173
|
`theme.breakpoints` is now derived from `SIZE_CLASSES` (compact < 840, medium 840–1199, expanded
|
|
@@ -93,7 +175,9 @@ release renames it and opens a new one here._
|
|
|
93
175
|
it out. Mapping: `xs` = `sm` = 52.5em (medium opens), `md` = `lg` = `xl` = 75em (expanded opens) — the
|
|
94
176
|
keys collapse. So `xs` moves 36em → 52.5em, `sm` 48em → 52.5em (an iPad portrait is now bottom-bar chrome), `md`
|
|
95
177
|
62em → 75em, `lg` stays 75em and `xl` 88em → 75em. Check every `visibleFrom`/`hiddenFrom`/`useBreakpoint`
|
|
96
|
-
on those keys: `xs` no longer differs from `sm`, and `md`/`lg`/`xl` now switch at the same width.
|
|
178
|
+
on those keys: `xs` no longer differs from `sm`, and `md`/`lg`/`xl` now switch at the same width. Outside a
|
|
179
|
+
shell home those props are `basalt/raw-breakpoint` findings — move them to a container grid rather
|
|
180
|
+
than re-keying them (see that section above).
|
|
97
181
|
|
|
98
182
|
| Removed | Replacement |
|
|
99
183
|
| --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
@@ -149,10 +233,10 @@ everywhere).
|
|
|
149
233
|
`storageKey`. Opt out with a controlled `collapsed` prop; a persisted `false` (the user opened it
|
|
150
234
|
once) pins it open.
|
|
151
235
|
|
|
152
|
-
**On notice — `useBreakpoint` (
|
|
153
|
-
`useBreakpoint('sm')` with `useSizeClass() !== 'compact'
|
|
154
|
-
`useSizeClass() === 'expanded'`. A
|
|
155
|
-
|
|
236
|
+
**On notice — `useBreakpoint` (removal moved to 1.33.0).** `@deprecated`, still works. For shell
|
|
237
|
+
chrome, replace `useBreakpoint('sm')` with `useSizeClass() !== 'compact'` and `useBreakpoint('lg')`
|
|
238
|
+
with `useSizeClass() === 'expanded'`. A page's own layout swap is a container decision, not a
|
|
239
|
+
`useSizeClass()` one — corrected after release; see the `basalt/raw-breakpoint` section above.
|
|
156
240
|
|
|
157
241
|
**Card chrome keys on the card's own width, not the viewport.** `ChartCard`, `StatCard` and `Section`
|
|
158
242
|
are now `container: basalt-card / inline-size` (`container-type: inline-size` — layout and inline-size
|
|
@@ -48,8 +48,7 @@ single mount (`basalt/hand-rolled-shell` fires on `AppShell.*` parts or a `Burge
|
|
|
48
48
|
does not render it). The sub-components are exported for a genuinely divergent layout; prefer the
|
|
49
49
|
shell, which already wires collapse persistence, the mobile breakpoint and the breadcrumb.
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
projection:
|
|
51
|
+
Extension points are **declared data, not `ReactNode` slots**, so basalt owns the mobile projection:
|
|
53
52
|
|
|
54
53
|
| Prop | Shape | What basalt then owns |
|
|
55
54
|
| ------------------- | ------------------------------------ | -------------------------------------------------------------------------------------- |
|
|
@@ -98,6 +97,8 @@ Depth-tier law (which token for which surface, why static, why the ring is inset
|
|
|
98
97
|
clears the iOS zoom threshold via an `!important` floor (`sub-16-input-font` flags a smaller one).
|
|
99
98
|
- **Charts measure themselves** — pass `height`/`aspectRatio`/`fill` only; never `useElementSize`
|
|
100
99
|
in a chart file (Mantine is banned there), never raw `@visx/responsive` outside `charts/**`.
|
|
100
|
+
- **A page's own layout keys on its container, not the viewport** — Mantine's `type="container"`
|
|
101
|
+
grids on `CONTAINER_CLASSES`; `useSizeClass()` is shell chrome only. Recipes: `MIGRATING.md`.
|
|
101
102
|
|
|
102
103
|
## Scroll regions
|
|
103
104
|
|
|
@@ -105,8 +106,7 @@ Depth-tier law (which token for which surface, why static, why the ring is inset
|
|
|
105
106
|
it draws its own bar inside its root, so the bar floats instead of reflowing the column
|
|
106
107
|
(`AppSidebar`'s nav is the reference: `type="hover"`, `scrollbars="y"`). Raw `overflow: auto` stays
|
|
107
108
|
correct only where a library owns the node (`BasaltStickToBottom`, `BasaltVirtualList`) and for a
|
|
108
|
-
table body (`Table.ScrollContainer type="native"` — a `ScrollArea` viewport
|
|
109
|
-
`<thead>`'s positioning context).
|
|
109
|
+
table body (`Table.ScrollContainer type="native"` — a `ScrollArea` viewport breaks a sticky `<thead>`).
|
|
110
110
|
|
|
111
111
|
## Interaction feedback and motion
|
|
112
112
|
|
package/configs/oxlint-plugin.js
CHANGED
|
@@ -2708,7 +2708,7 @@ const CONTROL_OUTSIDE_HOME_MESSAGE =
|
|
|
2708
2708
|
* `@mantine/form` (a form is the third home and its inputs are not filters), and the owner
|
|
2709
2709
|
* exemption — a file DEFINING a basalt control cannot be told to use one.
|
|
2710
2710
|
*/
|
|
2711
|
-
// Ships: warn (grace → 1.
|
|
2711
|
+
// Ships: warn (grace → 1.33.0)
|
|
2712
2712
|
const controlOutsideHome = {
|
|
2713
2713
|
meta: {
|
|
2714
2714
|
type: 'suggestion',
|
|
@@ -3656,8 +3656,9 @@ export const DEPRECATED_EXPORTS = [
|
|
|
3656
3656
|
{
|
|
3657
3657
|
subpath: 'basalt-ui',
|
|
3658
3658
|
name: 'useBreakpoint',
|
|
3659
|
-
replacement:
|
|
3660
|
-
|
|
3659
|
+
replacement:
|
|
3660
|
+
'useSizeClass() for shell chrome; a page’s own layout swap is a container decision — a type="container" SimpleGrid/Grid or an @container rule',
|
|
3661
|
+
removeIn: '1.33.0',
|
|
3661
3662
|
fix: false,
|
|
3662
3663
|
},
|
|
3663
3664
|
]
|
|
@@ -3959,14 +3960,16 @@ const RESPONSIVE_OBJECT_KEYS = new Set(['base', 'xs', 'sm', 'md', 'lg', 'xl'])
|
|
|
3959
3960
|
* object that merely happens to have a `sm` key among other, unrelated ones is not this shape, and
|
|
3960
3961
|
* an empty object is not a breakpoint decision at all.
|
|
3961
3962
|
*/
|
|
3962
|
-
function isResponsiveObjectValue(node) {
|
|
3963
|
+
function isResponsiveObjectValue(node, namedOnly = false) {
|
|
3963
3964
|
if (node === null || node === undefined || node.type !== 'ObjectExpression') return false
|
|
3964
3965
|
if (node.properties.length === 0) return false
|
|
3965
|
-
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3966
|
+
const names = node.properties.map((prop) =>
|
|
3967
|
+
prop.type === 'Property' ? propertyKeyName(prop) : undefined,
|
|
3968
|
+
)
|
|
3969
|
+
if (!names.every((name) => typeof name === 'string' && RESPONSIVE_OBJECT_KEYS.has(name)))
|
|
3970
|
+
return false
|
|
3971
|
+
// Under `type="container"` a lone `base` is the unconditional value, not a breakpoint decision.
|
|
3972
|
+
return !namedOnly || names.some((name) => name !== 'base')
|
|
3970
3973
|
}
|
|
3971
3974
|
|
|
3972
3975
|
/**
|
|
@@ -3977,17 +3980,91 @@ function isResponsiveObjectValue(node) {
|
|
|
3977
3980
|
* appears — the top-level attribute value and a nested property value alike. Matching only a nested
|
|
3978
3981
|
* `ObjectExpression` left the Identifier-in-a-property shape trivially bypassable.
|
|
3979
3982
|
*/
|
|
3980
|
-
function containsResponsiveObjectValue(node, consts, seen = new Set()) {
|
|
3983
|
+
function containsResponsiveObjectValue(node, consts, namedOnly = false, seen = new Set()) {
|
|
3981
3984
|
const resolved =
|
|
3982
3985
|
node !== null && node !== undefined && node.type === 'Identifier' ? consts.get(node.name) : node
|
|
3983
3986
|
if (resolved === null || resolved === undefined || resolved.type !== 'ObjectExpression')
|
|
3984
3987
|
return false
|
|
3985
3988
|
if (seen.has(resolved)) return false
|
|
3986
3989
|
seen.add(resolved)
|
|
3987
|
-
if (isResponsiveObjectValue(resolved)) return true
|
|
3990
|
+
if (isResponsiveObjectValue(resolved, namedOnly)) return true
|
|
3988
3991
|
return resolved.properties.some(
|
|
3989
|
-
(prop) =>
|
|
3992
|
+
(prop) =>
|
|
3993
|
+
prop.type === 'Property' &&
|
|
3994
|
+
containsResponsiveObjectValue(prop.value, consts, namedOnly, seen),
|
|
3995
|
+
)
|
|
3996
|
+
}
|
|
3997
|
+
|
|
3998
|
+
/**
|
|
3999
|
+
* The props each Mantine grid routes through `@container` queries under `type="container"` —
|
|
4000
|
+
* confirmed in `@mantine/core` 9.3 source: `SimpleGridContainerVariables` reads `cols`/`spacing`/
|
|
4001
|
+
* `verticalSpacing`, `GridVariables` reads `gap`/`rowGap`/`columnGap`, `GridColVariables` reads
|
|
4002
|
+
* `span`/`offset`/`order`/`align`. Every OTHER responsive prop on the same element (`p`, `mt`,
|
|
4003
|
+
* `mih`, …) is a Box style prop and still compiles to viewport `@media`, so the container exemption
|
|
4004
|
+
* stops at this set. `Grid`'s own `breakpoints` is the container scale itself, not a viewport key.
|
|
4005
|
+
*/
|
|
4006
|
+
const CONTAINER_ROUTED_PROPS = {
|
|
4007
|
+
SimpleGrid: new Set(['cols', 'spacing', 'verticalSpacing']),
|
|
4008
|
+
Grid: new Set(['gap', 'rowGap', 'columnGap', 'breakpoints']),
|
|
4009
|
+
'Grid.Col': new Set(['span', 'offset', 'order', 'align']),
|
|
4010
|
+
}
|
|
4011
|
+
|
|
4012
|
+
/**
|
|
4013
|
+
* How Mantine 9 resolves a responsive object on this element's grid, read from `@mantine/core`
|
|
4014
|
+
* 9.3 source — the sanctioned answer to this rule, so it has to be exempt exactly where it works:
|
|
4015
|
+
*
|
|
4016
|
+
* - `'container'` — a `<Grid type="container" breakpoints={…}>` (or a `Grid.Col` inside one) whose
|
|
4017
|
+
* map statically resolves to a non-empty object. Keys resolve through that map into
|
|
4018
|
+
* `@container mantine-grid` queries, so an `sm` key is whatever width the map gives it: exempt.
|
|
4019
|
+
* Mantine types the map as `Record<MantineSize, string>`, so the recipe's keys ARE `xs`–`xl` —
|
|
4020
|
+
* exempting by key name instead of by owner would flag the sanctioned answer itself.
|
|
4021
|
+
* - `'simple-grid'` — `<SimpleGrid type="container">`. `SimpleGridContainerVariables` writes each
|
|
4022
|
+
* key VERBATIM as `@container simple-grid (min-width: <key>)` and never consults
|
|
4023
|
+
* `theme.breakpoints`: a `'480px'` key works (and is not a responsive-object key, so it never
|
|
4024
|
+
* reaches here), while `sm` emits `(min-width: sm)` — invalid CSS, a dead query. Flagged.
|
|
4025
|
+
* - `'fallback'` — `<Grid type="container">` whose `breakpoints` is absent, `undefined`, `{}` or not
|
|
4026
|
+
* statically resolvable (or a `Grid.Col` in one). `Grid` takes its container branch only on a
|
|
4027
|
+
* truthy map, and an empty one emits no query at all — so none of these is the container law,
|
|
4028
|
+
* and an unreadable map is reported rather than trusted. Flagged.
|
|
4029
|
+
* - `undefined` — not a container grid; the ordinary viewport law applies.
|
|
4030
|
+
*
|
|
4031
|
+
* `type` has to be the string literal `"container"`; a dynamic value is not a decision this rule
|
|
4032
|
+
* can read. `Grid.Col` takes its grid's mode by walking to the nearest enclosing `Grid` element.
|
|
4033
|
+
* `consts` is the rule's same-file name→object map, so `breakpoints={map}` resolves like any value.
|
|
4034
|
+
*/
|
|
4035
|
+
function containerGridMode(opening, mantineImports, consts) {
|
|
4036
|
+
let tag = resolveMantineTag(opening.name, mantineImports)
|
|
4037
|
+
let grid = opening
|
|
4038
|
+
if (tag === 'Grid.Col') {
|
|
4039
|
+
grid = undefined
|
|
4040
|
+
let node = opening.parent?.parent
|
|
4041
|
+
for (let depth = 0; node !== null && node !== undefined; depth++, node = node.parent) {
|
|
4042
|
+
if (depth > ANCESTRY_MAX_DEPTH || node.type === 'Program') break
|
|
4043
|
+
if (node.type !== 'JSXElement') continue
|
|
4044
|
+
if (resolveMantineTag(node.openingElement.name, mantineImports) !== 'Grid') continue
|
|
4045
|
+
grid = node.openingElement
|
|
4046
|
+
tag = 'Grid'
|
|
4047
|
+
break
|
|
4048
|
+
}
|
|
4049
|
+
}
|
|
4050
|
+
if (grid === undefined || (tag !== 'Grid' && tag !== 'SimpleGrid')) return undefined
|
|
4051
|
+
const attr = (name) =>
|
|
4052
|
+
grid.attributes.find((a) => a.type === 'JSXAttribute' && a.name?.name === name)
|
|
4053
|
+
const type = attr('type')
|
|
4054
|
+
if (
|
|
4055
|
+
type === undefined ||
|
|
4056
|
+
!isStringLiteral(attrValue(type)) ||
|
|
4057
|
+
attrValue(type).value !== 'container'
|
|
3990
4058
|
)
|
|
4059
|
+
return undefined
|
|
4060
|
+
if (tag === 'SimpleGrid') return 'simple-grid'
|
|
4061
|
+
const breakpoints = attr('breakpoints')
|
|
4062
|
+
if (breakpoints === undefined) return 'fallback'
|
|
4063
|
+
let map = attrValue(breakpoints)
|
|
4064
|
+
if (map?.type === 'Identifier') map = consts.get(map.name)
|
|
4065
|
+
const nonEmpty =
|
|
4066
|
+
map?.type === 'ObjectExpression' && map.properties.some((prop) => prop.type === 'Property')
|
|
4067
|
+
return nonEmpty ? 'container' : 'fallback'
|
|
3991
4068
|
}
|
|
3992
4069
|
|
|
3993
4070
|
/**
|
|
@@ -4011,27 +4088,44 @@ const SHELL_HOME_NAMES = new Set(['BasaltShell', 'AppSidebar', 'MobileNav', 'App
|
|
|
4011
4088
|
*/
|
|
4012
4089
|
const RAW_BREAKPOINT_EXEMPT_FILE = /(?:^|[\\/])(?:use-media-query\.ts|ChartTooltip\.tsx)$/
|
|
4013
4090
|
|
|
4091
|
+
/**
|
|
4092
|
+
* The one recipe every raw-breakpoint message points at. A page's own layout keys on its CONTAINER
|
|
4093
|
+
* (`CONTAINER_CLASSES`, `basalt-ui/tokens`: compact 240 / regular 480 / wide 800), never on the
|
|
4094
|
+
* viewport — `useSizeClass()` is the shell's seam, not a page's. Mantine 9's own `type="container"`
|
|
4095
|
+
* grids are the primitive: both self-wrap in an `inline-size` container, so they need no ancestor.
|
|
4096
|
+
* The px literals are `CONTAINER_CLASSES` written out (the plugin cannot import TS source);
|
|
4097
|
+
* `oxlint-plugin.test.ts` asserts every one against it, and the MIGRATING recipe too.
|
|
4098
|
+
*/
|
|
4099
|
+
export const RAW_BREAKPOINT_RECIPE =
|
|
4100
|
+
'A page’s own layout keys on its container: <SimpleGrid type="container" cols={{ base: 1, ' +
|
|
4101
|
+
"'480px': 2, '800px': 3 }}> (px keys = CONTAINER_CLASSES, basalt-ui/tokens), or <Grid " +
|
|
4102
|
+
'type="container" breakpoints={…}> mapping all five xs–xl onto those px widths, with Grid.Col ' +
|
|
4103
|
+
'span={{ base: 12, sm: 6 }} keyed through that map; a Flex direction swap becomes that SimpleGrid (equal ' +
|
|
4104
|
+
'columns), a wrapping Group, or a CSS-module @container basalt-grid rule. useSizeClass() is for ' +
|
|
4105
|
+
'shell chrome only. Recipes: basalt-ui MIGRATING.md § basalt/raw-breakpoint.'
|
|
4106
|
+
|
|
4014
4107
|
const RAW_BREAKPOINT_RESPONSIVE_PROP_MESSAGE =
|
|
4015
|
-
'Responsive-object
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4108
|
+
'Responsive-object prop keyed on theme breakpoints — those are viewport widths. ' +
|
|
4109
|
+
`${RAW_BREAKPOINT_RECIPE} (basalt/raw-breakpoint)`
|
|
4110
|
+
|
|
4111
|
+
const RAW_BREAKPOINT_CONTAINER_KEY_MESSAGE =
|
|
4112
|
+
'Theme breakpoint name under type="container" — Mantine does not resolve it there: ' +
|
|
4113
|
+
"SimpleGrid uses each key verbatim as a (min-width: …) length, so 'sm' is a dead query, " +
|
|
4114
|
+
'and Grid only goes container with a breakpoints map (without one it silently falls back to ' +
|
|
4115
|
+
`viewport media queries). ${RAW_BREAKPOINT_RECIPE} (basalt/raw-breakpoint)`
|
|
4019
4116
|
|
|
4020
4117
|
const RAW_BREAKPOINT_VISIBLE_HIDDEN_MESSAGE =
|
|
4021
|
-
"visibleFrom/hiddenFrom outside a shell home or a control's own C9 swap —
|
|
4022
|
-
|
|
4023
|
-
"the framework cannot see or move. Use a container query for a component's own width instead. " +
|
|
4024
|
-
'(basalt/raw-breakpoint)'
|
|
4118
|
+
"visibleFrom/hiddenFrom outside a shell home or a control's own C9 swap — a viewport " +
|
|
4119
|
+
`breakpoint the framework cannot see or move. ${RAW_BREAKPOINT_RECIPE} (basalt/raw-breakpoint)`
|
|
4025
4120
|
|
|
4026
4121
|
const RAW_BREAKPOINT_HOOK_MESSAGE =
|
|
4027
|
-
"useMediaQuery/useMatches/useViewportSize — a raw viewport read outside the framework's
|
|
4028
|
-
'
|
|
4029
|
-
|
|
4122
|
+
"useMediaQuery/useMatches/useViewportSize — a raw viewport read outside the framework's " +
|
|
4123
|
+
'one seam. Shell chrome reads useSizeClass(); a page swapping its own layout (a table for a card ' +
|
|
4124
|
+
`list, a column count) is a container decision. ${RAW_BREAKPOINT_RECIPE} (basalt/raw-breakpoint)`
|
|
4030
4125
|
|
|
4031
4126
|
const RAW_BREAKPOINT_GLOBAL_MESSAGE =
|
|
4032
|
-
'window.matchMedia/window.innerWidth read directly — the
|
|
4033
|
-
|
|
4034
|
-
'(basalt/raw-breakpoint)'
|
|
4127
|
+
'window.matchMedia/window.innerWidth read directly — the viewport read useSizeClass() owns ' +
|
|
4128
|
+
`for shell chrome. ${RAW_BREAKPOINT_RECIPE} (basalt/raw-breakpoint)`
|
|
4035
4129
|
|
|
4036
4130
|
/** The three viewport hooks the law names, whatever module they are imported from. */
|
|
4037
4131
|
const RAW_BREAKPOINT_HOOK_NAMES = new Set(['useMediaQuery', 'useMatches', 'useViewportSize'])
|
|
@@ -4047,7 +4141,7 @@ const RAW_BREAKPOINT_HOOK_NAMES = new Set(['useMediaQuery', 'useMatches', 'useVi
|
|
|
4047
4141
|
* declares a shell home (or a control's own C9 swap) is exempt for all four shapes uniformly — the
|
|
4048
4142
|
* shell's own responsive chrome is the sanctioned use, whatever shape it takes.
|
|
4049
4143
|
*/
|
|
4050
|
-
// Ships: warn (grace → 1.
|
|
4144
|
+
// Ships: warn (grace → 1.33.0)
|
|
4051
4145
|
const rawBreakpoint = {
|
|
4052
4146
|
meta: {
|
|
4053
4147
|
type: 'suggestion',
|
|
@@ -4056,7 +4150,8 @@ const rawBreakpoint = {
|
|
|
4056
4150
|
'Disallow a hand-rolled viewport breakpoint — a responsive-object Mantine prop, ' +
|
|
4057
4151
|
'visibleFrom/hiddenFrom outside a shell home, useMediaQuery/useMatches/useViewportSize, or ' +
|
|
4058
4152
|
'a raw window.matchMedia/innerWidth read. All four shapes are exempt inside a file that ' +
|
|
4059
|
-
'declares a shell-home component (or a control implementing its own C9 swap)
|
|
4153
|
+
'declares a shell-home component (or a control implementing its own C9 swap); a ' +
|
|
4154
|
+
'responsive object on a Mantine type="container" grid is exempt where Mantine resolves it.',
|
|
4060
4155
|
},
|
|
4061
4156
|
schema: [],
|
|
4062
4157
|
},
|
|
@@ -4153,12 +4248,27 @@ const rawBreakpoint = {
|
|
|
4153
4248
|
if (definesShellHome || controlOwner.isOwner()) return
|
|
4154
4249
|
for (const node of responsiveObjectCandidates) {
|
|
4155
4250
|
const value = unwrapExpressionContainer(node.value)
|
|
4156
|
-
if (!containsResponsiveObjectValue(value, responsiveObjectConsts)) continue
|
|
4157
4251
|
const owner = node.parent
|
|
4158
4252
|
if (owner === null || owner === undefined || owner.type !== 'JSXOpeningElement') continue
|
|
4159
|
-
|
|
4253
|
+
const tag = resolveMantineTag(owner.name, mantineImports)
|
|
4254
|
+
if (tag === undefined) continue
|
|
4255
|
+
// The container law reaches only the props Mantine routes through the grid's container
|
|
4256
|
+
// queries; a `p={{ base, lg }}` on the same element is still a viewport @media.
|
|
4257
|
+
const routed = Object.hasOwn(CONTAINER_ROUTED_PROPS, tag)
|
|
4258
|
+
? CONTAINER_ROUTED_PROPS[tag]
|
|
4259
|
+
: undefined
|
|
4260
|
+
const mode = routed?.has(node.name.name)
|
|
4261
|
+
? containerGridMode(owner, mantineImports, responsiveObjectConsts)
|
|
4262
|
+
: undefined
|
|
4263
|
+
if (mode === 'container') continue
|
|
4264
|
+
if (!containsResponsiveObjectValue(value, responsiveObjectConsts, mode !== undefined))
|
|
4265
|
+
continue
|
|
4160
4266
|
if (hasThemeAllow(context, node, 'raw-breakpoint')) continue
|
|
4161
|
-
|
|
4267
|
+
const message =
|
|
4268
|
+
mode === undefined
|
|
4269
|
+
? RAW_BREAKPOINT_RESPONSIVE_PROP_MESSAGE
|
|
4270
|
+
: RAW_BREAKPOINT_CONTAINER_KEY_MESSAGE
|
|
4271
|
+
context.report({ node, message })
|
|
4162
4272
|
}
|
|
4163
4273
|
for (const node of visibleHiddenCandidates) {
|
|
4164
4274
|
if (hasThemeAllow(context, node, 'raw-breakpoint')) continue
|
|
@@ -4202,8 +4312,9 @@ const rawBreakpoint = {
|
|
|
4202
4312
|
export const PLUGIN_RULE_GRACE = {
|
|
4203
4313
|
'control-outside-home': {
|
|
4204
4314
|
since: '1.26.0',
|
|
4205
|
-
promote: '1.
|
|
4315
|
+
promote: '1.33.0',
|
|
4206
4316
|
why:
|
|
4317
|
+
"Extended 1.32.0 -> 1.33.0 at the 1.32.0 release, the last extension: basalt's own tree is at 0 (consumer-loop r1 dogfood) and argo is at 2, but RE-MEASURED 2026-09-30 the fleet carries ~33 (image-gen 11, rb 7, image-share 6, weatherorb 5, email-gateway 4, argo 2). The 1.32.0 fleet upgrade clears them while they warn, together with raw-breakpoint, so 1.33.0 promotes all four ids against a measured-clean fleet. " +
|
|
4207
4318
|
'Extended 1.31.0 -> 1.32.0 at the 1.31.0 release: the basalt tree still carries incumbents (data-table, notifications center, theme-lab) and the argo sweep has not run. ' +
|
|
4208
4319
|
'the wave-6 control guards (docs/CONTROLS-SPEC.md §6). The one openly HEURISTIC rule of the ' +
|
|
4209
4320
|
'set — "this control has no home" is a claim about layout intent, so its false-positive load ' +
|
|
@@ -4232,17 +4343,23 @@ export const PLUGIN_RULE_GRACE = {
|
|
|
4232
4343
|
},
|
|
4233
4344
|
'raw-breakpoint': {
|
|
4234
4345
|
since: '1.31.0',
|
|
4235
|
-
promote: '1.
|
|
4346
|
+
promote: '1.33.0',
|
|
4236
4347
|
why:
|
|
4237
|
-
'
|
|
4238
|
-
'
|
|
4239
|
-
'
|
|
4240
|
-
'
|
|
4241
|
-
"
|
|
4242
|
-
"
|
|
4243
|
-
'
|
|
4244
|
-
'1.32.0
|
|
4245
|
-
'
|
|
4348
|
+
'New in the wave-11 responsive/touch guards. Catches four independent shapes at once — a ' +
|
|
4349
|
+
'responsive-object Mantine prop, visibleFrom/hiddenFrom outside the three shell homes, the ' +
|
|
4350
|
+
'three raw viewport hooks, and window.matchMedia/innerWidth — none of which basalt policed ' +
|
|
4351
|
+
'before this wave, so every consumer on an earlier minor has a green build with all four ' +
|
|
4352
|
+
"shapes already in it. basalt-ui/content's own article-card.tsx (a `SimpleGrid cols={{ base: " +
|
|
4353
|
+
"1, sm: 2, lg }}`) was one incumbent measured in basalt's own tree at ship time — a real " +
|
|
4354
|
+
'number, not zero, so it shipped warn rather than error. ' +
|
|
4355
|
+
'Extended 1.32.0 -> 1.33.0: 1.31.0 shipped the rule naming "a container query" but no ' +
|
|
4356
|
+
'primitive, and MIGRATING never mentioned it (argo: 42 warns, no documented target). 1.32.0 ' +
|
|
4357
|
+
'is the first minor with a reachable, documented answer (Mantine type="container" grids keyed ' +
|
|
4358
|
+
'on CONTAINER_CLASSES, exempted here), and promoting in the minor that first makes a rule ' +
|
|
4359
|
+
'satisfiable hands a consumer zero minors to act on it — the control-outside-home ' +
|
|
4360
|
+
"extension's reasoning. 1.33.0 is when the incumbents are expected to have moved to a " +
|
|
4361
|
+
'container grid or a theme-allow with a stated reason. Promotes together with its CSS twin, ' +
|
|
4362
|
+
'the `raw-media-query` guard kind.',
|
|
4246
4363
|
},
|
|
4247
4364
|
}
|
|
4248
4365
|
|