basalt-ui 1.30.2 → 1.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +54 -0
- package/MIGRATING.md +256 -12
- package/agent/rules/basalt-controls.md +19 -19
- package/agent/rules/basalt-mantine.md +5 -5
- package/configs/oxlint-plugin.js +371 -4
- package/configs/oxlint-plugin.test.ts +327 -2
- package/configs/oxlint.json +2 -1
- package/dist/agent-chat/composer.d.ts.map +1 -1
- package/dist/agent-chat/composer.js +41 -43
- package/dist/agent-chat/thread-workspace.d.ts +2 -2
- package/dist/agent-chat/thread-workspace.d.ts.map +1 -1
- package/dist/agent-chat/thread-workspace.js +3 -4
- package/dist/agent-chat/use-keyboard-inset.d.ts +2 -0
- package/dist/agent-chat/use-keyboard-inset.d.ts.map +1 -0
- package/dist/agent-chat/use-keyboard-inset.js +34 -0
- package/dist/charts/cursor/touch-pin.d.ts +45 -0
- package/dist/charts/cursor/touch-pin.d.ts.map +1 -0
- package/dist/charts/cursor/touch-pin.js +79 -0
- package/dist/charts/hooks/use-discrete-cursor.d.ts +66 -0
- package/dist/charts/hooks/use-discrete-cursor.d.ts.map +1 -0
- package/dist/charts/hooks/use-discrete-cursor.js +198 -0
- package/dist/charts/hooks/use-hysteresis.d.ts +18 -0
- package/dist/charts/hooks/use-hysteresis.d.ts.map +1 -0
- package/dist/charts/hooks/use-hysteresis.js +12 -0
- package/dist/charts/hooks/useBandPlot.d.ts +7 -0
- package/dist/charts/hooks/useBandPlot.d.ts.map +1 -1
- package/dist/charts/hooks/useBandPlot.js +62 -18
- package/dist/charts/hooks/useChartCursor.d.ts +40 -11
- package/dist/charts/hooks/useChartCursor.d.ts.map +1 -1
- package/dist/charts/hooks/useChartCursor.js +102 -11
- package/dist/charts/index.d.ts +0 -1
- package/dist/charts/index.d.ts.map +1 -1
- package/dist/charts/index.js +0 -10
- package/dist/charts/kinds/BandStrip.d.ts.map +1 -1
- package/dist/charts/kinds/BandStrip.js +47 -82
- package/dist/charts/kinds/Donut.d.ts +9 -3
- package/dist/charts/kinds/Donut.d.ts.map +1 -1
- package/dist/charts/kinds/Donut.js +110 -48
- package/dist/charts/kinds/DualPanel.d.ts.map +1 -1
- package/dist/charts/kinds/DualPanel.js +138 -145
- package/dist/charts/kinds/Heatmap.d.ts +7 -0
- package/dist/charts/kinds/Heatmap.d.ts.map +1 -1
- package/dist/charts/kinds/Heatmap.js +37 -16
- package/dist/charts/kinds/MirroredBars.d.ts.map +1 -1
- package/dist/charts/kinds/MirroredBars.js +68 -111
- package/dist/charts/kinds/band-chrome.d.ts +31 -0
- package/dist/charts/kinds/band-chrome.d.ts.map +1 -0
- package/dist/charts/kinds/band-chrome.js +71 -0
- package/dist/charts/kinds/donut-layout.d.ts +47 -0
- package/dist/charts/kinds/donut-layout.d.ts.map +1 -0
- package/dist/charts/kinds/donut-layout.js +52 -0
- package/dist/charts/layout/auto-margin.d.ts +7 -2
- package/dist/charts/layout/auto-margin.d.ts.map +1 -1
- package/dist/charts/layout/auto-margin.js +12 -3
- package/dist/charts/layout/end-labels.d.ts +64 -0
- package/dist/charts/layout/end-labels.d.ts.map +1 -0
- package/dist/charts/layout/end-labels.js +76 -0
- package/dist/charts/primitives/Axes.d.ts +32 -4
- package/dist/charts/primitives/Axes.d.ts.map +1 -1
- package/dist/charts/primitives/Axes.js +62 -16
- package/dist/charts/primitives/CartesianChart.d.ts +7 -6
- package/dist/charts/primitives/CartesianChart.d.ts.map +1 -1
- package/dist/charts/primitives/CartesianChart.js +264 -145
- package/dist/charts/primitives/ChartCard.d.ts +0 -14
- package/dist/charts/primitives/ChartCard.d.ts.map +1 -1
- package/dist/charts/primitives/ChartCard.js +56 -21
- package/dist/charts/primitives/ChartFrame.d.ts +28 -22
- package/dist/charts/primitives/ChartFrame.d.ts.map +1 -1
- package/dist/charts/primitives/ChartFrame.js +116 -34
- package/dist/charts/primitives/ChartLegend.d.ts +19 -15
- package/dist/charts/primitives/ChartLegend.d.ts.map +1 -1
- package/dist/charts/primitives/ChartLegend.js +86 -73
- package/dist/charts/primitives/ChartTooltip.d.ts +5 -0
- package/dist/charts/primitives/ChartTooltip.d.ts.map +1 -1
- package/dist/charts/primitives/ChartTooltip.js +20 -4
- package/dist/charts/primitives/Crosshair.js +2 -2
- package/dist/charts/primitives/HoverOverlay.d.ts +29 -9
- package/dist/charts/primitives/HoverOverlay.d.ts.map +1 -1
- package/dist/charts/primitives/HoverOverlay.js +54 -27
- package/dist/charts/primitives/HoverOverlay.module.css +13 -0
- package/dist/charts/primitives/HoverOverlay.module.css.d.ts +8 -0
- package/dist/charts/primitives/chart-card-context.d.ts +33 -0
- package/dist/charts/primitives/chart-card-context.d.ts.map +1 -0
- package/dist/charts/primitives/chart-card-context.js +18 -0
- package/dist/charts/primitives/chart-frame-layout.d.ts +93 -113
- package/dist/charts/primitives/chart-frame-layout.d.ts.map +1 -1
- package/dist/charts/primitives/chart-frame-layout.js +75 -34
- package/dist/charts/primitives/chart-layout.d.ts +112 -0
- package/dist/charts/primitives/chart-layout.d.ts.map +1 -0
- package/dist/charts/primitives/chart-layout.js +175 -0
- package/dist/charts/primitives/chart-tier.d.ts +13 -11
- package/dist/charts/primitives/chart-tier.d.ts.map +1 -1
- package/dist/charts/primitives/chart-tier.js +42 -13
- package/dist/charts/primitives/legend-disclosure.d.ts +27 -0
- package/dist/charts/primitives/legend-disclosure.d.ts.map +1 -0
- package/dist/charts/primitives/legend-disclosure.js +153 -0
- package/dist/charts/series.d.ts +4 -1
- package/dist/charts/series.d.ts.map +1 -1
- package/dist/charts/utils/ticks.d.ts +27 -8
- package/dist/charts/utils/ticks.d.ts.map +1 -1
- package/dist/charts/utils/ticks.js +35 -11
- package/dist/common/errors.d.ts +11 -1
- package/dist/common/errors.d.ts.map +1 -1
- package/dist/common/errors.js +16 -2
- package/dist/common/hit-floor.d.ts +10 -0
- package/dist/common/hit-floor.d.ts.map +1 -0
- package/dist/common/hit-floor.js +6 -0
- package/dist/{shell → common}/isomorphic-layout-effect.d.ts +4 -3
- package/dist/common/isomorphic-layout-effect.d.ts.map +1 -0
- package/dist/common/use-measured-widths.d.ts +37 -0
- package/dist/common/use-measured-widths.d.ts.map +1 -0
- package/dist/common/use-measured-widths.js +51 -0
- package/dist/common/use-media-query.d.ts +6 -0
- package/dist/common/use-media-query.d.ts.map +1 -0
- package/dist/common/use-media-query.js +40 -0
- package/dist/common/validate.d.ts +9 -0
- package/dist/common/validate.d.ts.map +1 -1
- package/dist/common/validate.js +9 -4
- package/dist/content/article-layout.d.ts +4 -2
- package/dist/content/article-layout.d.ts.map +1 -1
- package/dist/content/article-layout.js +43 -3
- package/dist/content/article-layout.module.css +45 -4
- package/dist/content/article-layout.module.css.d.ts +3 -0
- package/dist/content/code-block.d.ts.map +1 -1
- package/dist/content/code-block.js +40 -2
- package/dist/content/code-block.module.css +32 -2
- package/dist/content/prose.module.css +13 -8
- package/dist/controls/actions.d.ts +29 -6
- package/dist/controls/actions.d.ts.map +1 -1
- package/dist/controls/actions.js +158 -27
- package/dist/controls/actions.module.css +14 -1
- package/dist/controls/actions.module.css.d.ts +1 -0
- package/dist/controls/controls.module.css +13 -31
- package/dist/controls/enum-filter.js +2 -2
- package/dist/controls/filter-context.d.ts +10 -0
- package/dist/controls/filter-context.d.ts.map +1 -1
- package/dist/controls/filter-context.js +2 -0
- package/dist/controls/filter-pill.d.ts.map +1 -1
- package/dist/controls/filter-pill.js +1 -0
- package/dist/controls/index.d.ts +1 -1
- package/dist/controls/index.d.ts.map +1 -1
- package/dist/controls/index.js +0 -2
- package/dist/controls/multi-select-filter.js +2 -2
- package/dist/controls/sync-button.module.css +2 -1
- package/dist/dashboard/section.d.ts.map +1 -1
- package/dist/dashboard/section.js +1 -0
- package/dist/dashboard/section.module.css +1 -26
- package/dist/dashboard/stat-card.d.ts +1 -1
- package/dist/dashboard/stat-card.d.ts.map +1 -1
- package/dist/dashboard/stat-card.js +4 -1
- package/dist/dashboard/stat-card.module.css +6 -9
- package/dist/dashboard/stat-group.module.css +33 -66
- package/dist/dashboard/widget-grid.d.ts.map +1 -1
- package/dist/dashboard/widget-grid.module.css +11 -38
- package/dist/dashboard/widget-header.d.ts +14 -4
- package/dist/dashboard/widget-header.d.ts.map +1 -1
- package/dist/dashboard/widget-header.js +23 -6
- package/dist/dashboard/widget-header.module.css +145 -133
- package/dist/dashboard/widget-header.module.css.d.ts +2 -0
- package/dist/data/data-table-state.d.ts +83 -0
- package/dist/data/data-table-state.d.ts.map +1 -0
- package/dist/data/data-table-state.js +139 -0
- package/dist/data/data-table.d.ts +56 -2
- package/dist/data/data-table.d.ts.map +1 -1
- package/dist/data/data-table.js +436 -336
- package/dist/data/data-table.module.css +94 -0
- package/dist/data/data-table.module.css.d.ts +11 -0
- package/dist/data/virtual-list.d.ts.map +1 -1
- package/dist/data/virtual-list.js +10 -0
- package/dist/forms/form-layout.d.ts.map +1 -1
- package/dist/forms/form-layout.js +3 -3
- package/dist/forms/form-layout.module.css +20 -5
- package/dist/forms/form-layout.module.css.d.ts +1 -0
- package/dist/guard/index.d.ts +8 -2
- package/dist/guard/index.d.ts.map +1 -1
- package/dist/guard/index.js +68 -2
- package/dist/guard/types.d.ts +3 -3
- package/dist/guard/types.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/notifications/center.d.ts.map +1 -1
- package/dist/provider/index.d.ts +20 -1
- package/dist/provider/index.d.ts.map +1 -1
- package/dist/provider/index.js +30 -8
- package/dist/shell/app-brand.d.ts.map +1 -1
- package/dist/shell/app-brand.js +1 -0
- package/dist/shell/app-brand.module.css +2 -2
- package/dist/shell/app-header.module.css +18 -8
- package/dist/shell/app-main.module.css +54 -3
- package/dist/shell/app-main.module.css.d.ts +1 -0
- package/dist/shell/app-mobile-nav.module.css +16 -4
- package/dist/shell/app-sidebar.module.css +4 -6
- package/dist/shell/aside-docking.d.ts +31 -0
- package/dist/shell/aside-docking.d.ts.map +1 -0
- package/dist/shell/aside-docking.js +19 -0
- package/dist/shell/index.d.ts +1 -0
- package/dist/shell/index.d.ts.map +1 -1
- package/dist/shell/index.js +56 -16
- package/dist/shell/mobile-nav-model.d.ts +1 -1
- package/dist/shell/page-aside.d.ts +22 -3
- package/dist/shell/page-aside.d.ts.map +1 -1
- package/dist/shell/page-aside.js +27 -13
- package/dist/shell/page-bar.d.ts.map +1 -1
- package/dist/shell/page-bar.js +10 -5
- package/dist/shell/page-bar.module.css +10 -34
- package/dist/shell/use-breakpoint.d.ts +3 -4
- package/dist/shell/use-breakpoint.d.ts.map +1 -1
- package/dist/shell/use-breakpoint.js +3 -25
- package/dist/shell/use-size-class.d.ts +6 -0
- package/dist/shell/use-size-class.d.ts.map +1 -0
- package/dist/shell/use-size-class.js +19 -0
- package/dist/state/persisted-or-local.d.ts +4 -1
- package/dist/state/persisted-or-local.d.ts.map +1 -1
- package/dist/state/persisted-or-local.js +4 -3
- package/dist/state/persisted.d.ts +10 -0
- package/dist/state/persisted.d.ts.map +1 -1
- package/dist/state/persisted.js +44 -14
- package/dist/styles.css +41 -0
- package/dist/surfaces.d.ts +4 -4
- package/dist/surfaces.d.ts.map +1 -1
- package/dist/surfaces.js +11 -3
- package/dist/theme/controls.module.css +7 -0
- package/dist/theme/ctl-theme.d.ts +1 -0
- package/dist/theme/ctl-theme.d.ts.map +1 -1
- package/dist/theme/ctl-theme.js +12 -4
- package/dist/theme/floating.module.css +37 -0
- package/dist/theme/floating.module.css.d.ts +3 -0
- package/dist/theme/index.d.ts +2 -2
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/index.js +34 -5
- package/dist/theme/nav-link.module.css +7 -0
- package/dist/theme-lab/derive-controls.d.ts.map +1 -1
- package/dist/tokens/index.d.ts +7 -16
- package/dist/tokens/index.d.ts.map +1 -1
- package/dist/tokens/index.js +23 -28
- package/dist/tokens/palette.d.ts +5 -27
- package/dist/tokens/palette.d.ts.map +1 -1
- package/dist/tokens/palette.js +8 -30
- package/dist/tokens/size-classes.d.ts +40 -0
- package/dist/tokens/size-classes.d.ts.map +1 -0
- package/dist/tokens/size-classes.js +29 -0
- package/dist/tokens.css +8 -4
- package/llms.txt +3 -3
- package/package.json +18 -17
- package/src/agent-chat/composer.tsx +74 -47
- package/src/agent-chat/thread-workspace.tsx +8 -11
- package/src/agent-chat/use-keyboard-inset.ts +68 -0
- package/src/charts/cursor/touch-pin.ts +138 -0
- package/src/charts/hooks/use-discrete-cursor.ts +335 -0
- package/src/charts/hooks/use-hysteresis.ts +26 -0
- package/src/charts/hooks/useBandPlot.ts +90 -27
- package/src/charts/hooks/useChartCursor.ts +211 -26
- package/src/charts/index.ts +0 -8
- package/src/charts/kinds/BandStrip.tsx +25 -61
- package/src/charts/kinds/Donut.tsx +153 -62
- package/src/charts/kinds/DualPanel.tsx +21 -26
- package/src/charts/kinds/Heatmap.tsx +61 -22
- package/src/charts/kinds/MirroredBars.tsx +23 -65
- package/src/charts/kinds/band-chrome.tsx +91 -0
- package/src/charts/kinds/donut-layout.ts +82 -0
- package/src/charts/layout/auto-margin.ts +24 -5
- package/src/charts/layout/end-labels.ts +135 -0
- package/src/charts/primitives/Axes.tsx +112 -21
- package/src/charts/primitives/CartesianChart.tsx +282 -111
- package/src/charts/primitives/ChartCard.tsx +119 -48
- package/src/charts/primitives/ChartFrame.tsx +204 -60
- package/src/charts/primitives/ChartLegend.tsx +115 -78
- package/src/charts/primitives/ChartTooltip.tsx +24 -3
- package/src/charts/primitives/Crosshair.tsx +2 -2
- package/src/charts/primitives/HoverOverlay.module.css +13 -0
- package/src/charts/primitives/HoverOverlay.module.css.d.ts +8 -0
- package/src/charts/primitives/HoverOverlay.tsx +62 -20
- package/src/charts/primitives/chart-card-context.ts +46 -0
- package/src/charts/primitives/chart-frame-layout.ts +207 -182
- package/src/charts/primitives/chart-layout.ts +318 -0
- package/src/charts/primitives/chart-tier.tsx +66 -21
- package/src/charts/primitives/legend-disclosure.tsx +177 -0
- package/src/charts/series.ts +4 -1
- package/src/charts/utils/ticks.ts +95 -19
- package/src/common/errors.ts +25 -1
- package/src/common/hit-floor.ts +9 -0
- package/src/{shell → common}/isomorphic-layout-effect.ts +4 -3
- package/src/common/use-measured-widths.ts +88 -0
- package/src/common/use-media-query.ts +56 -0
- package/src/common/validate.ts +17 -4
- package/src/content/article-layout.module.css +45 -4
- package/src/content/article-layout.module.css.d.ts +3 -0
- package/src/content/article-layout.tsx +60 -5
- package/src/content/code-block.module.css +32 -2
- package/src/content/code-block.tsx +47 -3
- package/src/content/prose.module.css +13 -8
- package/src/controls/actions.module.css +14 -1
- package/src/controls/actions.module.css.d.ts +1 -0
- package/src/controls/actions.tsx +223 -75
- package/src/controls/controls.module.css +13 -31
- package/src/controls/enum-filter.tsx +2 -2
- package/src/controls/filter-context.tsx +11 -0
- package/src/controls/filter-pill.tsx +1 -0
- package/src/controls/index.ts +0 -1
- package/src/controls/multi-select-filter.tsx +2 -2
- package/src/controls/sync-button.module.css +2 -1
- package/src/dashboard/section.module.css +1 -26
- package/src/dashboard/section.tsx +1 -0
- package/src/dashboard/stat-card.module.css +6 -9
- package/src/dashboard/stat-card.tsx +6 -3
- package/src/dashboard/stat-group.module.css +33 -66
- package/src/dashboard/widget-grid.module.css +11 -38
- package/src/dashboard/widget-grid.tsx +7 -6
- package/src/dashboard/widget-header.module.css +145 -133
- package/src/dashboard/widget-header.module.css.d.ts +2 -0
- package/src/dashboard/widget-header.tsx +45 -11
- package/src/data/data-table-state.ts +218 -0
- package/src/data/data-table.module.css +94 -0
- package/src/data/data-table.module.css.d.ts +11 -0
- package/src/data/data-table.tsx +547 -299
- package/src/data/virtual-list.tsx +31 -0
- package/src/forms/form-layout.module.css +20 -5
- package/src/forms/form-layout.module.css.d.ts +1 -0
- package/src/forms/form-layout.tsx +12 -10
- package/src/guard/index.ts +188 -3
- package/src/guard/types.ts +3 -2
- package/src/index.ts +2 -0
- package/src/notifications/center.tsx +3 -0
- package/src/provider/index.tsx +60 -7
- package/src/shell/app-brand.module.css +2 -2
- package/src/shell/app-brand.tsx +1 -0
- package/src/shell/app-header.module.css +18 -8
- package/src/shell/app-main.module.css +54 -3
- package/src/shell/app-main.module.css.d.ts +1 -0
- package/src/shell/app-mobile-nav.module.css +16 -4
- package/src/shell/app-sidebar.module.css +4 -6
- package/src/shell/aside-docking.ts +54 -0
- package/src/shell/index.tsx +178 -129
- package/src/shell/mobile-nav-model.ts +1 -1
- package/src/shell/page-aside.tsx +70 -21
- package/src/shell/page-bar.module.css +10 -34
- package/src/shell/page-bar.tsx +10 -5
- package/src/shell/use-breakpoint.ts +9 -45
- package/src/shell/use-size-class.ts +31 -0
- package/src/state/persisted-or-local.ts +10 -4
- package/src/state/persisted.ts +76 -17
- package/src/styles.css +41 -0
- package/src/surfaces.ts +9 -1
- package/src/theme/controls.module.css +7 -0
- package/src/theme/ctl-theme.tsx +15 -3
- package/src/theme/floating.module.css +37 -0
- package/src/theme/floating.module.css.d.ts +3 -0
- package/src/theme/index.ts +46 -8
- package/src/theme/nav-link.module.css +7 -0
- package/src/theme-lab/derive-controls.tsx +2 -0
- package/src/tokens/index.ts +20 -30
- package/src/tokens/palette.ts +6 -28
- package/src/tokens/size-classes.ts +46 -0
- package/dist/shell/isomorphic-layout-effect.d.ts.map +0 -1
- /package/dist/{shell → common}/isomorphic-layout-effect.js +0 -0
package/configs/oxlint-plugin.js
CHANGED
|
@@ -143,6 +143,7 @@ export const KNOWN_RULE_IDS = new Set([
|
|
|
143
143
|
'visx-tooltip',
|
|
144
144
|
'token-layer-boundary',
|
|
145
145
|
'no-import-meta-env',
|
|
146
|
+
'raw-breakpoint',
|
|
146
147
|
// These three honour `basalt-agent-allow`, never `theme-allow` — but they are real ids, so an
|
|
147
148
|
// annotation naming one must parse as a (useless) scoped annotation rather than as prose.
|
|
148
149
|
'agent-resume-guard',
|
|
@@ -175,6 +176,7 @@ export const KNOWN_RULE_IDS = new Set([
|
|
|
175
176
|
'hidden-inline-style',
|
|
176
177
|
'in-body-page-title',
|
|
177
178
|
'raw-selection-control',
|
|
179
|
+
'raw-media-query',
|
|
178
180
|
// Retired guard kinds — no longer in GUARD_RULES, but a `theme-allow` naming one must still
|
|
179
181
|
// parse as a real (dead) waiver rather than an unknown-id typo. See RETIRED_RULE_IDS above.
|
|
180
182
|
...RETIRED_RULE_IDS,
|
|
@@ -2706,7 +2708,7 @@ const CONTROL_OUTSIDE_HOME_MESSAGE =
|
|
|
2706
2708
|
* `@mantine/form` (a form is the third home and its inputs are not filters), and the owner
|
|
2707
2709
|
* exemption — a file DEFINING a basalt control cannot be told to use one.
|
|
2708
2710
|
*/
|
|
2709
|
-
// Ships: warn (grace → 1.
|
|
2711
|
+
// Ships: warn (grace → 1.33.0)
|
|
2710
2712
|
const controlOutsideHome = {
|
|
2711
2713
|
meta: {
|
|
2712
2714
|
type: 'suggestion',
|
|
@@ -3645,8 +3647,20 @@ const queryFnUnwrap = {
|
|
|
3645
3647
|
* @type {readonly DeprecatedExport[]}
|
|
3646
3648
|
*/
|
|
3647
3649
|
export const DEPRECATED_EXPORTS = [
|
|
3648
|
-
//
|
|
3649
|
-
//
|
|
3650
|
+
// The chart phone-tier API (`resolveChartTier`/`chartTierMetrics`/`useChartTier`/
|
|
3651
|
+
// `useChartTierMetrics`/`ChartTierMetrics`/`phoneChartWidth`) is NOT here: MIGRATING.md's own
|
|
3652
|
+
// Unreleased section states it a hard removal with no grace window (zero consumers), and these
|
|
3653
|
+
// exports are no longer reachable from any public barrel in `src/charts`/`src/tokens` — a row
|
|
3654
|
+
// here would nudge a rewrite to an import that no longer resolves, i.e. "it still resolves today"
|
|
3655
|
+
// would be false.
|
|
3656
|
+
{
|
|
3657
|
+
subpath: 'basalt-ui',
|
|
3658
|
+
name: 'useBreakpoint',
|
|
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',
|
|
3662
|
+
fix: false,
|
|
3663
|
+
},
|
|
3650
3664
|
]
|
|
3651
3665
|
|
|
3652
3666
|
function deprecatedExportMessage(row) {
|
|
@@ -3935,6 +3949,336 @@ const noImportMetaEnv = {
|
|
|
3935
3949
|
},
|
|
3936
3950
|
}
|
|
3937
3951
|
|
|
3952
|
+
// ── Rule 32 — raw-breakpoint ─────────────────────────────────────────────────────────────────────
|
|
3953
|
+
|
|
3954
|
+
/** The Mantine responsive-style-prop shorthand keys — `{ base, xs, sm, md, lg, xl }`, never a mix. */
|
|
3955
|
+
const RESPONSIVE_OBJECT_KEYS = new Set(['base', 'xs', 'sm', 'md', 'lg', 'xl'])
|
|
3956
|
+
|
|
3957
|
+
/**
|
|
3958
|
+
* Is `node` a Mantine responsive-style-prop object literal — `{ base: 1, sm: 2 }`? Every property
|
|
3959
|
+
* key has to be one of {@link RESPONSIVE_OBJECT_KEYS}, and there has to be at least one: a random
|
|
3960
|
+
* object that merely happens to have a `sm` key among other, unrelated ones is not this shape, and
|
|
3961
|
+
* an empty object is not a breakpoint decision at all.
|
|
3962
|
+
*/
|
|
3963
|
+
function isResponsiveObjectValue(node, namedOnly = false) {
|
|
3964
|
+
if (node === null || node === undefined || node.type !== 'ObjectExpression') return false
|
|
3965
|
+
if (node.properties.length === 0) return false
|
|
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')
|
|
3973
|
+
}
|
|
3974
|
+
|
|
3975
|
+
/**
|
|
3976
|
+
* Does this prop value CONTAIN a responsive object — itself, nested one level down in a property
|
|
3977
|
+
* (`footer={{ height: { base: 60, sm: 0 } }}`, Mantine's own AppShell idiom), or behind a same-file
|
|
3978
|
+
* `const` binding at either place (`const h = { base: 60, sm: 0 }`, then `footer={{ height: h }}`)?
|
|
3979
|
+
* `consts` is the same-file name→object map, so an Identifier resolves identically wherever it
|
|
3980
|
+
* appears — the top-level attribute value and a nested property value alike. Matching only a nested
|
|
3981
|
+
* `ObjectExpression` left the Identifier-in-a-property shape trivially bypassable.
|
|
3982
|
+
*/
|
|
3983
|
+
function containsResponsiveObjectValue(node, consts, namedOnly = false, seen = new Set()) {
|
|
3984
|
+
const resolved =
|
|
3985
|
+
node !== null && node !== undefined && node.type === 'Identifier' ? consts.get(node.name) : node
|
|
3986
|
+
if (resolved === null || resolved === undefined || resolved.type !== 'ObjectExpression')
|
|
3987
|
+
return false
|
|
3988
|
+
if (seen.has(resolved)) return false
|
|
3989
|
+
seen.add(resolved)
|
|
3990
|
+
if (isResponsiveObjectValue(resolved, namedOnly)) return true
|
|
3991
|
+
return resolved.properties.some(
|
|
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'
|
|
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'
|
|
4068
|
+
}
|
|
4069
|
+
|
|
4070
|
+
/**
|
|
4071
|
+
* The shell components that are `visibleFrom`/`hiddenFrom`'s legitimate home — the size-class
|
|
4072
|
+
* axis's one JSX escape hatch, alongside overlays. Matched by DECLARATION name, the same
|
|
4073
|
+
* owner-by-declaration test `hand-rolled-shell`'s
|
|
4074
|
+
* `notesOwnerDefinition` already uses for "this file IS the framework piece, not a consumer of it"
|
|
4075
|
+
* — a file defining one of these is exempt for the whole file, because deciding which JSX line
|
|
4076
|
+
* inside a shell's own render tree is "the shell deciding its own chrome" vs. "a stray breakpoint"
|
|
4077
|
+
* is not a distinction the shell's own implementation can make about itself. The OTHER legitimate
|
|
4078
|
+
* home is a control implementing its own C9 swap (`ViewTabs`, `ActionGroup`, …) — that half reuses
|
|
4079
|
+
* {@link createControlOwnerProbe} (`controlOwner` below) rather than a second name list.
|
|
4080
|
+
*/
|
|
4081
|
+
const SHELL_HOME_NAMES = new Set(['BasaltShell', 'AppSidebar', 'MobileNav', 'AppBrand'])
|
|
4082
|
+
|
|
4083
|
+
/**
|
|
4084
|
+
* The two files exempted by NAME rather than by declaration: `useMediaQuery`'s own implementation
|
|
4085
|
+
* (`common/use-media-query.ts` — the one sanctioned `window.matchMedia` read every other file,
|
|
4086
|
+
* including `useSizeClass`, now funnels through) and `ChartTooltip` (the Mantine-free chart layer's
|
|
4087
|
+
* own pointer-tier read).
|
|
4088
|
+
*/
|
|
4089
|
+
const RAW_BREAKPOINT_EXEMPT_FILE = /(?:^|[\\/])(?:use-media-query\.ts|ChartTooltip\.tsx)$/
|
|
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
|
+
|
|
4107
|
+
const RAW_BREAKPOINT_RESPONSIVE_PROP_MESSAGE =
|
|
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)`
|
|
4116
|
+
|
|
4117
|
+
const RAW_BREAKPOINT_VISIBLE_HIDDEN_MESSAGE =
|
|
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)`
|
|
4120
|
+
|
|
4121
|
+
const RAW_BREAKPOINT_HOOK_MESSAGE =
|
|
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)`
|
|
4125
|
+
|
|
4126
|
+
const RAW_BREAKPOINT_GLOBAL_MESSAGE =
|
|
4127
|
+
'window.matchMedia/window.innerWidth read directly — the viewport read useSizeClass() owns ' +
|
|
4128
|
+
`for shell chrome. ${RAW_BREAKPOINT_RECIPE} (basalt/raw-breakpoint)`
|
|
4129
|
+
|
|
4130
|
+
/** The three viewport hooks the law names, whatever module they are imported from. */
|
|
4131
|
+
const RAW_BREAKPOINT_HOOK_NAMES = new Set(['useMediaQuery', 'useMatches', 'useViewportSize'])
|
|
4132
|
+
|
|
4133
|
+
/**
|
|
4134
|
+
* Four independent shapes, one law: a consumer (or basalt itself, outside the shell homes)
|
|
4135
|
+
* reaching past the framework's two sanctioned seams — `useSizeClass()` for shell-only viewport
|
|
4136
|
+
* chrome, a container query for everything else — to read or react to a raw
|
|
4137
|
+
* viewport breakpoint. `visibleFrom`/`hiddenFrom` and the responsive-object shape are reported once
|
|
4138
|
+
* the whole file has been walked ({@link SHELL_HOME_NAMES} may be declared after its first JSX use,
|
|
4139
|
+
* the same ordering hazard `hand-rolled-shell` defers a `Program:exit` report to avoid); the import
|
|
4140
|
+
* and the two global reads carry no such ordering hazard and report immediately. A file that
|
|
4141
|
+
* declares a shell home (or a control's own C9 swap) is exempt for all four shapes uniformly — the
|
|
4142
|
+
* shell's own responsive chrome is the sanctioned use, whatever shape it takes.
|
|
4143
|
+
*/
|
|
4144
|
+
// Ships: warn (grace → 1.33.0)
|
|
4145
|
+
const rawBreakpoint = {
|
|
4146
|
+
meta: {
|
|
4147
|
+
type: 'suggestion',
|
|
4148
|
+
docs: {
|
|
4149
|
+
description:
|
|
4150
|
+
'Disallow a hand-rolled viewport breakpoint — a responsive-object Mantine prop, ' +
|
|
4151
|
+
'visibleFrom/hiddenFrom outside a shell home, useMediaQuery/useMatches/useViewportSize, or ' +
|
|
4152
|
+
'a raw window.matchMedia/innerWidth read. All four shapes are exempt inside a file that ' +
|
|
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.',
|
|
4155
|
+
},
|
|
4156
|
+
schema: [],
|
|
4157
|
+
},
|
|
4158
|
+
create(context) {
|
|
4159
|
+
if (isTestFile(context)) return {}
|
|
4160
|
+
if (RAW_BREAKPOINT_EXEMPT_FILE.test(getFilename(context))) return {}
|
|
4161
|
+
|
|
4162
|
+
const mantineImports = new Map()
|
|
4163
|
+
// A control implementing its OWN C9 responsive swap (`ViewTabs`, `ActionGroup`'s file, …) is
|
|
4164
|
+
// the other legitimate visibleFrom/hiddenFrom home, alongside the three named shell pieces —
|
|
4165
|
+
// reuse `responsive-twin`'s existing owner probe rather than hand-listing every control file
|
|
4166
|
+
// here too (`view-tabs.tsx`/`actions.tsx` were both false positives before this reuse).
|
|
4167
|
+
const controlOwner = createControlOwnerProbe()
|
|
4168
|
+
let definesShellHome = false
|
|
4169
|
+
const visibleHiddenCandidates = []
|
|
4170
|
+
const responsiveObjectCandidates = []
|
|
4171
|
+
// Same-file `const NAME = { base, sm }` bindings, resolved when a JSX attribute or a nested
|
|
4172
|
+
// property passes the Identifier — no scope manager here, so this is a flat name→object map.
|
|
4173
|
+
// A name declared more than once in the file is ambiguous (its two bindings cannot be told
|
|
4174
|
+
// apart), so it is dropped from the map entirely rather than guessed at last-wins.
|
|
4175
|
+
const responsiveObjectConsts = new Map()
|
|
4176
|
+
const seenDeclaratorNames = new Set()
|
|
4177
|
+
|
|
4178
|
+
const noteShellHomeOwner = (name) => {
|
|
4179
|
+
if (typeof name === 'string' && SHELL_HOME_NAMES.has(name)) definesShellHome = true
|
|
4180
|
+
}
|
|
4181
|
+
|
|
4182
|
+
return {
|
|
4183
|
+
ImportDeclaration(node) {
|
|
4184
|
+
controlOwner.noteImport(node)
|
|
4185
|
+
collectMantineImports(node, mantineImports)
|
|
4186
|
+
if (node.importKind === 'type') return
|
|
4187
|
+
// `useMatches` collides with `@tanstack/react-router`'s own hook of the same name (basalt's
|
|
4188
|
+
// own `src/router-tanstack/index.ts` imports it) — scope the whole set to a `@mantine/*`
|
|
4189
|
+
// source rather than name alone, the same provenance gate every other Mantine-name rule in
|
|
4190
|
+
// this file already uses (`collectMantineImports`).
|
|
4191
|
+
const source = node.source?.value
|
|
4192
|
+
if (typeof source !== 'string' || !source.startsWith('@mantine/')) return
|
|
4193
|
+
for (const specifier of node.specifiers ?? []) {
|
|
4194
|
+
if (specifier.type !== 'ImportSpecifier') continue
|
|
4195
|
+
if (specifier.importKind === 'type') continue
|
|
4196
|
+
const imported = specifier.imported
|
|
4197
|
+
const importedName = imported.type === 'Identifier' ? imported.name : imported.value
|
|
4198
|
+
if (typeof importedName !== 'string' || !RAW_BREAKPOINT_HOOK_NAMES.has(importedName))
|
|
4199
|
+
continue
|
|
4200
|
+
if (hasThemeAllow(context, specifier, 'raw-breakpoint')) continue
|
|
4201
|
+
context.report({ node: specifier, message: RAW_BREAKPOINT_HOOK_MESSAGE })
|
|
4202
|
+
}
|
|
4203
|
+
},
|
|
4204
|
+
FunctionDeclaration(node) {
|
|
4205
|
+
noteShellHomeOwner(node.id?.name)
|
|
4206
|
+
controlOwner.visitors.FunctionDeclaration(node)
|
|
4207
|
+
},
|
|
4208
|
+
VariableDeclarator(node) {
|
|
4209
|
+
noteShellHomeOwner(node.id?.name)
|
|
4210
|
+
controlOwner.visitors.VariableDeclarator(node)
|
|
4211
|
+
if (node.id?.type !== 'Identifier') return
|
|
4212
|
+
const name = node.id.name
|
|
4213
|
+
if (seenDeclaratorNames.has(name)) {
|
|
4214
|
+
// A redeclared name — drop whatever the first declaration put here, so the ambiguous
|
|
4215
|
+
// binding is never used to flag (or clear) a JSX value it may not even be.
|
|
4216
|
+
responsiveObjectConsts.delete(name)
|
|
4217
|
+
return
|
|
4218
|
+
}
|
|
4219
|
+
seenDeclaratorNames.add(name)
|
|
4220
|
+
if (node.init?.type === 'ObjectExpression') responsiveObjectConsts.set(name, node.init)
|
|
4221
|
+
},
|
|
4222
|
+
JSXAttribute(node) {
|
|
4223
|
+
const name = node.name?.name
|
|
4224
|
+
if (typeof name !== 'string') return
|
|
4225
|
+
if (name === 'visibleFrom' || name === 'hiddenFrom') {
|
|
4226
|
+
visibleHiddenCandidates.push(node)
|
|
4227
|
+
return
|
|
4228
|
+
}
|
|
4229
|
+
// Resolved at `Program:exit` so a `const` declared after its first JSX use still resolves.
|
|
4230
|
+
responsiveObjectCandidates.push(node)
|
|
4231
|
+
},
|
|
4232
|
+
CallExpression(node) {
|
|
4233
|
+
if (node.callee?.type !== 'Identifier' || node.callee.name !== 'matchMedia') return
|
|
4234
|
+
if (hasThemeAllow(context, node, 'raw-breakpoint')) return
|
|
4235
|
+
context.report({ node, message: RAW_BREAKPOINT_GLOBAL_MESSAGE })
|
|
4236
|
+
},
|
|
4237
|
+
MemberExpression(node) {
|
|
4238
|
+
if (node.object?.type !== 'Identifier' || node.object.name !== 'window') return
|
|
4239
|
+
if (node.computed) return
|
|
4240
|
+
const property = node.property?.name
|
|
4241
|
+
if (property !== 'matchMedia' && property !== 'innerWidth') return
|
|
4242
|
+
if (hasThemeAllow(context, node, 'raw-breakpoint')) return
|
|
4243
|
+
context.report({ node, message: RAW_BREAKPOINT_GLOBAL_MESSAGE })
|
|
4244
|
+
},
|
|
4245
|
+
'Program:exit'() {
|
|
4246
|
+
// A shell home (or a control implementing its own C9 swap) IS the framework piece — the
|
|
4247
|
+
// shell's own responsive chrome is the sanctioned use, so nothing here reports there.
|
|
4248
|
+
if (definesShellHome || controlOwner.isOwner()) return
|
|
4249
|
+
for (const node of responsiveObjectCandidates) {
|
|
4250
|
+
const value = unwrapExpressionContainer(node.value)
|
|
4251
|
+
const owner = node.parent
|
|
4252
|
+
if (owner === null || owner === undefined || owner.type !== 'JSXOpeningElement') continue
|
|
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
|
|
4266
|
+
if (hasThemeAllow(context, node, 'raw-breakpoint')) continue
|
|
4267
|
+
const message =
|
|
4268
|
+
mode === undefined
|
|
4269
|
+
? RAW_BREAKPOINT_RESPONSIVE_PROP_MESSAGE
|
|
4270
|
+
: RAW_BREAKPOINT_CONTAINER_KEY_MESSAGE
|
|
4271
|
+
context.report({ node, message })
|
|
4272
|
+
}
|
|
4273
|
+
for (const node of visibleHiddenCandidates) {
|
|
4274
|
+
if (hasThemeAllow(context, node, 'raw-breakpoint')) continue
|
|
4275
|
+
context.report({ node, message: RAW_BREAKPOINT_VISIBLE_HIDDEN_MESSAGE })
|
|
4276
|
+
}
|
|
4277
|
+
},
|
|
4278
|
+
}
|
|
4279
|
+
},
|
|
4280
|
+
}
|
|
4281
|
+
|
|
3938
4282
|
// ── Grace ledger ────────────────────────────────────────────────────────────────────────────────
|
|
3939
4283
|
|
|
3940
4284
|
/**
|
|
@@ -3968,8 +4312,10 @@ const noImportMetaEnv = {
|
|
|
3968
4312
|
export const PLUGIN_RULE_GRACE = {
|
|
3969
4313
|
'control-outside-home': {
|
|
3970
4314
|
since: '1.26.0',
|
|
3971
|
-
promote: '1.
|
|
4315
|
+
promote: '1.33.0',
|
|
3972
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. " +
|
|
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. ' +
|
|
3973
4319
|
'the wave-6 control guards (docs/CONTROLS-SPEC.md §6). The one openly HEURISTIC rule of the ' +
|
|
3974
4320
|
'set — "this control has no home" is a claim about layout intent, so its false-positive load ' +
|
|
3975
4321
|
'is carried by four exemptions (overlay/settings-row ancestor, the overlay FILENAME ' +
|
|
@@ -3995,6 +4341,26 @@ export const PLUGIN_RULE_GRACE = {
|
|
|
3995
4341
|
"still an overlay's own body declares it with " +
|
|
3996
4342
|
'`theme-allow-file control-outside-home — overlay`.',
|
|
3997
4343
|
},
|
|
4344
|
+
'raw-breakpoint': {
|
|
4345
|
+
since: '1.31.0',
|
|
4346
|
+
promote: '1.33.0',
|
|
4347
|
+
why:
|
|
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.',
|
|
4363
|
+
},
|
|
3998
4364
|
}
|
|
3999
4365
|
|
|
4000
4366
|
/**
|
|
@@ -4064,5 +4430,6 @@ export default {
|
|
|
4064
4430
|
'agent-no-raw-usechat': agentNoRawUseChat,
|
|
4065
4431
|
'ai-sdk-major': aiSdkMajor,
|
|
4066
4432
|
'no-import-meta-env': noImportMetaEnv,
|
|
4433
|
+
'raw-breakpoint': rawBreakpoint,
|
|
4067
4434
|
},
|
|
4068
4435
|
}
|