basalt-ui 1.32.1 → 1.33.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 +39 -0
- package/MIGRATING.md +124 -24
- package/agent/rules/basalt-state.md +2 -2
- package/agent/rules/basalt-tokens.md +1 -1
- package/configs/oxlint-plugin.js +68 -61
- package/configs/oxlint-plugin.test.ts +126 -9
- package/configs/oxlint.json +2 -2
- package/dist/agent/coalesce.d.ts.map +1 -1
- package/dist/agent/coalesce.js +1 -2
- package/dist/agent/merge.d.ts.map +1 -1
- package/dist/agent/merge.js +1 -2
- package/dist/agent-chat/relative-time.d.ts +9 -0
- package/dist/agent-chat/relative-time.d.ts.map +1 -1
- package/dist/agent-chat/relative-time.js +1 -2
- package/dist/agent-chat/thread-message.d.ts.map +1 -1
- package/dist/agent-chat/thread-message.js +1 -2
- package/dist/charts/kinds/BandStrip.d.ts.map +1 -1
- package/dist/charts/kinds/BandStrip.js +3 -3
- package/dist/charts/kinds/Bars.d.ts.map +1 -1
- package/dist/charts/kinds/Bars.js +1 -2
- package/dist/charts/kinds/StackedArea.d.ts.map +1 -1
- package/dist/charts/kinds/StackedArea.js +1 -2
- package/dist/charts/primitives/legend-disclosure.d.ts.map +1 -1
- package/dist/cli/audit-allows.d.ts +1 -1
- package/dist/cli/audit-allows.d.ts.map +1 -1
- package/dist/cli/audit-allows.js +4 -4
- package/dist/cli/check-theme.d.ts.map +1 -1
- package/dist/cli/check-theme.js +1 -2
- package/dist/cli/config.d.ts +197 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +20 -0
- package/dist/cli/doctor.js +1 -1
- package/dist/cli/guard-hook.d.ts.map +1 -1
- package/dist/cli/guard-hook.js +2 -8
- package/dist/cli/index.d.ts +2 -196
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +1 -18
- package/dist/commands/define-commands.d.ts.map +1 -1
- package/dist/commands/define-commands.js +2 -2
- package/dist/commands/define-overlays.d.ts.map +1 -1
- package/dist/commands/define-overlays.js +1 -2
- package/dist/common/index.d.ts +0 -1
- package/dist/common/index.d.ts.map +1 -1
- package/dist/common/index.js +0 -2
- package/dist/common/validate.d.ts +2 -2
- package/dist/common/validate.d.ts.map +1 -1
- package/dist/common/validate.js +2 -3
- package/dist/content/article-card.d.ts.map +1 -1
- package/dist/content/article-card.js +4 -1
- package/dist/controls/enum-filter.d.ts.map +1 -1
- package/dist/controls/enum-filter.js +3 -13
- package/dist/controls/filter-pill.d.ts +8 -0
- package/dist/controls/filter-pill.d.ts.map +1 -1
- package/dist/controls/filter-pill.js +15 -0
- package/dist/controls/multi-select-filter.d.ts.map +1 -1
- package/dist/controls/multi-select-filter.js +3 -13
- package/dist/controls/number-filter.d.ts +3 -0
- package/dist/controls/number-filter.d.ts.map +1 -1
- package/dist/controls/number-filter.js +12 -4
- package/dist/controls/range-filter.d.ts.map +1 -1
- package/dist/controls/range-filter.js +1 -2
- package/dist/data/data-table.d.ts.map +1 -1
- package/dist/data/data-table.js +2 -3
- package/dist/guard/index.d.ts +16 -2
- package/dist/guard/index.d.ts.map +1 -1
- package/dist/guard/index.js +63 -22
- package/dist/guard/types.d.ts +3 -3
- package/dist/guard/types.d.ts.map +1 -1
- package/dist/guard/vx-names.d.ts +3 -0
- package/dist/guard/vx-names.d.ts.map +1 -0
- package/dist/guard/vx-names.js +257 -0
- package/dist/notifications/mount-guard.d.ts.map +1 -1
- package/dist/notifications/mount-guard.js +1 -2
- package/dist/provider/index.d.ts.map +1 -1
- package/dist/provider/index.js +2 -3
- package/dist/provider/lab-theme.d.ts +5 -4
- package/dist/provider/lab-theme.d.ts.map +1 -1
- package/dist/provider/lab-theme.js +1 -3
- package/dist/router-tanstack/search-store.d.ts +18 -0
- package/dist/router-tanstack/search-store.d.ts.map +1 -1
- package/dist/router-tanstack/search-store.js +33 -1
- package/dist/shell/mobile-nav-model.d.ts.map +1 -1
- package/dist/shell/mobile-nav-model.js +3 -4
- package/dist/shell/page-bar.d.ts.map +1 -1
- package/dist/shell/page-bar.js +1 -2
- package/dist/surfaces.d.ts +1 -1
- package/dist/surfaces.d.ts.map +1 -1
- package/dist/surfaces.js +2 -0
- package/dist/tokens/index.d.ts +1 -1
- package/dist/tokens/index.d.ts.map +1 -1
- package/dist/tokens/index.js +7 -1
- package/dist/tokens/size-classes.d.ts +13 -0
- package/dist/tokens/size-classes.d.ts.map +1 -1
- package/dist/tokens/size-classes.js +8 -0
- package/llms.txt +2 -2
- package/package.json +1 -1
- package/src/agent/coalesce.ts +1 -2
- package/src/agent/merge.ts +1 -2
- package/src/agent-chat/relative-time.ts +1 -2
- package/src/agent-chat/thread-message.tsx +2 -3
- package/src/charts/kinds/BandStrip.tsx +7 -3
- package/src/charts/kinds/Bars.tsx +1 -2
- package/src/charts/kinds/StackedArea.tsx +4 -2
- package/src/charts/primitives/legend-disclosure.tsx +1 -0
- package/src/cli/audit-allows.ts +10 -9
- package/src/cli/check-theme.ts +1 -2
- package/src/cli/config.ts +209 -0
- package/src/cli/doctor.ts +2 -2
- package/src/cli/guard-hook.ts +2 -8
- package/src/cli/index.ts +2 -206
- package/src/commands/define-commands.ts +2 -2
- package/src/commands/define-overlays.ts +1 -2
- package/src/common/index.ts +0 -1
- package/src/common/validate.ts +4 -5
- package/src/content/article-card.tsx +1 -0
- package/src/controls/enum-filter.tsx +3 -13
- package/src/controls/filter-pill.tsx +20 -0
- package/src/controls/multi-select-filter.tsx +3 -13
- package/src/controls/number-filter.tsx +24 -3
- package/src/controls/range-filter.tsx +1 -2
- package/src/data/data-table.tsx +2 -3
- package/src/guard/index.ts +136 -46
- package/src/guard/types.ts +3 -2
- package/src/guard/vx-names.ts +257 -0
- package/src/notifications/mount-guard.ts +1 -2
- package/src/provider/index.tsx +2 -3
- package/src/provider/lab-theme.ts +28 -21
- package/src/router-tanstack/search-store.ts +73 -1
- package/src/shell/mobile-nav-model.ts +3 -5
- package/src/shell/page-bar.tsx +1 -4
- package/src/surfaces.ts +2 -0
- package/src/tokens/index.ts +6 -1
- package/src/tokens/size-classes.ts +14 -0
- package/dist/common/is-dev.d.ts +0 -3
- package/dist/common/is-dev.d.ts.map +0 -1
- package/dist/common/is-dev.js +0 -6
- package/src/common/is-dev.ts +0 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,42 @@
|
|
|
1
|
+
# [1.33.0](https://github.com/jkrumm/basalt-ui/compare/v1.32.1...v1.33.0) (2026-10-01)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* audit-allows asks oxlint about dual-lane and mixed waivers ([9e0a3d5](https://github.com/jkrumm/basalt-ui/commit/9e0a3d5a43cd9e27625801dd28c3360975f155ed))
|
|
7
|
+
* audit-allows probes bare line-scope waivers through oxlint ([b5d53f9](https://github.com/jkrumm/basalt-ui/commit/b5d53f9c8e3ac1712e455dd0fd7310d88358104f))
|
|
8
|
+
* break the audit-allows → index → check-theme → audit-allows cycle ([98d746c](https://github.com/jkrumm/basalt-ui/commit/98d746cd13e36b7cbf5fa809e120c91cd9d23c53))
|
|
9
|
+
* count only real declaration positions as a local --vx declaration ([4b5b723](https://github.com/jkrumm/basalt-ui/commit/4b5b723c994c6f6c2b01612f5a303649881f3cc2))
|
|
10
|
+
* gate the lab store on the dotted NODE_ENV form, record the fold matrix ([7d336b5](https://github.com/jkrumm/basalt-ui/commit/7d336b5209aa7be846ba11faa935e31e5aa8f795))
|
|
11
|
+
* gen-vx-names reads CSS declarations in ts/tsx and says what QUOTED admits ([238cdb9](https://github.com/jkrumm/basalt-ui/commit/238cdb9fb887b6b703e61c684d0c657d3a9a6a5c))
|
|
12
|
+
* harden the provider-only budget's build, dist and externals handling ([8a20d0f](https://github.com/jkrumm/basalt-ui/commit/8a20d0f49784e496b7db9634a2ac83f97c01903d))
|
|
13
|
+
* judge a resets write against the URL at navigate time, not the render ([74a6dc7](https://github.com/jkrumm/basalt-ui/commit/74a6dc762965e470525e9aabe14e9f5e0972b07b))
|
|
14
|
+
* judge only the vx names basalt claims — removed names and bare roots ([bf15dab](https://github.com/jkrumm/basalt-ui/commit/bf15dab0704858022ec2c157b74e8183dda71586))
|
|
15
|
+
* keep the page when clear() leaves a field where it was ([2a6b40f](https://github.com/jkrumm/basalt-ui/commit/2a6b40faebb38011b2203b10382411c97fb6d551))
|
|
16
|
+
* keep the page when Reset all moves no field ([c12d01a](https://github.com/jkrumm/basalt-ui/commit/c12d01ae7fa998f569369b3fb347bc941c56cf6c))
|
|
17
|
+
* print a failed provider-only build as a budget row, not a stack ([66361ef](https://github.com/jkrumm/basalt-ui/commit/66361ef1a41019b6f096e33ffc0d13d28913e639))
|
|
18
|
+
* resolve the CONTAINER_GRID_BREAKPOINTS trust through the scope manager ([26f664b](https://github.com/jkrumm/basalt-ui/commit/26f664b6c5af662ce89f09ff1d839fd8fc34830e))
|
|
19
|
+
* see a --vx reference a formatter wrapped across lines ([ba469b1](https://github.com/jkrumm/basalt-ui/commit/ba469b12cc7513d90fbc5171e570cfacc83312bf))
|
|
20
|
+
* stop NumberFilter's Clear from committing the draft on its way ([04e3156](https://github.com/jkrumm/basalt-ui/commit/04e315682571ad9cca24cadd451accce0a312134))
|
|
21
|
+
* trust CONTAINER_GRID_BREAKPOINTS read off a namespace import ([cc15f76](https://github.com/jkrumm/basalt-ui/commit/cc15f760fbcafa041404b750f1e588c712108745))
|
|
22
|
+
* word the bare-waiver oxlint verdict by what it waives, not a fake id ([3b5e3b2](https://github.com/jkrumm/basalt-ui/commit/3b5e3b2757b0ff7b875dc1a337f4a8137e8c4bc3))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
### Features
|
|
26
|
+
|
|
27
|
+
* add clearable to NumberFilter for parity with SelectFilter ([a46d805](https://github.com/jkrumm/basalt-ui/commit/a46d805f97c1b60b93017ade2f6edb5a293fd302))
|
|
28
|
+
* add resets to createSearchStore for sibling params like page ([e809fd7](https://github.com/jkrumm/basalt-ui/commit/e809fd78e0b397f1ea52bb860b68bda5353c4943))
|
|
29
|
+
* promote the C1 and breakpoint twin pairs to error ([d49a5e2](https://github.com/jkrumm/basalt-ui/commit/d49a5e22b4f678f82f2377485f15ce6bc65c1be6))
|
|
30
|
+
* report removed and misspelled --vx-* names as unknown-vx-token ([6405f1a](https://github.com/jkrumm/basalt-ui/commit/6405f1af265cb7659026c1806bead121a22253f6))
|
|
31
|
+
* ship CONTAINER_GRID_BREAKPOINTS and let raw-breakpoint trust it ([4e3addb](https://github.com/jkrumm/basalt-ui/commit/4e3addbf50d1d358d8037389ad679d434ba00d98))
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
### Performance Improvements
|
|
35
|
+
|
|
36
|
+
* budget the provider-only first paint in check-budgets ([d36bed2](https://github.com/jkrumm/basalt-ui/commit/d36bed2c9c898490fddde0de126a36541ee25860))
|
|
37
|
+
* fold every dev-only gate out of production bundles ([25f94b7](https://github.com/jkrumm/basalt-ui/commit/25f94b79e81b045c05fe5eefb9479edebe195c43))
|
|
38
|
+
* keep the theme lab's store out of production first paint ([4e7512b](https://github.com/jkrumm/basalt-ui/commit/4e7512b41846e54fbb3d196ec157435c03b1c582))
|
|
39
|
+
|
|
1
40
|
## [1.32.1](https://github.com/jkrumm/basalt-ui/compare/v1.32.0...v1.32.1) (2026-09-30)
|
|
2
41
|
|
|
3
42
|
|
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 | 1.32.0 | 1.32.1 | 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` (§ 1.31.0) | — | `SIZE_CLASSES`/`CONTAINER_CLASSES` actually exported (§ Fixes) | — |
|
|
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 (§ 1.31.0) | — | `ResponsiveChartHeight` `sm` → key (§ Container recipes) | — |
|
|
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 (§ 1.31.0) | `useBreakpoint` removal → 1.33.0; `useSizeClass` is shell-only (§ 1.32.0) | shell-less `shell/` gutter, `AppShell` breakpoints, `useSizeClass` for overlays (§§ Shell-less, `useSizeClass`) | — |
|
|
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) | — | — | — | — | — | `FormGroup` row no longer stretches (§ Fixes) | — |
|
|
76
|
-
| **data** (`./data/table`) | — | root is a `<div>`, row selection, `getItemKey` required (§ `basalt-ui/data`) | `./data` + `./query` + `./connectivity` dropped (§ Consolidation) | — | — | — | — | — | `renderCard` documented (§ `renderCard`) | — |
|
|
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 (§ 1.32.0) | `FormRow`/`FormGroup` homes in both lanes; `basalt-main` dropped (§ Fixes) | — |
|
|
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 | 1.32.1 | 1.33.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` (§ 1.31.0) | — | `SIZE_CLASSES`/`CONTAINER_CLASSES` actually exported (§ Fixes) | `CONTAINER_GRID_BREAKPOINTS`; `raw-breakpoint` trusts it (§ 1.33.0) | — |
|
|
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 (§ 1.31.0) | — | `ResponsiveChartHeight` `sm` → key (§ Container recipes) | — | — |
|
|
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 (§ 1.31.0) | `useBreakpoint` removal → 1.33.0; `useSizeClass` is shell-only (§ 1.32.0) | shell-less `shell/` gutter, `AppShell` breakpoints, `useSizeClass` for overlays (§§ Shell-less, `useSizeClass`) | — | — |
|
|
74
|
+
| **controls** (`./controls`) | `NumberFilter`, `field.number` (§ Controls) | sheet renders panel rows; `PanelRow`, `SliderControl` (§ `basalt-ui/controls`) | — | — | — | — | — | — | — | `NumberFilter clearable`; `createSearchStore` `resets` (§ State and controls) | — |
|
|
75
|
+
| **forms** (`./forms`) | — | `field` → `inputProps`, **`inputProps` drops `key`**, the layout tier (§ `inputProps`) | `field` DELETED — and the `--fix` recipe no longer works (§ Consolidation) | — | — | — | — | — | `FormGroup` row no longer stretches (§ Fixes) | — | — |
|
|
76
|
+
| **data** (`./data/table`) | — | root is a `<div>`, row selection, `getItemKey` required (§ `basalt-ui/data`) | `./data` + `./query` + `./connectivity` dropped (§ Consolidation) | — | — | — | — | — | `renderCard` documented (§ `renderCard`) | — | — |
|
|
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 (§ 1.32.0) | `FormRow`/`FormGroup` homes in both lanes; `basalt-main` dropped (§ Fixes) | C1 + breakpoint pairs → `error`; `unknown-vx-token` `warn` (§ Guards) | — |
|
|
81
81
|
|
|
82
82
|
---
|
|
83
83
|
|
|
@@ -86,6 +86,105 @@ 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.33.0 — the 1.33.0 minor
|
|
90
|
+
|
|
91
|
+
### `CONTAINER_GRID_BREAKPOINTS` — the `Grid type="container"` map ships
|
|
92
|
+
|
|
93
|
+
`basalt-ui/tokens` exports the five-key map the 1.32.0 recipe had every consumer hand-write
|
|
94
|
+
(`xs` compact 240px · `sm` regular 480px · `md`/`lg`/`xl` wide 800px), derived from
|
|
95
|
+
`CONTAINER_CLASSES`. `basalt/raw-breakpoint` trusts it by name: before, it read an IMPORTED map as
|
|
96
|
+
unresolvable and flagged every `Grid.Col` span under it, so each route file declared its own
|
|
97
|
+
same-file literal (argo: five identical copies).
|
|
98
|
+
|
|
99
|
+
```tsx
|
|
100
|
+
import { CONTAINER_GRID_BREAKPOINTS } from 'basalt-ui/tokens'
|
|
101
|
+
;<Grid type="container" breakpoints={CONTAINER_GRID_BREAKPOINTS}>
|
|
102
|
+
<Grid.Col span={{ base: 12, md: 4 }}>…</Grid.Col>
|
|
103
|
+
</Grid>
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
| Delete | Replace with |
|
|
107
|
+
| ------------------------------------------------------------------------------------ | -------------------------------------------- |
|
|
108
|
+
| a same-file `const GRID_BREAKPOINTS = { xs: …, sm: …, md: …, lg: …, xl: … }` literal | `breakpoints={CONTAINER_GRID_BREAKPOINTS}` |
|
|
109
|
+
| a shared map you export yourself (flagged when imported) | the shipped one, or keep a same-file literal |
|
|
110
|
+
|
|
111
|
+
The trust is provenance-gated: the import must name `CONTAINER_GRID_BREAKPOINTS` from
|
|
112
|
+
`basalt-ui/tokens` (an alias `{ CONTAINER_GRID_BREAKPOINTS as bp }`, a namespace member
|
|
113
|
+
`tokens.CONTAINER_GRID_BREAKPOINTS` on `import * as tokens`, and a same-file `const bp = …` of
|
|
114
|
+
either all count; a parameter or inner `const` that shadows the name does not). A map of your own
|
|
115
|
+
that deviates from it — a 1200px `xl`, say — stays a same-file literal. `SimpleGrid type="container"` is unchanged: its keys
|
|
116
|
+
are CSS lengths, so ``[`${CONTAINER_CLASSES.regular}px`]`` stays the form.
|
|
117
|
+
|
|
118
|
+
### State and controls — `resets: ['page']`, `NumberFilter clearable`
|
|
119
|
+
|
|
120
|
+
Additive; nothing to change unless you carry one of the two workarounds below.
|
|
121
|
+
|
|
122
|
+
**`createSearchStore({ …, resets: ['page'] })`** drops the named sibling params — ones the store does
|
|
123
|
+
NOT own — in the same navigate as every URL-lane write that moves a value (setter, `clear()`,
|
|
124
|
+
`useReset()`); a `url: false` field makes no navigate and keeps the page. The route's own `validateSearch` resolves the default (`page` → 1). An explicit
|
|
125
|
+
`set(v, { patch: { page } })` still wins; naming a param the store owns throws at definition.
|
|
126
|
+
Store-wide by design: every filter of a list narrows the same list, sort included.
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
// before — an effect per page, which also snapped Back/Forward onto page 1
|
|
130
|
+
useEffect(() => { if (filtersChanged && search.page !== 1) navigate({ search: (p) => ({ ...p, page: 1 }) }) }, [filterKey])
|
|
131
|
+
|
|
132
|
+
// after — the store owns it; Back restores filter AND page, because they were one write
|
|
133
|
+
export const b2Filters = createSearchStore({ key: 'b2-filters', fields: { … }, resets: ['page'] })
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**`NumberFilter clearable`** — parity with `SelectFilter`/`EnumFilter`: a `Clear` in the popover that
|
|
137
|
+
writes the fallback back, in both the `options` and the stepper form. "No filter" is the FALLBACK,
|
|
138
|
+
not a row: with `clearable`, drop an `{ value: 0, label: 'Any …' }` option — the pill reads the
|
|
139
|
+
filter's `label` while no preset matches.
|
|
140
|
+
|
|
141
|
+
### Guards — four ids promote to `error`
|
|
142
|
+
|
|
143
|
+
The last two twin pairs leave grace together, one law per pair and one promotion for both lanes:
|
|
144
|
+
|
|
145
|
+
| Law | oxlint rule (JSX) | `check-theme` kind (text/CSS) | In grace since |
|
|
146
|
+
| --------------------- | ----------------------------- | ----------------------------- | -------------- |
|
|
147
|
+
| C1 — a control's home | `basalt/control-outside-home` | `raw-selection-control` | 1.26.0 |
|
|
148
|
+
| the breakpoint law | `basalt/raw-breakpoint` | `raw-media-query` | 1.31.0 |
|
|
149
|
+
|
|
150
|
+
Measured before flipping, 2026-10-01: all nine consumers on 1.32.1 — argo, rb, image-gen,
|
|
151
|
+
image-share, email-gateway, linewatch, rollhook, obsidian, weatherorb — at 0 for all four ids.
|
|
152
|
+
basalt's own tree and the playground are at 0 too, after two reasoned waivers in the package
|
|
153
|
+
(`legend-disclosure.tsx` clamps a fixed panel with `window.innerWidth`, a position rather than a
|
|
154
|
+
breakpoint; `ArticleGrid`'s `cols` is documented per viewport `lg`, so moving it to container keys
|
|
155
|
+
would re-flow every consumer's grid and ships opt-in instead).
|
|
156
|
+
|
|
157
|
+
If one fires after upgrading, it is code written since the measurement: the remedies are unchanged
|
|
158
|
+
(§ 1.31.0 for C1's homes, § 1.32.0 `basalt/raw-breakpoint` for the container recipe), or a
|
|
159
|
+
`theme-allow <id> — <why>`. `basalt.severity` still turns a kind down per repo; the shipped oxlint
|
|
160
|
+
preset's level can be overridden in your own `.oxlintrc.json`.
|
|
161
|
+
|
|
162
|
+
### `unknown-vx-token` — a removed `--vx-*` name is a finding (`warn`, `error` at 1.34.0)
|
|
163
|
+
|
|
164
|
+
A `var(--vx-*)` naming a token basalt does not emit resolves to its fallback — or to nothing — with
|
|
165
|
+
no error from tsc, oxlint or the browser. obsidian lost its 44px touch floor that way, to
|
|
166
|
+
`var(--vx-space-touch-target)`. `check-theme` now reports it, in every scanned file type. It ships
|
|
167
|
+
`warn` for this minor and promotes at 1.34.0. Measured at ship time: all nine consumers at 0.
|
|
168
|
+
|
|
169
|
+
| Removed name | Replacement |
|
|
170
|
+
| --------------------------------------------- | --------------------------------------------------------- |
|
|
171
|
+
| `--vx-space-touch-target` | `--vx-hit` |
|
|
172
|
+
| `--vx-space-touch-control-height` | `--vx-hit` |
|
|
173
|
+
| `--vx-space-app-header-mobile-actions-height` | `--vx-space-sticky-header-clearance` |
|
|
174
|
+
| `--vx-space-sticky-header-clearance-mobile` | `--vx-space-sticky-header-clearance` |
|
|
175
|
+
| `--vx-space-sidebar-brand-inset-top` | none — the brand row is the header band (§ 1.30.0 Chrome) |
|
|
176
|
+
|
|
177
|
+
- **Judged: a removed name** (the table) **and a bare family root nothing emits** —
|
|
178
|
+
`var(--vx-surface)`, `var(--vx-space)`, `var(--vx-status)`: basalt only writes `<root>-<key>`,
|
|
179
|
+
and so does `groupTokens`. The live set is exactly `basalt-ui/tokens.css` plus three
|
|
180
|
+
component-scoped names (`--vx-hit-gap`, `--vx-space-icon-size`, `--vx-keyboard-inset`).
|
|
181
|
+
- **Not judged: any other unknown name**, even under a basalt prefix. `groupTokens('surface', …)`
|
|
182
|
+
emits `--vx-surface-<key>` from a file a per-file scan cannot see, so `--vx-surface-2` could be
|
|
183
|
+
your group or a typo, and the guard does not guess. Check such a name against
|
|
184
|
+
`basalt-ui/tokens.css` yourself. Your `defineSeries`/`groupTokens` series (argo's `--vx-lp-*`,
|
|
185
|
+
rb's `--vx-confidence-*`), a computed name (`var(--vx-fill-${hue})`) and a name the same file
|
|
186
|
+
declares are never reported.
|
|
187
|
+
|
|
89
188
|
## 1.32.1 — the 1.32.0 recipe resolves, and the gaps consumers hit upgrading to it
|
|
90
189
|
|
|
91
190
|
A patch: no new API beyond restoring what 1.31.0/1.32.0 already documented. Eight consumers
|
|
@@ -109,8 +208,10 @@ const-resolved prop value (`span={wide ? { base: 12, md: 4 } : 12}` used to slip
|
|
|
109
208
|
warnings.)
|
|
110
209
|
|
|
111
210
|
**After any guard narrows, audit your waivers:** `basalt-ui check-theme --audit-allows` lists every
|
|
112
|
-
`theme-allow` and whether it still suppresses anything. Dead ones (rb carried
|
|
113
|
-
`in-body-page-title`, linewatch one `bound-control-outside-home`) go.
|
|
211
|
+
`theme-allow` and whether it still suppresses anything. Dead ones (rb carried three
|
|
212
|
+
`in-body-page-title`, linewatch one `bound-control-outside-home`) go. Before 1.33.0 the audit also
|
|
213
|
+
called an `in-body-page-title` waiver dead when only the oxlint lane still needed it — if deleting
|
|
214
|
+
one makes `oxlint` fail, restore it.
|
|
114
215
|
|
|
115
216
|
**Scope — the breakpoint law is Mantine/CSS-scoped.** `raw-breakpoint` is an oxlint rule over JSX
|
|
116
217
|
and `raw-media-query` a `check-theme` kind over `.css`. A tokens-only (Tailwind) consumer has only
|
|
@@ -147,12 +248,12 @@ swap to a list inside a `min-width` query. `BasaltDataTable` needs the optional
|
|
|
147
248
|
**Layouts that need a step above `wide` (800px).** There is no fifth class; one ships when two named
|
|
148
249
|
consumers need the same width. Until then, verified against the 1.32.0 plugin:
|
|
149
250
|
|
|
150
|
-
| Where | Off-class width (e.g. `1200px`)
|
|
151
|
-
| ------------------------------------------------------------------------ |
|
|
152
|
-
| `SimpleGrid type="container"` px key — `cols={{ base: 1, '1200px': 5 }}` | passes: `raw-breakpoint` does not judge px keys, only theme names (`sm`)
|
|
153
|
-
| `Grid type="container"` `breakpoints` map value — `xl: '1200px'` | passes: the map's values are not judged
|
|
154
|
-
| `@container basalt-card` or unnamed, in CSS | flagged — `theme-allow raw-media-query — <why this layout needs 1200px>`
|
|
155
|
-
| `@container <your-own-name>` or `basalt-grid`, in CSS | passes
|
|
251
|
+
| Where | Off-class width (e.g. `1200px`) |
|
|
252
|
+
| ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
253
|
+
| `SimpleGrid type="container"` px key — `cols={{ base: 1, '1200px': 5 }}` | passes: `raw-breakpoint` does not judge px keys, only theme names (`sm`) |
|
|
254
|
+
| `Grid type="container"` `breakpoints` map value — `xl: '1200px'` | passes: the map's values are not judged |
|
|
255
|
+
| `@container basalt-card` or unnamed, in CSS | flagged — `theme-allow raw-media-query — <why this layout needs 1200px>` |
|
|
256
|
+
| `@container <your-own-name>` or `basalt-grid`, in CSS | passes — the name is unjudged, so write no waiver (`--audit-allows` reports one dead); a minor that starts judging `basalt-grid` will say so here |
|
|
156
257
|
|
|
157
258
|
Either way, write the reason next to the width: it is the evidence the fifth class is waiting on.
|
|
158
259
|
|
|
@@ -246,11 +347,10 @@ source, which is what the rule's exemption is built on:
|
|
|
246
347
|
<Grid><Grid.Col span={{ base: 12, lg: 4 }}>…</Grid.Col></Grid>
|
|
247
348
|
|
|
248
349
|
// after — the grid's own width
|
|
249
|
-
import { CONTAINER_CLASSES as C } from 'basalt-ui/tokens'
|
|
350
|
+
import { CONTAINER_CLASSES as C, CONTAINER_GRID_BREAKPOINTS } from 'basalt-ui/tokens'
|
|
250
351
|
<SimpleGrid type="container" cols={{ base: 1, [`${C.regular}px`]: 3 }}>…</SimpleGrid>
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
<Grid type="container" breakpoints={containerBreakpoints}>
|
|
352
|
+
// the shipped map (§ 1.33.0); on 1.32.x, a same-file literal of the same five keys
|
|
353
|
+
<Grid type="container" breakpoints={CONTAINER_GRID_BREAKPOINTS}>
|
|
254
354
|
<Grid.Col span={{ base: 12, md: 4 }}>…</Grid.Col>
|
|
255
355
|
</Grid>
|
|
256
356
|
```
|
|
@@ -76,8 +76,8 @@ export const analytics = createSearchStore({
|
|
|
76
76
|
hand-count either.
|
|
77
77
|
- **A reset UNSETS.** `useReset()`/`field.clear()` DELETE the persisted key, never write
|
|
78
78
|
`fallback` (which would pin a thunk fallback as a value nobody chose).
|
|
79
|
-
- **`set(next, { patch })`** merges
|
|
80
|
-
|
|
79
|
+
- **`set(next, { patch })`** merges params the store does NOT own into the same navigate; store-level
|
|
80
|
+
`resets: ['page']` does it on every URL-lane write (never a `useEffect`: it snaps Back/Forward).
|
|
81
81
|
|
|
82
82
|
## Nav links carry the store BY REFERENCE
|
|
83
83
|
|
|
@@ -9,7 +9,7 @@ paths:
|
|
|
9
9
|
|
|
10
10
|
<!-- basalt:coverage -->
|
|
11
11
|
<!-- GENERATED from src/surfaces.ts — `bun scripts/check-coverage.ts --write`. Do not hand-edit. -->
|
|
12
|
-
<!-- backed by: guard kinds — css-raw-surface, inline-font-size, off-identity-accent, off-system-surface-var, raw-color-fn, raw-font-family, raw-hex, raw-radius, raw-surface, surface-shadow-override, theme-allow-unscoped · oxlint rules — basalt/no-raw-font-size, basalt/raw-size-literal, basalt/token-layer-boundary -->
|
|
12
|
+
<!-- backed by: guard kinds — css-raw-surface, inline-font-size, off-identity-accent, off-system-surface-var, raw-color-fn, raw-font-family, raw-hex, raw-radius, raw-surface, surface-shadow-override, theme-allow-unscoped, unknown-vx-token · oxlint rules — basalt/no-raw-font-size, basalt/raw-size-literal, basalt/token-layer-boundary -->
|
|
13
13
|
<!-- not guarded: — -->
|
|
14
14
|
<!-- /basalt:coverage -->
|
|
15
15
|
|
package/configs/oxlint-plugin.js
CHANGED
|
@@ -177,6 +177,7 @@ export const KNOWN_RULE_IDS = new Set([
|
|
|
177
177
|
'in-body-page-title',
|
|
178
178
|
'raw-selection-control',
|
|
179
179
|
'raw-media-query',
|
|
180
|
+
'unknown-vx-token',
|
|
180
181
|
// Retired guard kinds — no longer in GUARD_RULES, but a `theme-allow` naming one must still
|
|
181
182
|
// parse as a real (dead) waiver rather than an unknown-id typo. See RETIRED_RULE_IDS above.
|
|
182
183
|
...RETIRED_RULE_IDS,
|
|
@@ -2702,9 +2703,8 @@ const CONTROL_OUTSIDE_HOME_MESSAGE =
|
|
|
2702
2703
|
|
|
2703
2704
|
/**
|
|
2704
2705
|
* The cross-file half of C1, and the one rule here that is openly a HEURISTIC: "this control has
|
|
2705
|
-
* no home" is a claim about layout intent, which no AST can see.
|
|
2706
|
-
*
|
|
2707
|
-
* (docs/CONTROLS-SPEC.md §9 wave 7).
|
|
2706
|
+
* no home" is a claim about layout intent, which no AST can see. That is why it sat in grace from
|
|
2707
|
+
* 1.26.0 to 1.33.0, promoting only once basalt's tree and nine consumers measured at zero.
|
|
2708
2708
|
*
|
|
2709
2709
|
* Four exemptions carry the false-positive load: an overlay/settings-row/form-row ancestor
|
|
2710
2710
|
* ({@link CONTROL_HOST_TAGS}, `FormRow`/`FormGroup` included), an {@link isOverlayConventionFile}
|
|
@@ -2712,7 +2712,7 @@ const CONTROL_OUTSIDE_HOME_MESSAGE =
|
|
|
2712
2712
|
* `@mantine/form` (a form is the third home and its inputs are not filters), and the owner
|
|
2713
2713
|
* exemption — a file DEFINING a basalt control cannot be told to use one.
|
|
2714
2714
|
*/
|
|
2715
|
-
// Ships:
|
|
2715
|
+
// Ships: error
|
|
2716
2716
|
const controlOutsideHome = {
|
|
2717
2717
|
meta: {
|
|
2718
2718
|
type: 'suggestion',
|
|
@@ -4066,8 +4066,9 @@ const CONTAINER_ROUTED_PROPS = {
|
|
|
4066
4066
|
* `type` has to be the string literal `"container"`; a dynamic value is not a decision this rule
|
|
4067
4067
|
* can read. `Grid.Col` takes its grid's mode by walking to the nearest enclosing `Grid` element.
|
|
4068
4068
|
* `consts` is the rule's same-file name→object map, so `breakpoints={map}` resolves like any value.
|
|
4069
|
+
* The one IMPORTED map trusted is basalt's own `CONTAINER_GRID_BREAKPOINTS` ({@link isShippedGridMap}).
|
|
4069
4070
|
*/
|
|
4070
|
-
function containerGridMode(opening, mantineImports, consts) {
|
|
4071
|
+
function containerGridMode(opening, mantineImports, consts, sourceCode) {
|
|
4071
4072
|
let tag = resolveMantineTag(opening.name, mantineImports)
|
|
4072
4073
|
let grid = opening
|
|
4073
4074
|
if (tag === 'Grid.Col') {
|
|
@@ -4096,12 +4097,69 @@ function containerGridMode(opening, mantineImports, consts) {
|
|
|
4096
4097
|
const breakpoints = attr('breakpoints')
|
|
4097
4098
|
if (breakpoints === undefined) return 'fallback'
|
|
4098
4099
|
let map = attrValue(breakpoints)
|
|
4100
|
+
if (isShippedGridMap(sourceCode, map)) return 'container'
|
|
4099
4101
|
if (map?.type === 'Identifier') map = consts.get(map.name)
|
|
4100
4102
|
const nonEmpty =
|
|
4101
4103
|
map?.type === 'ObjectExpression' && map.properties.some((prop) => prop.type === 'Property')
|
|
4102
4104
|
return nonEmpty ? 'container' : 'fallback'
|
|
4103
4105
|
}
|
|
4104
4106
|
|
|
4107
|
+
/**
|
|
4108
|
+
* Whether `node` reads basalt's own `CONTAINER_GRID_BREAKPOINTS` — its value is known, so it is
|
|
4109
|
+
* the one imported `breakpoints` map trusted. Resolved through the scope manager to the BINDING the
|
|
4110
|
+
* identifier reads, never by local name: a parameter or inner `const` shadowing the import is not
|
|
4111
|
+
* the import. The binding has to be an `ImportSpecifier` naming it from `basalt-ui/tokens` (any
|
|
4112
|
+
* alias, not type-only), a `.CONTAINER_GRID_BREAKPOINTS` member of that module's namespace import,
|
|
4113
|
+
* or a `const` whose initializer resolves the same way. Without a scope manager nothing is trusted
|
|
4114
|
+
* — reported, the conservative answer.
|
|
4115
|
+
*/
|
|
4116
|
+
function isShippedGridMap(sourceCode, node, seen = new Set()) {
|
|
4117
|
+
if (node?.type === 'MemberExpression') return isShippedGridMapMember(sourceCode, node)
|
|
4118
|
+
if (node?.type !== 'Identifier' || seen.has(node)) return false
|
|
4119
|
+
seen.add(node)
|
|
4120
|
+
const def = soleDefinition(sourceCode, node)
|
|
4121
|
+
if (def?.type === 'ImportBinding') {
|
|
4122
|
+
const spec = def.node
|
|
4123
|
+
const decl = def.parent
|
|
4124
|
+
if (decl?.type !== 'ImportDeclaration' || decl.importKind === 'type') return false
|
|
4125
|
+
if (decl.source?.value !== 'basalt-ui/tokens') return false
|
|
4126
|
+
if (spec.type !== 'ImportSpecifier' || spec.importKind === 'type') return false
|
|
4127
|
+
const imported = spec.imported
|
|
4128
|
+
const importedName = imported.type === 'Identifier' ? imported.name : imported.value
|
|
4129
|
+
return importedName === 'CONTAINER_GRID_BREAKPOINTS'
|
|
4130
|
+
}
|
|
4131
|
+
if (def?.type === 'Variable' && def.parent?.kind === 'const')
|
|
4132
|
+
return isShippedGridMap(sourceCode, def.node.init, seen)
|
|
4133
|
+
return false
|
|
4134
|
+
}
|
|
4135
|
+
|
|
4136
|
+
/** `tokens.CONTAINER_GRID_BREAKPOINTS` (or `tokens['CONTAINER_GRID_BREAKPOINTS']`) on `import * as tokens from 'basalt-ui/tokens'`. */
|
|
4137
|
+
function isShippedGridMapMember(sourceCode, node) {
|
|
4138
|
+
const property = node.property
|
|
4139
|
+
const name = node.computed
|
|
4140
|
+
? isStringLiteral(property) && property.value
|
|
4141
|
+
: property?.type === 'Identifier' && property.name
|
|
4142
|
+
if (name !== 'CONTAINER_GRID_BREAKPOINTS' || node.object?.type !== 'Identifier') return false
|
|
4143
|
+
const def = soleDefinition(sourceCode, node.object)
|
|
4144
|
+
return (
|
|
4145
|
+
def?.type === 'ImportBinding' &&
|
|
4146
|
+
def.node.type === 'ImportNamespaceSpecifier' &&
|
|
4147
|
+
def.parent?.importKind !== 'type' &&
|
|
4148
|
+
def.parent?.source?.value === 'basalt-ui/tokens'
|
|
4149
|
+
)
|
|
4150
|
+
}
|
|
4151
|
+
|
|
4152
|
+
/** The one definition of the variable `identifier` reads, or `undefined` (unresolved, or more than one). */
|
|
4153
|
+
function soleDefinition(sourceCode, identifier) {
|
|
4154
|
+
if (typeof sourceCode?.getScope !== 'function') return undefined
|
|
4155
|
+
for (let scope = sourceCode.getScope(identifier); scope; scope = scope.upper) {
|
|
4156
|
+
const variable = scope.set.get(identifier.name)
|
|
4157
|
+
if (variable === undefined) continue
|
|
4158
|
+
return variable.defs.length === 1 ? variable.defs[0] : undefined
|
|
4159
|
+
}
|
|
4160
|
+
return undefined
|
|
4161
|
+
}
|
|
4162
|
+
|
|
4105
4163
|
/**
|
|
4106
4164
|
* The shell components that are `visibleFrom`/`hiddenFrom`'s legitimate home — the size-class
|
|
4107
4165
|
* axis's one JSX escape hatch, alongside overlays. Matched by DECLARATION name, the same
|
|
@@ -4134,7 +4192,7 @@ const RAW_BREAKPOINT_EXEMPT_FILE = /(?:^|[\\/])(?:use-media-query\.ts|ChartToolt
|
|
|
4134
4192
|
export const RAW_BREAKPOINT_RECIPE =
|
|
4135
4193
|
'A page’s own layout keys on its container: <SimpleGrid type="container" cols={{ base: 1, ' +
|
|
4136
4194
|
"'480px': 2, '800px': 3 }}> (px keys = CONTAINER_CLASSES, basalt-ui/tokens), or <Grid " +
|
|
4137
|
-
'type="container" breakpoints={
|
|
4195
|
+
'type="container" breakpoints={CONTAINER_GRID_BREAKPOINTS}> (basalt-ui/tokens), with Grid.Col ' +
|
|
4138
4196
|
'span={{ base: 12, sm: 6 }} keyed through that map; a Flex direction swap becomes that SimpleGrid (equal ' +
|
|
4139
4197
|
'columns), a wrapping Group, or a CSS-module @container basalt-grid rule. useSizeClass() is for ' +
|
|
4140
4198
|
'shell chrome only. Recipes: basalt-ui MIGRATING.md § basalt/raw-breakpoint.'
|
|
@@ -4204,7 +4262,7 @@ const RAW_BREAKPOINT_HOOK_NAMES = new Set(['useMediaQuery', 'useMatches', 'useVi
|
|
|
4204
4262
|
* declares a shell home (or a control's own C9 swap) is exempt for all four shapes uniformly — the
|
|
4205
4263
|
* shell's own responsive chrome is the sanctioned use, whatever shape it takes.
|
|
4206
4264
|
*/
|
|
4207
|
-
// Ships:
|
|
4265
|
+
// Ships: error
|
|
4208
4266
|
const rawBreakpoint = {
|
|
4209
4267
|
meta: {
|
|
4210
4268
|
type: 'suggestion',
|
|
@@ -4238,6 +4296,7 @@ const rawBreakpoint = {
|
|
|
4238
4296
|
// apart), so it is dropped from the map entirely rather than guessed at last-wins.
|
|
4239
4297
|
const responsiveObjectConsts = new Map()
|
|
4240
4298
|
const seenDeclaratorNames = new Set()
|
|
4299
|
+
const sourceCode = context.sourceCode ?? context.getSourceCode?.()
|
|
4241
4300
|
|
|
4242
4301
|
const noteShellHomeOwner = (name) => {
|
|
4243
4302
|
if (typeof name === 'string' && SHELL_HOME_NAMES.has(name)) definesShellHome = true
|
|
@@ -4322,7 +4381,7 @@ const rawBreakpoint = {
|
|
|
4322
4381
|
? CONTAINER_ROUTED_PROPS[tag]
|
|
4323
4382
|
: undefined
|
|
4324
4383
|
const mode = routed?.has(node.name.name)
|
|
4325
|
-
? containerGridMode(owner, mantineImports, responsiveObjectConsts)
|
|
4384
|
+
? containerGridMode(owner, mantineImports, responsiveObjectConsts, sourceCode)
|
|
4326
4385
|
: undefined
|
|
4327
4386
|
if (mode === 'container') continue
|
|
4328
4387
|
if (!containsResponsiveObjectValue(value, responsiveObjectConsts, mode !== undefined))
|
|
@@ -4373,59 +4432,7 @@ const rawBreakpoint = {
|
|
|
4373
4432
|
*
|
|
4374
4433
|
* @type {Record<string, GraceEntry>}
|
|
4375
4434
|
*/
|
|
4376
|
-
export const PLUGIN_RULE_GRACE = {
|
|
4377
|
-
'control-outside-home': {
|
|
4378
|
-
since: '1.26.0',
|
|
4379
|
-
promote: '1.33.0',
|
|
4380
|
-
why:
|
|
4381
|
-
"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. " +
|
|
4382
|
-
'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. ' +
|
|
4383
|
-
'the wave-6 control guards (docs/CONTROLS-SPEC.md §6). The one openly HEURISTIC rule of the ' +
|
|
4384
|
-
'set — "this control has no home" is a claim about layout intent, so its false-positive load ' +
|
|
4385
|
-
'is carried by four exemptions (overlay/settings-row ancestor, the overlay FILENAME ' +
|
|
4386
|
-
'convention below, @mantine/form, owner definition) rather than by certainty. The other five ' +
|
|
4387
|
-
'wave-6 rules promoted at 1.27.0; this one has not, across three re-datings. ' +
|
|
4388
|
-
'RE-MEASURED 2026-09-09, every consumer freshly migrated to 1.29.2 and basalt built from ' +
|
|
4389
|
-
'master: 29 incumbents across five repos — image-gen 10, rb 8, image-share 6, the playground ' +
|
|
4390
|
-
'3, argo 2 — and zero in linewatch, meteo and obsidian. The 1.28.0 prediction held: ' +
|
|
4391
|
-
"{@link isOverlayConventionFile} took argo's 9 cross-file overlay warns down to 2, which is " +
|
|
4392
|
-
'the part of the remainder that was ever going to fall to an exemption. ' +
|
|
4393
|
-
'Extended to 1.31.0, and the argument is NOT the count — it is that 1.30.0 is the first ' +
|
|
4394
|
-
'release in which this rule names an answer the 29 can reach. Every home it listed was a ' +
|
|
4395
|
-
'shell slot (PageBar / Section / WidgetHeader), so a consumer that mounts `BasaltProvider` ' +
|
|
4396
|
-
'and no `BasaltShell` had no reachable home at all: image-gen is a Tauri window with a ' +
|
|
4397
|
-
'hand-rolled header and carries 10 of the 29 by itself, and `bound-control-outside-home` ' +
|
|
4398
|
-
'closed the `ViewTabs` escape it would otherwise have taken. 1.30.0 adds the missing ' +
|
|
4399
|
-
'sentence to both messages ({@link SHELL_LESS_HOME_HINT} — a `PageBar` outside a shell ' +
|
|
4400
|
-
'renders in flow, sticky, with its own title, which is what `src/shell/page-bar.tsx` ' +
|
|
4401
|
-
'actually does). Promoting a rule to `error` in the same minor that first makes it ' +
|
|
4402
|
-
'satisfiable hands a consumer zero minors to act on the answer, which is exactly the failure ' +
|
|
4403
|
-
'the grace mechanism exists to prevent. 1.31.0 is when the 29 have been through the new home ' +
|
|
4404
|
-
'and the remainder is measured against that number. A file outside the convention that is ' +
|
|
4405
|
-
"still an overlay's own body declares it with " +
|
|
4406
|
-
'`theme-allow-file control-outside-home — overlay`.',
|
|
4407
|
-
},
|
|
4408
|
-
'raw-breakpoint': {
|
|
4409
|
-
since: '1.31.0',
|
|
4410
|
-
promote: '1.33.0',
|
|
4411
|
-
why:
|
|
4412
|
-
'New in the wave-11 responsive/touch guards. Catches four independent shapes at once — a ' +
|
|
4413
|
-
'responsive-object Mantine prop, visibleFrom/hiddenFrom outside the three shell homes, the ' +
|
|
4414
|
-
'three raw viewport hooks, and window.matchMedia/innerWidth — none of which basalt policed ' +
|
|
4415
|
-
'before this wave, so every consumer on an earlier minor has a green build with all four ' +
|
|
4416
|
-
"shapes already in it. basalt-ui/content's own article-card.tsx (a `SimpleGrid cols={{ base: " +
|
|
4417
|
-
"1, sm: 2, lg }}`) was one incumbent measured in basalt's own tree at ship time — a real " +
|
|
4418
|
-
'number, not zero, so it shipped warn rather than error. ' +
|
|
4419
|
-
'Extended 1.32.0 -> 1.33.0: 1.31.0 shipped the rule naming "a container query" but no ' +
|
|
4420
|
-
'primitive, and MIGRATING never mentioned it (argo: 42 warns, no documented target). 1.32.0 ' +
|
|
4421
|
-
'is the first minor with a reachable, documented answer (Mantine type="container" grids keyed ' +
|
|
4422
|
-
'on CONTAINER_CLASSES, exempted here), and promoting in the minor that first makes a rule ' +
|
|
4423
|
-
'satisfiable hands a consumer zero minors to act on it — the control-outside-home ' +
|
|
4424
|
-
"extension's reasoning. 1.33.0 is when the incumbents are expected to have moved to a " +
|
|
4425
|
-
'container grid or a theme-allow with a stated reason. Promotes together with its CSS twin, ' +
|
|
4426
|
-
'the `raw-media-query` guard kind.',
|
|
4427
|
-
},
|
|
4428
|
-
}
|
|
4435
|
+
export const PLUGIN_RULE_GRACE = {}
|
|
4429
4436
|
|
|
4430
4437
|
/**
|
|
4431
4438
|
* Plugin rules that stay `warn` in the shipped preset PERMANENTLY — outside the C16 version gate,
|