basalt-ui 1.29.1 → 1.30.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 +16 -0
- package/MIGRATING.md +701 -369
- package/README.md +23 -2
- package/agent/rules/basalt-controls.md +34 -34
- package/agent/skills/basalt-app/SKILL.md +4 -2
- package/agent/templates/query-client.ts.tpl +18 -4
- package/configs/lefthook.yml +51 -19
- package/configs/oxlint-plugin.js +210 -84
- package/configs/oxlint-plugin.test.ts +182 -5
- package/configs/oxlint.json +4 -4
- package/dist/charts/primitives/ChartCard.d.ts.map +1 -1
- package/dist/charts/primitives/ChartCard.js +2 -2
- package/dist/charts/primitives/ChartFrame.d.ts +23 -3
- package/dist/charts/primitives/ChartFrame.d.ts.map +1 -1
- package/dist/charts/primitives/ChartFrame.js +4 -4
- package/dist/charts/primitives/chart-frame-layout.d.ts +55 -0
- package/dist/charts/primitives/chart-frame-layout.d.ts.map +1 -1
- package/dist/charts/primitives/chart-frame-layout.js +16 -0
- package/dist/cli/check-theme.d.ts.map +1 -1
- package/dist/cli/check-theme.js +6 -0
- package/dist/cli/doctor.d.ts +10 -4
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +28 -1
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +2 -1
- package/dist/cli/index.d.ts +12 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +29 -0
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +4 -15
- package/dist/cli/sync.d.ts.map +1 -1
- package/dist/cli/sync.js +8 -14
- package/dist/controls/actions.d.ts.map +1 -1
- package/dist/controls/actions.js +12 -2
- package/dist/dashboard/section.module.css +15 -7
- package/dist/dashboard/stat-card.d.ts.map +1 -1
- package/dist/dashboard/stat-card.js +7 -2
- package/dist/dashboard/stat-group.d.ts +8 -2
- package/dist/dashboard/stat-group.d.ts.map +1 -1
- package/dist/dashboard/stat-group.js +23 -15
- package/dist/dashboard/stat-group.module.css +85 -9
- package/dist/dashboard/stat-group.module.css.d.ts +1 -0
- package/dist/dashboard/widget-grid.d.ts.map +1 -1
- package/dist/dashboard/widget-grid.js +4 -5
- package/dist/dashboard/widget-grid.module.css +64 -21
- package/dist/dashboard/widget-grid.module.css.d.ts +1 -0
- package/dist/guard/index.d.ts +19 -2
- package/dist/guard/index.d.ts.map +1 -1
- package/dist/guard/index.js +27 -4
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/query-client.d.ts +20 -2
- package/dist/query-client.d.ts.map +1 -1
- package/dist/shell/app-brand.module.css +12 -3
- package/dist/shell/app-header.module.css +49 -9
- package/dist/shell/app-main.module.css +24 -4
- package/dist/shell/app-mobile-nav.d.ts.map +1 -1
- package/dist/shell/app-mobile-nav.js +98 -51
- package/dist/shell/app-mobile-nav.module.css +99 -11
- package/dist/shell/app-mobile-nav.module.css.d.ts +1 -0
- package/dist/shell/app-sidebar.module.css +55 -2
- package/dist/shell/index.d.ts.map +1 -1
- package/dist/shell/index.js +3 -3
- package/dist/shell/mobile-nav-model.d.ts +26 -7
- package/dist/shell/mobile-nav-model.d.ts.map +1 -1
- package/dist/shell/mobile-nav-model.js +12 -3
- package/dist/shell/page-aside.module.css +8 -6
- package/dist/shell/page-bar.d.ts +13 -0
- package/dist/shell/page-bar.d.ts.map +1 -1
- package/dist/shell/page-bar.js +13 -3
- package/dist/shell/page-bar.module.css +20 -12
- package/dist/shell/page-title.module.css +3 -1
- package/dist/theme/use-basalt-spacing.d.ts.map +1 -1
- package/dist/tokens/index.d.ts.map +1 -1
- package/dist/tokens/index.js +51 -7
- package/dist/tokens/palette.d.ts +98 -17
- package/dist/tokens/palette.d.ts.map +1 -1
- package/dist/tokens/palette.js +110 -18
- package/dist/tokens.css +17 -5
- package/llms.txt +2 -2
- package/package.json +1 -1
- package/src/charts/primitives/ChartCard.tsx +12 -7
- package/src/charts/primitives/ChartFrame.tsx +30 -15
- package/src/charts/primitives/chart-frame-layout.ts +86 -0
- package/src/cli/check-theme.ts +13 -0
- package/src/cli/doctor.ts +49 -8
- package/src/cli/help.ts +5 -3
- package/src/cli/index.ts +49 -0
- package/src/cli/init.ts +6 -27
- package/src/cli/sync.ts +11 -22
- package/src/controls/actions.tsx +51 -0
- package/src/dashboard/section.module.css +15 -7
- package/src/dashboard/stat-card.tsx +7 -2
- package/src/dashboard/stat-group.module.css +85 -9
- package/src/dashboard/stat-group.module.css.d.ts +1 -0
- package/src/dashboard/stat-group.tsx +40 -20
- package/src/dashboard/widget-grid.module.css +64 -21
- package/src/dashboard/widget-grid.module.css.d.ts +1 -0
- package/src/dashboard/widget-grid.tsx +30 -12
- package/src/guard/index.ts +79 -11
- package/src/index.ts +9 -0
- package/src/query-client.ts +17 -5
- package/src/shell/app-brand.module.css +12 -3
- package/src/shell/app-header.module.css +49 -9
- package/src/shell/app-main.module.css +24 -4
- package/src/shell/app-mobile-nav.module.css +99 -11
- package/src/shell/app-mobile-nav.module.css.d.ts +1 -0
- package/src/shell/app-mobile-nav.tsx +225 -83
- package/src/shell/app-sidebar.module.css +55 -2
- package/src/shell/index.tsx +26 -6
- package/src/shell/mobile-nav-model.ts +37 -9
- package/src/shell/page-aside.module.css +8 -6
- package/src/shell/page-bar.module.css +20 -12
- package/src/shell/page-bar.tsx +39 -5
- package/src/shell/page-title.module.css +3 -1
- package/src/theme/use-basalt-spacing.ts +8 -6
- package/src/tokens/index.ts +90 -6
- package/src/tokens/palette.ts +111 -18
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"widget-grid.d.ts","sourceRoot":"","sources":["../../src/dashboard/widget-grid.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"widget-grid.d.ts","sourceRoot":"","sources":["../../src/dashboard/widget-grid.tsx"],"names":[],"mappings":"AAoDA,OAAO,KAAK,EAAiB,SAAS,EAAE,MAAM,OAAO,CAAA;AAErD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAGlD,uGAAuG;AACvG,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;AAgB1C,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG;IAC1C;8FAC0F;IAC1F,IAAI,CAAC,EAAE,cAAc,CAAA;IACrB,8FAA8F;IAC9F,QAAQ,EAAE,SAAS,CAAA;CACpB,CAAA;AAED,wBAAgB,UAAU,CAAC,EAAE,IAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,eAAe,+BA8BnF;yBA9Be,UAAU;;;AAgC1B,MAAM,MAAM,mBAAmB,GAAG,WAAW,GAAG;IAC9C,oGAAoG;IACpG,IAAI,CAAC,EAAE,cAAc,CAAA;IACrB,sCAAsC;IACtC,QAAQ,EAAE,SAAS,CAAA;CACpB,CAAA;AAED;;GAEG;AACH,iBAAS,cAAc,CAAC,EAAE,IAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,mBAAmB,+BAkBpF"}
|
|
@@ -5,19 +5,18 @@ import classes from "./widget-grid.module.css";
|
|
|
5
5
|
const WidgetGridColsContext = createContext({ sm: 2, lg: 2 });
|
|
6
6
|
function WidgetGrid({ cols = 2, children, className, style }) {
|
|
7
7
|
const resolved = useMemo(() => ({ sm: Math.min(cols, 2), lg: cols }), [cols]);
|
|
8
|
-
return /* @__PURE__ */ jsx(WidgetGridColsContext.Provider, { value: resolved, children: /* @__PURE__ */ jsx(
|
|
8
|
+
return /* @__PURE__ */ jsx(WidgetGridColsContext.Provider, { value: resolved, children: /* @__PURE__ */ jsx("div", { className: cx(classes.container, className), style, children: /* @__PURE__ */ jsx(
|
|
9
9
|
"div",
|
|
10
10
|
{
|
|
11
|
-
className:
|
|
11
|
+
className: classes.root,
|
|
12
12
|
"data-cols": cols,
|
|
13
13
|
style: {
|
|
14
14
|
"--basalt-widget-grid-cols-sm": resolved.sm,
|
|
15
|
-
"--basalt-widget-grid-cols-lg": resolved.lg
|
|
16
|
-
...style
|
|
15
|
+
"--basalt-widget-grid-cols-lg": resolved.lg
|
|
17
16
|
},
|
|
18
17
|
children
|
|
19
18
|
}
|
|
20
|
-
) });
|
|
19
|
+
) }) });
|
|
21
20
|
}
|
|
22
21
|
function WidgetGridItem({ span = 1, children, className, style }) {
|
|
23
22
|
const cols = useContext(WidgetGridColsContext);
|
|
@@ -1,15 +1,34 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* WidgetGrid's column law, in CSS (law C9 — a responsive swap belongs to the control, never to a JS
|
|
3
|
-
* media query).
|
|
4
|
-
* `--mantine-breakpoint-lg` (75em); a `@media` condition is resolved before custom properties
|
|
5
|
-
* exist, so the number has to be written — same standing constraint `content/article-layout.
|
|
6
|
-
* module.css` documents.
|
|
3
|
+
* media query).
|
|
7
4
|
*
|
|
8
|
-
* The
|
|
9
|
-
*
|
|
10
|
-
*
|
|
5
|
+
* **The law keys on the CONTAINER, not the viewport**, for the reason `stat-group.module.css`'s
|
|
6
|
+
* header states in full: the shell moves the available width without moving the viewport (a
|
|
7
|
+
* `PageAside` claiming 300px, the sidebar collapsing to its 48px rail, a consumer's split layout),
|
|
8
|
+
* and `@media` is blind to all of it. `.container` — rendered by `WidgetGrid` around the grid —
|
|
9
|
+
* is what makes the queries answerable and is always the box the grid actually fills; a query with
|
|
10
|
+
* no container resolves to false, so leaning on the shell to establish one would have pinned every
|
|
11
|
+
* non-shell consumer to a single column.
|
|
12
|
+
*
|
|
13
|
+
* `.item`'s span law is in the same blocks for the same reason: `grid-column: span <n>` must be
|
|
14
|
+
* clamped against the count the ROOT is actually rendering, and the root's count now follows the
|
|
15
|
+
* container. A span resolved against the viewport while the tracks follow the container is exactly
|
|
16
|
+
* the phantom-track defect `WidgetGrid.Item`'s context clamp exists to prevent.
|
|
17
|
+
*
|
|
18
|
+
* The literals: px in `@container`, Mantine's own `em` in the `@supports not` fallback — same
|
|
19
|
+
* boundary (768px / 1200px at the 16px initial font size), but `em` inside a `@container`
|
|
20
|
+
* condition resolves against the CONTAINER's font-size, so px is the only spelling that cannot
|
|
21
|
+
* drift. A condition cannot read a custom property either way, so the numbers are written; the
|
|
22
|
+
* COUNTS are custom properties, set once per instance by the component — three hand-written
|
|
23
|
+
* `repeat()` blocks would have to enumerate every `cols` value, and the whole point of this
|
|
24
|
+
* primitive is that a consumer states one desktop number and basalt owns the rest.
|
|
11
25
|
*/
|
|
12
26
|
|
|
27
|
+
.container {
|
|
28
|
+
container-type: inline-size;
|
|
29
|
+
container-name: basalt-widget-grid;
|
|
30
|
+
}
|
|
31
|
+
|
|
13
32
|
.root {
|
|
14
33
|
display: grid;
|
|
15
34
|
/* Below `sm` a widget column is always 1 — a dashboard card holds a chart, and two of them on a
|
|
@@ -18,18 +37,6 @@
|
|
|
18
37
|
gap: var(--vx-space-stack-md);
|
|
19
38
|
}
|
|
20
39
|
|
|
21
|
-
@media (min-width: 48em) {
|
|
22
|
-
.root {
|
|
23
|
-
grid-template-columns: repeat(var(--basalt-widget-grid-cols-sm), minmax(0, 1fr));
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
@media (min-width: 75em) {
|
|
28
|
-
.root {
|
|
29
|
-
grid-template-columns: repeat(var(--basalt-widget-grid-cols-lg), minmax(0, 1fr));
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
40
|
/*
|
|
34
41
|
* `min-width: 0` on every cell: a grid track's default `min-width: auto` is its content's intrinsic
|
|
35
42
|
* width, so one wide `<table>` or one long unbroken value blows the whole row out instead of
|
|
@@ -40,14 +47,50 @@
|
|
|
40
47
|
min-width: 0;
|
|
41
48
|
}
|
|
42
49
|
|
|
43
|
-
@
|
|
50
|
+
@container basalt-widget-grid (min-width: 768px) {
|
|
51
|
+
.root {
|
|
52
|
+
grid-template-columns: repeat(var(--basalt-widget-grid-cols-sm), minmax(0, 1fr));
|
|
53
|
+
}
|
|
54
|
+
|
|
44
55
|
.item {
|
|
45
56
|
grid-column: span var(--basalt-widget-grid-span-sm);
|
|
46
57
|
}
|
|
47
58
|
}
|
|
48
59
|
|
|
49
|
-
@
|
|
60
|
+
@container basalt-widget-grid (min-width: 1200px) {
|
|
61
|
+
.root {
|
|
62
|
+
grid-template-columns: repeat(var(--basalt-widget-grid-cols-lg), minmax(0, 1fr));
|
|
63
|
+
}
|
|
64
|
+
|
|
50
65
|
.item {
|
|
51
66
|
grid-column: span var(--basalt-widget-grid-span-lg);
|
|
52
67
|
}
|
|
53
68
|
}
|
|
69
|
+
|
|
70
|
+
/*
|
|
71
|
+
* The pre-container-query fallback — Safari < 16, Chrome < 106, Firefox < 110. Verbatim the law
|
|
72
|
+
* this file shipped before, keyed on the viewport, and reachable ONLY where `@container` is not: a
|
|
73
|
+
* browser that cannot parse `container-type` cannot parse the blocks above either, so the two sets
|
|
74
|
+
* are never live at once.
|
|
75
|
+
*/
|
|
76
|
+
@supports not (container-type: inline-size) {
|
|
77
|
+
@media (min-width: 48em) {
|
|
78
|
+
.root {
|
|
79
|
+
grid-template-columns: repeat(var(--basalt-widget-grid-cols-sm), minmax(0, 1fr));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.item {
|
|
83
|
+
grid-column: span var(--basalt-widget-grid-span-sm);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@media (min-width: 75em) {
|
|
88
|
+
.root {
|
|
89
|
+
grid-template-columns: repeat(var(--basalt-widget-grid-cols-lg), minmax(0, 1fr));
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.item {
|
|
93
|
+
grid-column: span var(--basalt-widget-grid-span-lg);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
package/dist/guard/index.d.ts
CHANGED
|
@@ -90,6 +90,23 @@ export declare function unmatchedExemptPatterns(cfg: GuardConfig, scannedRelPath
|
|
|
90
90
|
* with the plugin's own `KNOWN_RULE_IDS`; `configs/oxlint-plugin.test.ts` asserts the two agree.
|
|
91
91
|
*/
|
|
92
92
|
export declare const PLUGIN_RULE_IDS: ReadonlySet<string>;
|
|
93
|
+
/**
|
|
94
|
+
* ONE LAW, TWO RULE IDS — the ids that waive each other, in BOTH directions.
|
|
95
|
+
*
|
|
96
|
+
* `raw-selection-control` (this lane) and `basalt/control-outside-home` (the oxlint plugin) are the
|
|
97
|
+
* same law read by two engines, and this lane's own message already says so. They keep separate ids
|
|
98
|
+
* because the two engines disagree often enough that a consumer needs to be able to name which one
|
|
99
|
+
* they are waiving — but a consumer waiving the LAW should not have to know that, and before this
|
|
100
|
+
* map they did: `theme-allow control-outside-home` parsed here (the plugin's ids are all known,
|
|
101
|
+
* see {@link PLUGIN_RULE_IDS}) and then covered nothing, so the only working annotation was
|
|
102
|
+
* `theme-allow raw-selection-control control-outside-home` — two ids, undocumented, one silent
|
|
103
|
+
* debug cycle per consumer. `in-body-page-title` needs no entry: it is one id in both lanes.
|
|
104
|
+
*
|
|
105
|
+
* Mirrored VERBATIM in `configs/oxlint-plugin.js` (which cannot import from this package — see its
|
|
106
|
+
* header); `check-source.test.ts` asserts the two agree. An alias only ever WIDENS what an
|
|
107
|
+
* annotation covers, so a waiver can never become stricter by being spelled the other way.
|
|
108
|
+
*/
|
|
109
|
+
export declare const WAIVER_ID_ALIASES: Readonly<Record<string, readonly string[]>>;
|
|
93
110
|
/**
|
|
94
111
|
* The exact first line of every stylesheet the CLI emits — the contract between `basalt-ui
|
|
95
112
|
* tokens:css` / `fonts:css` and this scanner, and the single source of truth for it (`src/cli`
|
|
@@ -279,13 +296,13 @@ export declare const GUARD_RULES: {
|
|
|
279
296
|
readonly kind: "in-body-page-title";
|
|
280
297
|
readonly pattern: RegExp;
|
|
281
298
|
readonly appliesTo: (relPath: string) => boolean;
|
|
282
|
-
readonly message: "In-body page title — a page is named ONCE
|
|
299
|
+
readonly message: "In-body page title — a page is named ONCE: by the breadcrumb (staticData.title), by PageBar.title, or by <PageTitle> on a shell-less surface (a route error, an auth gate, a standalone screen). Every section/card/table title is a WidgetHeader (docs/CONTROLS-SPEC.md law C8). An <Title order={1|2}> spelling a name out in the body is a second name for the same page, and it drifts. A Title rendering a VALUE — {doc.title}, {RANK_LABEL[rank]} — never reports: that is data, not a name. Prose / ArticleLayout / an overlay and anything under a content/ path never report either. Same law the oxlint plugin enforces as basalt/in-body-page-title — one id, two lanes, so one theme-allow covers both.";
|
|
283
300
|
};
|
|
284
301
|
readonly 'raw-selection-control': {
|
|
285
302
|
readonly kind: "raw-selection-control";
|
|
286
303
|
readonly pattern: RegExp;
|
|
287
304
|
readonly appliesTo: (relPath: string) => boolean;
|
|
288
|
-
readonly message: "Raw selection control with no home — a filter or tab belongs in a PageBar / Section / WidgetHeader slot and takes a `field` (a FieldHandle), so it owns the URL write and the localStorage mirror instead of carrying value/onChange (docs/CONTROLS-SPEC.md laws C1–C3). Use the bound control from basalt-ui/controls. A settings row, an overlay and an @mantine/form file are the declared non-homes and never report. This is the TEXT lane of basalt/control-outside-home, which answers the same question against the real AST — where the two disagree, the plugin is right.";
|
|
305
|
+
readonly message: "Raw selection control with no home — a filter or tab belongs in a PageBar / Section / WidgetHeader slot and takes a `field` (a FieldHandle), so it owns the URL write and the localStorage mirror instead of carrying value/onChange (docs/CONTROLS-SPEC.md laws C1–C3). Use the bound control from basalt-ui/controls. A settings row, an overlay and an @mantine/form file are the declared non-homes and never report. No shell? PageBar needs no BasaltShell: outside one it renders in flow, sticky, with its own title — so its slots are a reachable home for a provider-only app. This is the TEXT lane of basalt/control-outside-home, which answers the same question against the real AST — where the two disagree, the plugin is right.";
|
|
289
306
|
};
|
|
290
307
|
readonly 'inline-font-size': {
|
|
291
308
|
readonly kind: "inline-font-size";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/guard/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAE7E,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/guard/index.ts"],"names":[],"mappings":"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"}
|
package/dist/guard/index.js
CHANGED
|
@@ -158,6 +158,16 @@ const RAW_FORM_CONTROL = /<(?:input|select|textarea)\b/g;
|
|
|
158
158
|
const RAW_FORM_CONTROL_TAG = /<(?:input|select|textarea)\b(?:=>|[^>])*?>/g;
|
|
159
159
|
const PAGE_TITLE_TAG = /<Title(?![\w.])(?:=>|[^>])*?>/g;
|
|
160
160
|
const PAGE_TITLE_ORDER_PROP = /\border\s*=\s*\{\s*([12])\s*\}/;
|
|
161
|
+
const PAGE_TITLE_BRACED_RUN = /\{[^{}]*(?:\{[^{}]*\}[^{}]*)*\}/g;
|
|
162
|
+
const PAGE_TITLE_LAUNDERED_LITERAL = /^\s*['"`][^'"`]*['"`]\s*$/;
|
|
163
|
+
function titleBodyNamesThePage(body) {
|
|
164
|
+
let outsideBraces = body;
|
|
165
|
+
for (const braced of body.match(PAGE_TITLE_BRACED_RUN) ?? []) {
|
|
166
|
+
if (PAGE_TITLE_LAUNDERED_LITERAL.test(braced.slice(1, -1))) return true;
|
|
167
|
+
outsideBraces = outsideBraces.replace(braced, "");
|
|
168
|
+
}
|
|
169
|
+
return outsideBraces.replace(/<[^>]*>/g, "").trim() !== "";
|
|
170
|
+
}
|
|
161
171
|
const RAW_SELECTION_CONTROL_TAG = /<(SegmentedControl|Select|MultiSelect|NativeSelect|DatePickerInput|DateInput|TagsInput|Chip\.Group)(?![\w])(?:=>|[^>])*?>/g;
|
|
162
172
|
const PROSE_CONTEXT_TAG = /<(?:Prose|ArticleLayout|Modal|Drawer)(?![\w])/;
|
|
163
173
|
const CONTROL_HOST_TAG = /<(?:SettingsRow|Modal|Drawer|Popover\.Dropdown|Menu\.Dropdown|Composer|FilterSet|PageAside|PanelRow)(?![\w])/;
|
|
@@ -198,8 +208,8 @@ const DEFAULT_GUARD_CONFIG = {
|
|
|
198
208
|
const GRACE_PERIOD_KINDS = {
|
|
199
209
|
"raw-selection-control": {
|
|
200
210
|
since: "1.26.0",
|
|
201
|
-
promote: "1.
|
|
202
|
-
why: 'new in the wave-6 control guards (docs/CONTROLS-SPEC.md \xA76, law C1). The text lane cannot see ancestry, so "no home" is approximated by a 12-line host-tag window \u2014 the loosest reading in the guard, and the reason this one lands warn rather than error even though its law is settled.
|
|
211
|
+
promote: "1.31.0",
|
|
212
|
+
why: 'new in the wave-6 control guards (docs/CONTROLS-SPEC.md \xA76, law C1). The text lane cannot see ancestry, so "no home" is approximated by a 12-line host-tag window \u2014 the loosest reading in the guard, and the reason this one lands warn rather than error even though its law is settled. ONE LAW, TWO LANES, ONE PROMOTION: it moves with its AST twin, `basalt/control-outside-home`, whose PLUGIN_RULE_GRACE entry carries the full argument and the measurement, and it must never be promoted or extended alone \u2014 a consumer waiving one spelling and failing the other is the exact confusion `WAIVER_ID_ALIASES` exists to close. RE-MEASURED 2026-09-09 across the whole fleet on 1.29.2: 29 AST-lane incumbents in five repos, plus three of basalt\'s own (data-table, notifications/center, theme-lab). Extended to 1.31.0 because 1.30.0 is the FIRST release in which either lane names a home a provider-only consumer can reach \u2014 every home both messages listed was a shell slot, and the shell-less `PageBar` sentence ships in this minor. Promoting in the same minor that makes a rule satisfiable gives nobody a window to act. 1.31.0 is when the 29 are re-measured against that number.'
|
|
203
213
|
}
|
|
204
214
|
};
|
|
205
215
|
function severityOf(kind, cfg) {
|
|
@@ -321,6 +331,10 @@ const PLUGIN_RULE_IDS = /* @__PURE__ */ new Set([
|
|
|
321
331
|
// Mirrored by the plugin's own `RETIRED_RULE_IDS`.
|
|
322
332
|
"query-dual-import"
|
|
323
333
|
]);
|
|
334
|
+
const WAIVER_ID_ALIASES = {
|
|
335
|
+
"control-outside-home": ["raw-selection-control"],
|
|
336
|
+
"raw-selection-control": ["control-outside-home"]
|
|
337
|
+
};
|
|
324
338
|
const MIN_ALLOW_REASON_LENGTH = 4;
|
|
325
339
|
function parseAllowAnnotation(rest, scope) {
|
|
326
340
|
const rules = [];
|
|
@@ -445,6 +459,7 @@ function collectAllowAnnotations(lines, codeLines, allowComment, syntax) {
|
|
|
445
459
|
}
|
|
446
460
|
function annotationCovers(annotation, kind) {
|
|
447
461
|
if (annotation.rules.includes(kind)) return true;
|
|
462
|
+
if ((WAIVER_ID_ALIASES[kind] ?? []).some((alias) => annotation.rules.includes(alias))) return true;
|
|
448
463
|
if (annotation.scope === "file") return false;
|
|
449
464
|
return annotation.rules.length === 0 && annotation.unknownRules.length === 0;
|
|
450
465
|
}
|
|
@@ -868,7 +883,7 @@ const GUARD_RULES = {
|
|
|
868
883
|
// handled inline (full-text tag-scoped scan); entry keeps the registry complete
|
|
869
884
|
// JSX-tag-shaped (`<Title order={1}>`) — never appears in CSS text.
|
|
870
885
|
appliesTo: (relPath) => !relPath.endsWith(".css"),
|
|
871
|
-
message: "In-body page title \u2014 a page is named ONCE
|
|
886
|
+
message: "In-body page title \u2014 a page is named ONCE: by the breadcrumb (staticData.title), by PageBar.title, or by <PageTitle> on a shell-less surface (a route error, an auth gate, a standalone screen). Every section/card/table title is a WidgetHeader (docs/CONTROLS-SPEC.md law C8). An <Title order={1|2}> spelling a name out in the body is a second name for the same page, and it drifts. A Title rendering a VALUE \u2014 {doc.title}, {RANK_LABEL[rank]} \u2014 never reports: that is data, not a name. Prose / ArticleLayout / an overlay and anything under a content/ path never report either. Same law the oxlint plugin enforces as basalt/in-body-page-title \u2014 one id, two lanes, so one theme-allow covers both."
|
|
872
887
|
},
|
|
873
888
|
"raw-selection-control": {
|
|
874
889
|
kind: "raw-selection-control",
|
|
@@ -876,7 +891,7 @@ const GUARD_RULES = {
|
|
|
876
891
|
// handled inline (full-text tag-scoped scan + host window)
|
|
877
892
|
// JSX-tag-shaped (`<Select …>`) — never appears in CSS text.
|
|
878
893
|
appliesTo: (relPath) => !relPath.endsWith(".css"),
|
|
879
|
-
message: "Raw selection control with no home \u2014 a filter or tab belongs in a PageBar / Section / WidgetHeader slot and takes a `field` (a FieldHandle), so it owns the URL write and the localStorage mirror instead of carrying value/onChange (docs/CONTROLS-SPEC.md laws C1\u2013C3). Use the bound control from basalt-ui/controls. A settings row, an overlay and an @mantine/form file are the declared non-homes and never report. This is the TEXT lane of basalt/control-outside-home, which answers the same question against the real AST \u2014 where the two disagree, the plugin is right."
|
|
894
|
+
message: "Raw selection control with no home \u2014 a filter or tab belongs in a PageBar / Section / WidgetHeader slot and takes a `field` (a FieldHandle), so it owns the URL write and the localStorage mirror instead of carrying value/onChange (docs/CONTROLS-SPEC.md laws C1\u2013C3). Use the bound control from basalt-ui/controls. A settings row, an overlay and an @mantine/form file are the declared non-homes and never report. No shell? PageBar needs no BasaltShell: outside one it renders in flow, sticky, with its own title \u2014 so its slots are a reachable home for a provider-only app. This is the TEXT lane of basalt/control-outside-home, which answers the same question against the real AST \u2014 where the two disagree, the plugin is right."
|
|
880
895
|
},
|
|
881
896
|
"inline-font-size": {
|
|
882
897
|
kind: "inline-font-size",
|
|
@@ -924,6 +939,9 @@ function checkSource(text, relPath, cfg) {
|
|
|
924
939
|
for (const annotation of fileScoped) {
|
|
925
940
|
for (const rule of annotation.rules) {
|
|
926
941
|
if (Object.hasOwn(GUARD_RULES, rule)) fileWaived.add(rule);
|
|
942
|
+
for (const alias of WAIVER_ID_ALIASES[rule] ?? []) {
|
|
943
|
+
if (Object.hasOwn(GUARD_RULES, alias)) fileWaived.add(alias);
|
|
944
|
+
}
|
|
927
945
|
}
|
|
928
946
|
}
|
|
929
947
|
const isAllowed = (line, kind) => fileWaived.has(kind) || annotationsCover(waivers.get(line - 1), kind);
|
|
@@ -1119,6 +1137,10 @@ function checkSource(text, relPath, cfg) {
|
|
|
1119
1137
|
for (const m of codeText.matchAll(PAGE_TITLE_TAG)) {
|
|
1120
1138
|
const order = PAGE_TITLE_ORDER_PROP.exec(m[0]);
|
|
1121
1139
|
if (order === null) continue;
|
|
1140
|
+
if (m[0].endsWith("/>")) continue;
|
|
1141
|
+
const bodyStart = (m.index ?? 0) + m[0].length;
|
|
1142
|
+
const closeAt = codeText.indexOf("</Title>", bodyStart);
|
|
1143
|
+
if (closeAt === -1 || !titleBodyNamesThePage(codeText.slice(bodyStart, closeAt))) continue;
|
|
1122
1144
|
const startLine = codeText.slice(0, m.index ?? 0).split("\n").length;
|
|
1123
1145
|
const endLine = startLine + (m[0].split("\n").length - 1);
|
|
1124
1146
|
if (isAllowedInRange(startLine, endLine, "in-body-page-title")) continue;
|
|
@@ -1212,6 +1234,7 @@ export {
|
|
|
1212
1234
|
NEUTRALIZED_ALLOW_TOKEN,
|
|
1213
1235
|
PLUGIN_RULE_IDS,
|
|
1214
1236
|
TOKENS_ONLY_DISABLED_KINDS,
|
|
1237
|
+
WAIVER_ID_ALIASES,
|
|
1215
1238
|
checkSource,
|
|
1216
1239
|
findAllowAnnotations,
|
|
1217
1240
|
guardKindRemedy,
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,15 @@ export { createBasaltTheme, baseTheme, cssVariablesResolver } from './theme/inde
|
|
|
11
11
|
export type { BasaltFontsConfig, CreateBasaltThemeOptions } from './theme/index.js';
|
|
12
12
|
export { CTL_THEME, CtlSlot } from './theme/index.js';
|
|
13
13
|
export type { CtlSlotProps } from './theme/index.js';
|
|
14
|
+
/**
|
|
15
|
+
* The ACTIVE resolved spacing off the running theme, not the frozen level-0 `SPACE`/`SPACE_STEP`
|
|
16
|
+
* snapshot on `basalt-ui/tokens`. Public because a consumer laying out ITS OWN chrome beside the
|
|
17
|
+
* shell's (a sticky sub-header under the app header, a fixed rail beside the navbar) has to hit the
|
|
18
|
+
* same rhythm the shell resolved, and every one of those numbers is JS-consumed — an AppShell
|
|
19
|
+
* dimension or a `<Menu width={…}>` — so there is no `--vx-*` var to read it from instead. See
|
|
20
|
+
* `theme/use-basalt-spacing.ts` for the level-0 fallback contract.
|
|
21
|
+
*/
|
|
22
|
+
export { useBasaltSpacing } from './theme/index.js';
|
|
14
23
|
export { ThemeToggle, type ThemeToggleProps } from './theme/theme-toggle.js';
|
|
15
24
|
/**
|
|
16
25
|
* The action vocabulary every home's `actions` slot takes (`docs/CONTROLS-SPEC.md` §2.1). The
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from "./common/index.js";
|
|
10
10
|
import { createBasaltTheme, baseTheme, cssVariablesResolver } from "./theme/index.js";
|
|
11
11
|
import { CTL_THEME, CtlSlot } from "./theme/index.js";
|
|
12
|
+
import { useBasaltSpacing } from "./theme/index.js";
|
|
12
13
|
import { ThemeToggle } from "./theme/theme-toggle.js";
|
|
13
14
|
import {
|
|
14
15
|
ActionGroup
|
|
@@ -148,6 +149,7 @@ export {
|
|
|
148
149
|
toErrorMessage,
|
|
149
150
|
unwrap,
|
|
150
151
|
useAgentThreadRuns,
|
|
152
|
+
useBasaltSpacing,
|
|
151
153
|
useBreakpoint,
|
|
152
154
|
useConnectivity
|
|
153
155
|
};
|
package/dist/query-client.d.ts
CHANGED
|
@@ -42,6 +42,16 @@ export declare function createBasaltQueryClient(config?: QueryClientConfig): Que
|
|
|
42
42
|
* `unwrap` reference — so `api.threads.get().then(unwrap)` silently widened. A single generic
|
|
43
43
|
* signature has exactly one type to read regardless of how the reference is used.
|
|
44
44
|
*
|
|
45
|
+
* **The conditional infers the raw `data` type and strips `null`/`undefined` from it**, rather
|
|
46
|
+
* than inferring the already-narrowed `Envelope<TData>`'s `TData` directly — Eden Treaty's
|
|
47
|
+
* response type is a UNION of envelope shapes (`{ data: T; error: null } | { data: null; error:
|
|
48
|
+
* EdenFetchError }`), and inferring through `Envelope<infer TData>` reads `TData` off whichever
|
|
49
|
+
* union member the conditional happens to match, landing on `T | null` at every Eden call site. A
|
|
50
|
+
* conditional type distributes over a union input when the checked type is a bare type parameter,
|
|
51
|
+
* so inferring `D` from `{ data: infer D; error: unknown }` and wrapping the result in
|
|
52
|
+
* `NonNullable` runs the check per union member and unions the results back together —
|
|
53
|
+
* `NonNullable<T> | NonNullable<null>` collapses to `T`.
|
|
54
|
+
*
|
|
45
55
|
* @example
|
|
46
56
|
* import { unwrap } from 'basalt-ui'
|
|
47
57
|
*
|
|
@@ -61,7 +71,15 @@ type Envelope<TData = unknown> = {
|
|
|
61
71
|
error: unknown;
|
|
62
72
|
};
|
|
63
73
|
/** `unwrap`'s conditional return: a `Promise<TData>` when `R` is a promised envelope, `TData` when
|
|
64
|
-
* it is an already-resolved one — inferred off the SAME `R` the overload used to split on
|
|
65
|
-
|
|
74
|
+
* it is an already-resolved one — inferred off the SAME `R` the overload used to split on, and
|
|
75
|
+
* distributing over a union `R` (see the JSDoc above) so an Eden Treaty response's null branch
|
|
76
|
+
* never leaks into the resolved type. */
|
|
77
|
+
type UnwrapResult<R> = R extends Promise<{
|
|
78
|
+
data: infer TData;
|
|
79
|
+
error: unknown;
|
|
80
|
+
}> ? Promise<NonNullable<TData>> : R extends {
|
|
81
|
+
data: infer TData;
|
|
82
|
+
error: unknown;
|
|
83
|
+
} ? NonNullable<TData> : never;
|
|
66
84
|
export {};
|
|
67
85
|
//# sourceMappingURL=query-client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query-client.d.ts","sourceRoot":"","sources":["../src/query-client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACnD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AAW9D;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,CAAC,EAAE,iBAAiB,GAAG,WAAW,CAQ/E;AAID
|
|
1
|
+
{"version":3,"file":"query-client.d.ts","sourceRoot":"","sources":["../src/query-client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACnD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AAW9D;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,CAAC,EAAE,iBAAiB,GAAG,WAAW,CAQ/E;AAID;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,YAAY,CAAC,CAAC,CAAC,CAK3F;AAED,iGAAiG;AACjG,KAAK,QAAQ,CAAC,KAAK,GAAG,OAAO,IAAI;IAAE,IAAI,EAAE,KAAK,GAAG,IAAI,GAAG,SAAS,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAA;AAEnF;;;yCAGyC;AACzC,KAAK,YAAY,CAAC,CAAC,IACjB,CAAC,SAAS,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,KAAK,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC,GACpD,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,GAC3B,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,KAAK,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAC7C,WAAW,CAAC,KAAK,CAAC,GAClB,KAAK,CAAA"}
|
|
@@ -10,7 +10,11 @@
|
|
|
10
10
|
* state and lands its trailing edge exactly on the sidebar|main seam. The negative
|
|
11
11
|
* `margin-inline-start` cancels `AppShell.Header`'s own `px` inset so the zone starts at the
|
|
12
12
|
* viewport edge and re-applies that inset as padding — which is what puts the brand lead on the
|
|
13
|
-
* same x as the sidebar
|
|
13
|
+
* same x as the sidebar's nav ICON column below it. The arithmetic, now that the page gutter is
|
|
14
|
+
* `SPACE.appShellInset`: the zone re-applies `--app-shell-padding` = 20, and a nav icon sits at
|
|
15
|
+
* 10px of `.root` frame inset plus 10px of NavLink inset (`rowInsetX`) = 20. One vertical line
|
|
16
|
+
* across the seam — a claim this comment used to make while the gutter was 13, and that the
|
|
17
|
+
* 13 -> 20 move made true.
|
|
14
18
|
*/
|
|
15
19
|
.zone {
|
|
16
20
|
flex: 0 0 var(--app-shell-navbar-offset, 0rem);
|
|
@@ -58,11 +62,16 @@
|
|
|
58
62
|
}
|
|
59
63
|
|
|
60
64
|
/* Workspace switcher (`brand.menu`) — the brand name plus a chevron, as a row-shaped trigger. The
|
|
61
|
-
* chevron is faint until hover so the brand still reads as the brand, not as a control.
|
|
65
|
+
* chevron is faint until hover so the brand still reads as the brand, not as a control.
|
|
66
|
+
*
|
|
67
|
+
* `control-gap`, not the `sidebar-section-label-gap` this used to borrow: it is a HORIZONTAL
|
|
68
|
+
* name-to-glyph gap inside one control, and it has nothing to do with a sidebar label's vertical
|
|
69
|
+
* proximity pair — which is exactly why it moved when that token was retuned for an unrelated
|
|
70
|
+
* reason. Same 6px, correct by meaning. */
|
|
62
71
|
.brandButton {
|
|
63
72
|
display: flex;
|
|
64
73
|
align-items: center;
|
|
65
|
-
gap: var(--vx-space-
|
|
74
|
+
gap: var(--vx-space-control-gap);
|
|
66
75
|
min-width: 0;
|
|
67
76
|
padding: 0;
|
|
68
77
|
color: var(--vx-faint);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* App-shell top bar layout. ONE
|
|
1
|
+
/* App-shell top bar layout. ONE 44px row on every viewport, spanning the FULL viewport width —
|
|
2
2
|
* [brand | collapse] [breadcrumb] ········ [page bar row 1] | [global actions].
|
|
3
3
|
*
|
|
4
4
|
* The leading zone is `app-brand.module.css`'s `.zone`: exactly `--app-shell-navbar-offset` wide,
|
|
@@ -36,17 +36,48 @@
|
|
|
36
36
|
* overflows towards its START, so the sync button painted 30px INTO the page title. Measured in
|
|
37
37
|
* Chrome: the title spanned 119.7–197.1 and the sync button 158.3–188.3.
|
|
38
38
|
*
|
|
39
|
-
* So the lead is now the elastic side (`flex: 1 1 auto`,
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
39
|
+
* So the lead is now the elastic side (`flex: 1 1 auto`, each crumb truncating via its own
|
|
40
|
+
* `truncate` prop) and the control side is rigid. A row of buttons that genuinely does not fit is
|
|
41
|
+
* not a shrinking problem — it is the OVERFLOW FOLD's problem, and basalt already owns that (law
|
|
42
|
+
* C7: below `sm` row 1 is the primary plus ONE kebab).
|
|
43
|
+
*
|
|
44
|
+
* `min-width` is a FLOOR, not the `0` it used to be: elastic still, but never elastic to nothing.
|
|
45
|
+
* With `0` the breadcrumb was the row's entire shock absorber and it absorbed itself out of
|
|
46
|
+
* existence — and then the row overflowed anyway, because `.pageBar` and `.global` below are both
|
|
47
|
+
* rigid. Measured on /dashboard at exactly 768px (the `sm` breakpoint, where the navbar appears):
|
|
48
|
+
* 768 − 256 navbar = 512px of header left, against ~554px of row 1 + ~102px of globals + ~48px of
|
|
49
|
+
* gaps ≈ 704px. ~192px over, with the page title already at zero — so the fold bought nothing and
|
|
50
|
+
* cost the reader the one word saying where they are.
|
|
51
|
+
*
|
|
52
|
+
* 96px, because the current crumb is `VX.text.lg` (16px) at `font-stretch: 88%`, i.e. ~7px of
|
|
53
|
+
* average advance: 96px is ~13 characters ("Study progress") before the crumb's own `truncate`
|
|
54
|
+
* starts eliding, and a short title ("Dashboard", "Settings") fits with room to spare. Below that
|
|
55
|
+
* the crumb is an ellipsis with a letter in front of it, which is the state this floor exists to
|
|
56
|
+
* forbid.
|
|
57
|
+
*
|
|
58
|
+
* It reads a TOKEN (`SPACE_STEP.appShellHeaderLeadMin`) rather than the raw `96px` it shipped as,
|
|
59
|
+
* because the derivation above is entirely in units that move with density — the crumb's type size
|
|
60
|
+
* and its average advance — so a frozen floor would buy ~13 characters at level 0 and fewer at
|
|
61
|
+
* every level up. The rem fallback is the level-0 number, for a stylesheet loaded before the
|
|
62
|
+
* provider's.
|
|
63
|
+
*
|
|
64
|
+
* Unscoped by width on purpose — it costs nothing on a phone. At 390px the row is the breadcrumb
|
|
65
|
+
* plus ~66px of mobile bar, ~66px of globals and ~26px of gaps inside a 374px content box, so the
|
|
66
|
+
* floor is never the binding constraint there.
|
|
67
|
+
*
|
|
68
|
+
* The floor is NOT free above `sm`: on its own it adds its own 96px to that ~192px overflow. The
|
|
69
|
+
* `md` label fold in `controls/actions.tsx` (`BarEntry`, same 62em tier) is what pays for it —
|
|
70
|
+
* dropping up to `DESKTOP_SECONDARY_MAX` (3) labelled secondaries to `ctl`-tier icon buttons returns
|
|
71
|
+
* roughly 180-240px on that same row. The two are one change; neither is correct alone, and
|
|
72
|
+
* NEITHER is the real answer, which is measuring the row (a ResizeObserver fold) rather than
|
|
73
|
+
* declaring breakpoints for it. This pair is the cheap, declared interim until that exists.
|
|
43
74
|
*/
|
|
44
75
|
.lead {
|
|
45
76
|
display: flex;
|
|
46
77
|
align-items: center;
|
|
47
78
|
gap: var(--mantine-spacing-sm);
|
|
48
79
|
flex: 1 1 auto;
|
|
49
|
-
min-width:
|
|
80
|
+
min-width: var(--vx-space-app-shell-header-lead-min, 96px);
|
|
50
81
|
}
|
|
51
82
|
|
|
52
83
|
/* No `overflow: hidden` here or on `.lead` above: Mantine's focus ring is `outline: 2px solid;
|
|
@@ -81,7 +112,8 @@
|
|
|
81
112
|
}
|
|
82
113
|
|
|
83
114
|
/*
|
|
84
|
-
* The shell globals sit at the SAME
|
|
115
|
+
* The shell globals sit at the SAME 32px `ctl` tier as everything else in the row, and they get there
|
|
116
|
+
* the
|
|
85
117
|
* same way a home's slot does — `HeaderGlobalActions` wraps this region in a `CtlSlot`, so a
|
|
86
118
|
* consumer's bare `<ActionIcon>` in `globalActions` defaults to `size="ctl"` with no prop at the call
|
|
87
119
|
* site (law C5). They rendered at Mantine's `md` 28px before, which is 2px under the page group
|
|
@@ -98,9 +130,17 @@
|
|
|
98
130
|
flex-shrink: 0;
|
|
99
131
|
}
|
|
100
132
|
|
|
133
|
+
/* Glyph BOX, 1.125rem — the SAME decoration-class fixed size `page-bar.module.css` sets on row 1's
|
|
134
|
+
* own glyphs, and deliberately NOT a `--vx-space-*` token (an icon is not a gap; the shipped icon
|
|
135
|
+
* set draws on a 24px grid and the box is a fraction of the type size, not of the spacing scale).
|
|
136
|
+
* Do not re-litigate these in a token sweep.
|
|
137
|
+
* 1.125rem rather than the old 1rem for the same reason the page bar's grew — `controlHeightCtl`
|
|
138
|
+
* went 30 -> 32, and a glyph held at 16px inside a 32px control reads EMPTIER, not bigger. The two
|
|
139
|
+
* rows are ONE control family (`HeaderGlobalActions` and `PageBar` row 1 sit in the same 44px
|
|
140
|
+
* band), so they had to stop disagreeing by 2px on the same glyph. */
|
|
101
141
|
.global :global(.mantine-ActionIcon-root) > svg {
|
|
102
|
-
width:
|
|
103
|
-
height:
|
|
142
|
+
width: 1.125rem;
|
|
143
|
+
height: 1.125rem;
|
|
104
144
|
}
|
|
105
145
|
|
|
106
146
|
/*
|
|
@@ -89,7 +89,23 @@
|
|
|
89
89
|
margin-bottom: calc(var(--app-shell-footer-offset, 0rem) + env(safe-area-inset-bottom, 0px));
|
|
90
90
|
margin-inline-start: var(--app-shell-navbar-offset, 0rem);
|
|
91
91
|
margin-inline-end: var(--app-shell-aside-offset, 0rem);
|
|
92
|
-
|
|
92
|
+
/*
|
|
93
|
+
* The scrollport's own inset, SPLIT by axis — a gap under a divider is not a gutter beside a
|
|
94
|
+
* seam.
|
|
95
|
+
*
|
|
96
|
+
* Inline stays on `--app-shell-padding`, the one Mantine var this module still reads for a
|
|
97
|
+
* value rather than an offset, because Mantine owns the responsive switch (`shell/index.tsx`
|
|
98
|
+
* hands `AppShell` the `appShellInset`/`appShellInsetMobile` pair) and the header, the band and
|
|
99
|
+
* Main all have to land on the SAME number — re-deriving it here would fork it. It is an
|
|
100
|
+
* ALIGNMENT constraint: 20 at `sm`+ puts the page's first column on the sidebar nav icon
|
|
101
|
+
* column's x across the seam (`app-brand.module.css` states that arithmetic).
|
|
102
|
+
*
|
|
103
|
+
* Block is `stack-md` and is only breathing room under the band's single `--vx-divider` line —
|
|
104
|
+
* nothing aligns to it, so it has no business tracking a gutter that grew for an alignment
|
|
105
|
+
* reason. Holding it at 12 keeps the total chrome above the first card at ~97px (44 header + 40
|
|
106
|
+
* band + 1 seam + 12) — DOWN from 100 — even though the inline gutter grew 13 -> 20.
|
|
107
|
+
*/
|
|
108
|
+
padding: var(--vx-space-stack-md) var(--app-shell-padding);
|
|
93
109
|
/* Without this a wide flex/grid child (a bare table, a nowrap control row) sizes Main to ITSELF. */
|
|
94
110
|
min-width: 0;
|
|
95
111
|
overflow-y: auto;
|
|
@@ -107,9 +123,13 @@
|
|
|
107
123
|
}
|
|
108
124
|
|
|
109
125
|
/* Installed PWA (C5 consolidation, seeded from argo's `styles/native.css`): clear the landscape
|
|
110
|
-
* notch on the side Main touches. `max()` is a FLOOR over `.main`'s
|
|
111
|
-
* — same mechanism as `app-sidebar.module.css`'s left counterpart
|
|
112
|
-
*
|
|
126
|
+
* notch on the side Main touches. `max()` is a FLOOR over the INLINE value of `.main`'s `padding`
|
|
127
|
+
* shorthand above — same mechanism as `app-sidebar.module.css`'s left counterpart, and it still
|
|
128
|
+
* floors correctly now that the shorthand is two axes and the inline one is responsive: this rule
|
|
129
|
+
* reads the same `--app-shell-padding`, so the floor is against whichever of 20/8 is live, and on
|
|
130
|
+
* the phone half (8) it is doing MORE work than before, not less. It overrides only
|
|
131
|
+
* `padding-right`; the block padding keeps coming from the shorthand. The bottom inset already
|
|
132
|
+
* rides `margin-bottom` above (`env(safe-area-inset-bottom)`); the PWA's top inset needs no rule here
|
|
113
133
|
* (the status bar uses the opaque `default` style, per argo's own seed comment). */
|
|
114
134
|
@media (display-mode: standalone) {
|
|
115
135
|
.main {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-mobile-nav.d.ts","sourceRoot":"","sources":["../../src/shell/app-mobile-nav.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"app-mobile-nav.d.ts","sourceRoot":"","sources":["../../src/shell/app-mobile-nav.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAc,YAAY,EAAa,MAAM,OAAO,CAAA;AAEhE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAGlD,OAAO,KAAK,EACV,eAAe,EAEf,cAAc,EAEd,YAAY,EAKb,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAoB/C,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG;IACzC,kFAAkF;IAClF,KAAK,EAAE,cAAc,CAAA;IACrB,MAAM,CAAC,EAAE,eAAe,GAAG,SAAS,CAAA;IACpC;;wEAEoE;IACpE,OAAO,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAA;IACxC,iBAAiB,CAAC,EAAE,gBAAgB,EAAE,GAAG,SAAS,CAAA;IAClD;;;;;OAKG;IACH,MAAM,CAAC,EAAE,YAAY,EAAE,GAAG,SAAS,CAAA;CACpC,CAAA;AAwGD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,kBAAkB,GAAG,SAAS,GAAG,MAAM,CAE/E;AA6ED,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,MAAM,EACN,OAAO,EACP,iBAAiB,EACjB,MAAM,EACN,SAAS,EACT,KAAK,GACN,EAAE,cAAc,GAAG,YAAY,CA2hB/B"}
|