basalt-ui 1.34.0 → 1.35.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.
Files changed (49) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/MIGRATING.md +24 -12
  3. package/dist/cli/check-theme.d.ts.map +1 -1
  4. package/dist/cli/check-theme.js +4 -1
  5. package/dist/cli/doctor.d.ts +5 -10
  6. package/dist/cli/doctor.d.ts.map +1 -1
  7. package/dist/cli/doctor.js +4 -0
  8. package/dist/cli/index.d.ts +18 -24
  9. package/dist/cli/index.d.ts.map +1 -1
  10. package/dist/cli/index.js +10 -0
  11. package/dist/guard/index.d.ts.map +1 -1
  12. package/dist/guard/index.js +16 -6
  13. package/dist/shell/app-mobile-nav.d.ts.map +1 -1
  14. package/dist/shell/app-mobile-nav.js +19 -10
  15. package/dist/shell/app-sidebar-account.d.ts.map +1 -1
  16. package/dist/shell/app-sidebar-account.js +1 -0
  17. package/dist/shell/app-sidebar.d.ts.map +1 -1
  18. package/dist/shell/app-sidebar.js +11 -6
  19. package/dist/shell/app-sidebar.module.css +39 -0
  20. package/dist/shell/app-sidebar.module.css.d.ts +3 -0
  21. package/dist/shell/index.d.ts +12 -5
  22. package/dist/shell/index.d.ts.map +1 -1
  23. package/dist/shell/nav-types.d.ts +19 -3
  24. package/dist/shell/nav-types.d.ts.map +1 -1
  25. package/dist/shell/sidebar-block-model.d.ts +3 -3
  26. package/dist/shell/sidebar-block-model.d.ts.map +1 -1
  27. package/dist/shell/sidebar-block-model.js +6 -2
  28. package/dist/shell/sidebar-blocks.d.ts +2 -1
  29. package/dist/shell/sidebar-blocks.d.ts.map +1 -1
  30. package/dist/shell/sidebar-blocks.js +13 -5
  31. package/dist/surfaces.js +2 -2
  32. package/dist/tokens/index.js +1 -1
  33. package/llms.txt +2 -2
  34. package/package.json +1 -1
  35. package/src/cli/check-theme.ts +4 -1
  36. package/src/cli/doctor.ts +9 -10
  37. package/src/cli/index.ts +26 -24
  38. package/src/guard/index.ts +34 -18
  39. package/src/shell/app-mobile-nav.tsx +34 -15
  40. package/src/shell/app-sidebar-account.tsx +3 -0
  41. package/src/shell/app-sidebar.module.css +39 -0
  42. package/src/shell/app-sidebar.module.css.d.ts +3 -0
  43. package/src/shell/app-sidebar.tsx +13 -6
  44. package/src/shell/index.tsx +12 -5
  45. package/src/shell/nav-types.ts +19 -3
  46. package/src/shell/sidebar-block-model.ts +13 -5
  47. package/src/shell/sidebar-blocks.tsx +30 -5
  48. package/src/surfaces.ts +2 -2
  49. package/src/tokens/index.ts +1 -1
@@ -249,6 +249,21 @@
249
249
  color: var(--vx-ink);
250
250
  }
251
251
 
252
+ /* A settings entry that IS the current page (`SettingsMenuItem.current: 'page'`) — the nav row's
253
+ * active treatment (theme/nav-link.module.css): accent fill, weight 600, accent icon. */
254
+ .footerBtn[aria-current='page'],
255
+ .settingsMenuItem[aria-current='page'] {
256
+ background-color: color-mix(in srgb, var(--vx-accent) 12%, transparent);
257
+ color: var(--vx-ink);
258
+ font-weight: 600;
259
+ }
260
+
261
+ .footerBtn[aria-current='page'] > svg,
262
+ .footerBtn[aria-current='page'] .footerIconSlot > svg,
263
+ .settingsMenuItem[aria-current='page'] [data-position='left'] {
264
+ color: var(--vx-accent);
265
+ }
266
+
252
267
  .footerText {
253
268
  flex: 1;
254
269
  text-align: left;
@@ -399,6 +414,25 @@
399
414
  color: var(--vx-ink);
400
415
  }
401
416
 
417
+ /* A custom block's rail trigger (`rail: 'icon'`) — a footer-row-sized icon target. */
418
+ .blockRailTrigger {
419
+ display: flex;
420
+ align-items: center;
421
+ justify-content: center;
422
+ padding: var(--vx-space-row-inset-y) var(--vx-space-row-inset-x);
423
+ border-radius: var(--vx-radius-ctrl);
424
+ color: var(--vx-faint);
425
+ }
426
+
427
+ .blockRailTrigger:hover {
428
+ background-color: color-mix(in srgb, var(--vx-ink) 6%, transparent);
429
+ color: var(--vx-ink);
430
+ }
431
+
432
+ .blockRailPopover {
433
+ min-width: 220px;
434
+ }
435
+
402
436
  .blockIcon {
403
437
  position: relative;
404
438
  display: flex;
@@ -717,6 +751,11 @@
717
751
  display: none;
718
752
  }
719
753
 
754
+ .root[data-collapsed] .block[data-rail='icon'] {
755
+ display: flex;
756
+ justify-content: center;
757
+ }
758
+
720
759
  .root[data-collapsed] .block[data-rail='dot'] .blockHeader {
721
760
  justify-content: center;
722
761
  padding: 0;
@@ -42,5 +42,8 @@ declare const classes: {
42
42
  readonly footerLinks: string
43
43
  readonly footerIconSlot: string
44
44
  readonly footerVersion: string
45
+ readonly settingsMenuItem: string
46
+ readonly blockRailTrigger: string
47
+ readonly blockRailPopover: string
45
48
  }
46
49
  export default classes
@@ -39,10 +39,16 @@ export type SettingsMenuItem = {
39
39
  label: string;
40
40
  icon?: ReactNode;
41
41
  onClick?: (e: MouseEvent) => void;
42
- /** This entry is the current selection (e.g. the active theme radio, the open dev tool) — a
43
- * trailing check glyph renders in every form (flat footer row, gear `Menu.Item`, the mobile
44
- * More-sheet row) and the row carries `aria-current="true"`. */
42
+ /** This entry is the current one (e.g. the active theme radio, the open dev tool, the open
43
+ * settings page) — how it shows is `current`. */
45
44
  active?: boolean;
45
+ /**
46
+ * What `active` means. `'selection'` (default) is a chosen value: a trailing check glyph in every
47
+ * form (flat footer row, gear `Menu.Item`, the mobile More-sheet row) and `aria-current="true"`.
48
+ * `'page'` is a navigation destination: no check, the nav-item active style, and
49
+ * `aria-current="page"` — what a router-backed settings entry wants.
50
+ */
51
+ current?: 'selection' | 'page';
46
52
  };
47
53
  export type BasaltShellProps = BasaltProps & {
48
54
  /**
@@ -77,8 +83,9 @@ export type BasaltShellProps = BasaltProps & {
77
83
  * Because they are data, basalt owns the projections the two `ReactNode` slots could not express:
78
84
  * a `list` with a `count` becomes a dot on its icon in the collapsed rail, a `progress` block
79
85
  * becomes a ring on the settings row, and a block with `mobile: 'more'` becomes one More-sheet
80
- * row opening a nested sheet of its items. A `kind: 'custom'` block is desktop-only, exactly as
81
- * `sidebarNavExtra` was.
86
+ * row opening a nested sheet of its items. A `kind: 'custom'` block is desktop-only and hidden in the rail, exactly
87
+ * as `sidebarNavExtra` was, unless it opts in with `icon` + `label` (a rail icon opening it in a
88
+ * popover) and `mobile: 'more'` (a More row opening it in a sheet).
82
89
  */
83
90
  sidebarBlocks?: SidebarBlock[];
84
91
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/shell/index.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/shell/index.tsx"],"names":[],"mappings":"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"}
@@ -129,9 +129,10 @@ export type SidebarProgressBlock = {
129
129
  mobile?: 'more' | 'hidden';
130
130
  };
131
131
  /**
132
- * DESKTOP ONLY — arbitrary consumer content (a tree, a filter panel) that no set of rows can
133
- * express. Replaced `BasaltShellProps.sidebarNavExtra`; hidden on the collapsed rail and absent
134
- * from mobile for the same reason that prop was.
132
+ * Arbitrary consumer content (a tree, a filter panel) that no set of rows can express. Replaced
133
+ * `BasaltShellProps.sidebarNavExtra`. By default desktop-only and hidden on the collapsed rail,
134
+ * exactly as that prop was; `icon` + `label` opt it into the rail (as an icon opening the node in a
135
+ * popover) and `mobile: 'more'` into the More sheet.
135
136
  */
136
137
  export type SidebarCustomBlock = {
137
138
  kind: 'custom';
@@ -139,6 +140,21 @@ export type SidebarCustomBlock = {
139
140
  node: ReactNode;
140
141
  /** @default 'nav' */
141
142
  placement?: 'nav' | 'bottom';
143
+ /** The rail icon. Needs `label` too: an icon-only trigger must be nameable. */
144
+ icon?: ReactNode;
145
+ /** The rail icon's accessible name, the popover heading and the More row / sheet title. */
146
+ label?: string;
147
+ /**
148
+ * Collapsed-rail projection: `'icon'` swaps the node for `icon`, which opens it in a popover.
149
+ * @default 'icon' when both `icon` and `label` are set, `'hidden'` otherwise
150
+ */
151
+ rail?: 'icon' | 'hidden';
152
+ /**
153
+ * Below `sm` there is no sidebar: `'more'` makes one More row, labelled `label`, that opens the
154
+ * node in a sheet. Needs `label`.
155
+ * @default 'hidden'
156
+ */
157
+ mobile?: 'more' | 'hidden';
142
158
  };
143
159
  /**
144
160
  * A sidebar block — DECLARED DATA, never a `ReactNode` slot (law C13, `docs/CONTROLS-SPEC.md`
@@ -1 +1 @@
1
- {"version":3,"file":"nav-types.d.ts","sourceRoot":"","sources":["../../src/shell/nav-types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"nav-types.d.ts","sourceRoot":"","sources":["../../src/shell/nav-types.ts"],"names":[],"mappings":"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"}
@@ -20,10 +20,10 @@ export declare function sidebarBlockPlacement(block: SidebarBlock): 'nav' | 'bot
20
20
  /**
21
21
  * The collapsed-rail projection. A list block earns a dot only when it carries a `count` — a rail
22
22
  * icon with no number behind it is a dot that means nothing — and a progress block a ring on the
23
- * settings row. A `custom` block has no rail representation at all (arbitrary content in ~48px of
24
- * icon column), which is exactly what `sidebarNavExtra` did before it.
23
+ * settings row. A `custom` block has a rail form only when it opts in (see below), which is
24
+ * `sidebarNavExtra`'s old hidden-in-the-rail behaviour otherwise.
25
25
  */
26
- export declare function sidebarBlockRail(block: SidebarBlock): 'dot' | 'ring' | 'hidden';
26
+ export declare function sidebarBlockRail(block: SidebarBlock): 'dot' | 'ring' | 'icon' | 'hidden';
27
27
  /**
28
28
  * The mobile projection. A list is reachable from More by default — below `sm` the sidebar does
29
29
  * not render at all, so a hidden list is unreachable, not merely unshown. A progress row defaults
@@ -1 +1 @@
1
- {"version":3,"file":"sidebar-block-model.d.ts","sourceRoot":"","sources":["../../src/shell/sidebar-block-model.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE/C,gGAAgG;AAChG,eAAO,MAAM,YAAY,IAAI,CAAA;AAE7B;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,YAAY,GAAG,KAAK,GAAG,QAAQ,CAG3E;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,CAS/E;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,GAAG,QAAQ,CAIzE;AAED,gGAAgG;AAChG,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAG3F;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKlD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE3D"}
1
+ {"version":3,"file":"sidebar-block-model.d.ts","sourceRoot":"","sources":["../../src/shell/sidebar-block-model.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE/C,gGAAgG;AAChG,eAAO,MAAM,YAAY,IAAI,CAAA;AAE7B;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,YAAY,GAAG,KAAK,GAAG,QAAQ,CAG3E;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,YAAY,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,CAexF;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,GAAG,QAAQ,CAMzE;AAED,gGAAgG;AAChG,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAG3F;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKlD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE3D"}
@@ -4,13 +4,17 @@ function sidebarBlockPlacement(block) {
4
4
  return block.placement ?? "nav";
5
5
  }
6
6
  function sidebarBlockRail(block) {
7
- if (block.kind === "custom") return "hidden";
7
+ if (block.kind === "custom") {
8
+ if (block.icon === void 0 || block.label === void 0) return "hidden";
9
+ return block.rail ?? "icon";
10
+ }
8
11
  if (block.kind === "progress") return block.rail ?? "ring";
9
12
  if (block.icon === void 0 || block.count === void 0) return "hidden";
10
13
  return block.rail ?? "dot";
11
14
  }
12
15
  function sidebarBlockMobile(block) {
13
- if (block.kind === "custom") return "hidden";
16
+ if (block.kind === "custom")
17
+ return block.mobile === "more" && block.label !== void 0 ? "more" : "hidden";
14
18
  if (block.kind === "progress") return block.mobile ?? "hidden";
15
19
  return block.mobile ?? "more";
16
20
  }
@@ -26,7 +26,8 @@ export declare function SidebarProgressRing({ value, total }: {
26
26
  total: number;
27
27
  }): import("react").JSX.Element;
28
28
  /** One block, whichever kind it is. `AppSidebar` places it; this decides nothing but the paint. */
29
- export declare function SidebarBlockView({ block, }: {
29
+ export declare function SidebarBlockView({ block, collapsed, }: {
30
30
  block: SidebarListBlock | SidebarProgressBlock | SidebarCustomBlock;
31
+ collapsed?: boolean;
31
32
  }): import("react").JSX.Element;
32
33
  //# sourceMappingURL=sidebar-blocks.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sidebar-blocks.d.ts","sourceRoot":"","sources":["../../src/shell/sidebar-blocks.tsx"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAEV,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EACrB,MAAM,aAAa,CAAA;AAYpB;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,+BAgBtD;AAsBD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,OAAO,GACf,SAAS,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC,CAE7C;AAcD,iGAAiG;AACjG,wBAAgB,mBAAmB,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,+BAEvE;AAED,yFAAyF;AACzF,wBAAgB,mBAAmB,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,+BAwBrF;AA4JD,mGAAmG;AACnG,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,GACN,EAAE;IACD,KAAK,EAAE,gBAAgB,GAAG,oBAAoB,GAAG,kBAAkB,CAAA;CACpE,+BAIA"}
1
+ {"version":3,"file":"sidebar-blocks.d.ts","sourceRoot":"","sources":["../../src/shell/sidebar-blocks.tsx"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAEV,gBAAgB,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EACrB,MAAM,aAAa,CAAA;AAYpB;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,+BAgBtD;AAsBD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,OAAO,GACf,SAAS,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC,CAE7C;AAcD,iGAAiG;AACjG,wBAAgB,mBAAmB,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,+BAEvE;AAED,yFAAyF;AACzF,wBAAgB,mBAAmB,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,+BAwBrF;AAmLD,mGAAmG;AACnG,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,SAAiB,GAClB,EAAE;IACD,KAAK,EAAE,gBAAgB,GAAG,oBAAoB,GAAG,kBAAkB,CAAA;IACnE,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB,+BAIA"}
@@ -1,5 +1,5 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
- import { Collapse, NavLink, Progress, Text, UnstyledButton } from "@mantine/core";
2
+ import { Collapse, NavLink, Popover, Progress, Text, UnstyledButton } from "@mantine/core";
3
3
  import { useState } from "react";
4
4
  import { NavCountBadge } from "./nav-count-badge.js";
5
5
  import { createPersistedState } from "../state.js";
@@ -150,15 +150,23 @@ function ProgressBlock({ block }) {
150
150
  ] });
151
151
  return /* @__PURE__ */ jsx("div", { className: classes.block, "data-rail": sidebarBlockRail(block), children: block.onClick !== void 0 ? /* @__PURE__ */ jsx(UnstyledButton, { className: classes.blockProgress, onClick: block.onClick, children: inner }) : /* @__PURE__ */ jsx("div", { className: classes.blockProgress, children: inner }) });
152
152
  }
153
- function CustomBlock({ block }) {
154
- return /* @__PURE__ */ jsx("div", { className: classes.block, "data-rail": "hidden", children: block.node });
153
+ function CustomBlock({ block, collapsed }) {
154
+ const rail = sidebarBlockRail(block);
155
+ if (collapsed && rail === "icon") {
156
+ return /* @__PURE__ */ jsx("div", { className: classes.block, "data-rail": "icon", children: /* @__PURE__ */ jsxs(Popover, { position: "right-start", withArrow: false, offset: 4, withinPortal: true, zIndex: 400, children: [
157
+ /* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx(UnstyledButton, { className: classes.blockRailTrigger, "aria-label": block.label, children: /* @__PURE__ */ jsx(IconSlot, { children: block.icon }) }) }),
158
+ /* @__PURE__ */ jsx(Popover.Dropdown, { p: "xs", className: classes.blockRailPopover, children: block.node })
159
+ ] }) });
160
+ }
161
+ return /* @__PURE__ */ jsx("div", { className: classes.block, "data-rail": rail, children: block.node });
155
162
  }
156
163
  function SidebarBlockView({
157
- block
164
+ block,
165
+ collapsed = false
158
166
  }) {
159
167
  if (block.kind === "list") return /* @__PURE__ */ jsx(ListBlock, { block });
160
168
  if (block.kind === "progress") return /* @__PURE__ */ jsx(ProgressBlock, { block });
161
- return /* @__PURE__ */ jsx(CustomBlock, { block });
169
+ return /* @__PURE__ */ jsx(CustomBlock, { block, collapsed });
162
170
  }
163
171
  export {
164
172
  IconChevron,
package/dist/surfaces.js CHANGED
@@ -357,8 +357,8 @@ const SURFACES = {
357
357
  layer: "mantine-coupled",
358
358
  rule: "controls",
359
359
  skill: ["basalt-design"],
360
- // The text lane of law C1 — the plugin's `control-outside-home` seen through a 12-line host-tag
361
- // window, since a regex scan has no ancestry. Same law, same wave, same promotion.
360
+ // The text lane of law C1 — the plugin's `control-outside-home` seen through a host-tag nesting
361
+ // count, since a regex scan has no AST. Same law, same wave, same promotion.
362
362
  guardKinds: ["raw-selection-control"],
363
363
  // The control tier itself (laws C1/C3/C5/C9). `hand-rolled-filter`, `control-size-literal` and
364
364
  // `responsive-twin` all ship `error`; the two C1 placement rules are the grace entries in
@@ -557,7 +557,7 @@ function warnConsumerVxName(name) {
557
557
  if (!BASALT_VX_FAMILIES.includes(family) || warnedVxNames.has(name)) return;
558
558
  warnedVxNames.add(name);
559
559
  console.warn(
560
- `[basalt] ${name} is inside basalt's own --vx-${family} family \u2014 name your series group something basalt does not own (groupTokens('app', \u2026)). Throws from 1.35.0.`
560
+ `[basalt] ${name} is inside basalt's own --vx-${family} family \u2014 name your series group something basalt does not own (groupTokens('app', \u2026)). Throws from 1.36.0.`
561
561
  );
562
562
  }
563
563
  function seriesTokens(map, prefix = "") {
package/llms.txt CHANGED
@@ -1,4 +1,4 @@
1
- # basalt-ui v1.34.0
1
+ # basalt-ui v1.35.0
2
2
  # Opinionated framework for Mantine-based React apps — theme, app shell, visx charts, toolchain presets
3
3
  #
4
4
  # basalt-ui is an opinionated framework for Mantine-based React apps.
@@ -19,7 +19,7 @@
19
19
  # ./tokens.css subpath. Guide: docs/FRAMEWORK-FREE.md in the repo.
20
20
 
21
21
  Package: basalt-ui
22
- Version: 1.34.0
22
+ Version: 1.35.0
23
23
 
24
24
  ## basalt-ui
25
25
  Import: import { ... } from 'basalt-ui'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "basalt-ui",
3
- "version": "1.34.0",
3
+ "version": "1.35.0",
4
4
  "description": "Opinionated framework for Mantine-based React apps — theme, app shell, visx charts, toolchain presets",
5
5
  "keywords": [
6
6
  "charts",
@@ -24,6 +24,8 @@ import {
24
24
  namesShipped,
25
25
  noteRelocation,
26
26
  OXLINT_FILES,
27
+ OXLINT_NO_BIN,
28
+ oxlintBinResolves,
27
29
  packageRoot,
28
30
  parseJsonc,
29
31
  readBasaltConfig,
@@ -61,7 +63,8 @@ function astLaneNotice(cwd: string): string | null {
61
63
  const root = findRepoRoot(cwd)
62
64
  for (let dir = cwd; ; dir = dirname(dir)) {
63
65
  const lane = oxlintLaneAt(dir)
64
- if (lane === 'wired') return null
66
+ if (lane === 'wired')
67
+ return oxlintBinResolves(cwd) ? null : `ℹ basalt-ui check-theme: ${OXLINT_NO_BIN}.`
65
68
  if (lane === 'unwired' || dir === root || dirname(dir) === dir) break
66
69
  }
67
70
  const preset = readSource(packageRoot(), OXLINT_FILES.guards)
package/src/cli/doctor.ts CHANGED
@@ -17,6 +17,8 @@ import {
17
17
  findRepoRoot,
18
18
  inspectLefthookGate,
19
19
  OXLINT_FILES,
20
+ OXLINT_NO_BIN,
21
+ oxlintBinResolves,
20
22
  parseJsonc,
21
23
  readBasaltConfig,
22
24
  readIfExists,
@@ -115,20 +117,15 @@ function resolveAiMajorSkewReason(cfg: BasaltConfig): {
115
117
  * version agrees with the manifest's `basaltVersion`.
116
118
  * 3. `guard-scan`: `check-theme` would scan more than zero files, sharing `scannableFiles` so the
117
119
  * two cannot disagree. Both RESTORED in 1.30.0 after four minors gone with no MIGRATING row —
118
- * README § `doctor` carries what their absence cost (a no-op CI gate, a green guard scanning
119
- * nothing, and two basalt-WRITTEN docs describing output the CLI no longer produced).
120
+ * README § `doctor` carries what their absence cost.
120
121
  * 4. `oxlint-preset` ("rules in sync"): the consumer's `.oxlintrc.json` extends the shipped
121
- * preset AND that path resolves. `init` keeps an existing config, so the framework's whole
122
+ * preset AND that path resolves (warns when no `oxlint` bin does). `init` keeps an existing config, so the framework's whole
122
123
  * lint half can be silently off — one repo carried six real violations invisibly across five
123
124
  * minors this way.
124
125
  * 6. `ai-major-parity`: within THIS package.json, `dependencies`/`devDependencies`/
125
- * `peerDependencies` agree on the `ai` package's major. `basalt/ai-sdk-major` (the oxlint
126
- * plugin rule) already catches this per linted FILE against its nearest package.json; this
127
- * check exists for the shape a lint run cannot see — a package whose own manifest asks its
128
- * dependents for one major while it itself runs another. A detected skew is exempt-able via
129
- * `basalt.aiMajorSkewReason` (a non-empty reason string, not a bare `true`); missing or
130
- * invalid still hard-fails as if the key were absent. A declared reason when the majors
131
- * already agree warns that the exemption is stale.
126
+ * `peerDependencies` agree on the `ai` package's major — the shape `basalt/ai-sdk-major` (per
127
+ * linted FILE) cannot see. A skew is exempt-able via `basalt.aiMajorSkewReason` (a non-empty
128
+ * reason, not a bare `true`); a declared reason when the majors agree warns it is stale.
132
129
  *
133
130
  * Warning (non-fatal):
134
131
  * 5. `lefthook-preset` ("lefthook wired"): a pre-commit command runs `check-theme`, read from
@@ -267,6 +264,8 @@ export function doctor(invocationCwd: string = process.cwd(), flags: string[] =
267
264
  'oxlint refuses to start on a missing extends target (`NotFound`), so nothing is ' +
268
265
  `linted at all. Repoint it at "${correct}", where basalt-ui actually resolves.`,
269
266
  )
267
+ } else if (!oxlintBinResolves(cwd)) {
268
+ warn(`.oxlintrc.json extends the shipped preset (${entry}), but ${OXLINT_NO_BIN}`)
270
269
  } else {
271
270
  pass(`.oxlintrc.json extends the shipped basalt-ui oxlint preset (${entry})`)
272
271
  }
package/src/cli/index.ts CHANGED
@@ -238,13 +238,12 @@ export function relativePosix(fromDir: string, toPath: string): string {
238
238
  /**
239
239
  * Where `basalt-ui` actually resolves from, seen from a consumer directory.
240
240
  *
241
- * Every toolchain seam basalt seeds (`.oxlintrc.json`'s `extends`, `lefthook.yml`'s `extends`, the
242
- * CI `run:` steps) used to hardcode `./node_modules/basalt-ui` at the repo ROOT. Under bun's
243
- * isolated linker a library package that declares basalt a peer + devDependency gets
244
- * `<pkg>/node_modules/basalt-ui` and NOTHING at the root, so all three silently failed to resolve
245
- * and `bunx` fetched a second, different copy from npm instead. Resolution therefore walks
246
- * OUTWARD from the consumer dir first, then across the workspace packages — and every caller
247
- * renders its paths from the answer rather than assuming the root.
241
+ * Every seam basalt seeds (oxlint/lefthook `extends`, the CI `run:` steps) used to hardcode
242
+ * `./node_modules/basalt-ui` at the repo ROOT; under bun's isolated linker a package that declares
243
+ * basalt a peer + devDependency gets it at `<pkg>/node_modules` and NOTHING at the root, so all three
244
+ * silently failed to resolve and `bunx` fetched a second, different copy. Resolution therefore walks
245
+ * OUTWARD from the consumer dir, then across the workspace packages — and every caller renders its
246
+ * paths from the answer rather than assuming the root.
248
247
  */
249
248
  export type BasaltInstall = {
250
249
  /** Absolute path of the resolved `node_modules/basalt-ui` directory, or null when unresolvable. */
@@ -724,6 +723,17 @@ export function findRepoRoot(dir: string): string {
724
723
  }
725
724
  }
726
725
 
726
+ /** The AST lane's other half: an `oxlint` bin in `node_modules/.bin`, `dir` up to the repo root. */
727
+ export const OXLINT_NO_BIN =
728
+ 'oxlint config found but no oxlint binary — the AST lane never runs; add oxlint as a devDependency'
729
+ export function oxlintBinResolves(dir: string): boolean {
730
+ const root = findRepoRoot(dir)
731
+ for (let d = dir; ; d = dirname(d)) {
732
+ if (existsSync(resolve(d, 'node_modules/.bin/oxlint'))) return true
733
+ if (d === root || dirname(d) === d) return false
734
+ }
735
+ }
736
+
727
737
  /**
728
738
  * First path under `dir` (recursive) whose basename is `filename`, or null. Skips dependency/build
729
739
  * dirs, mirroring `walkSourceFiles`'s scoping.
@@ -1228,24 +1238,16 @@ export function writeUnit(file: ManagedFile, cwd: string, desired: string): stri
1228
1238
  * Classify a managed file against the manifest for a sync run.
1229
1239
  * - missing : the managed unit is absent on disk → recreate.
1230
1240
  * - current : on disk == desired → nothing to do.
1231
- * - unchanged: on disk matches a KNOWN-SHIPPED rendering of this template, checked three ways (any
1232
- * one is sufficient) — but != desired as-is → safe overwrite:
1233
- * 1. `sha256(current) === manifestHash` — legacy raw-hash path. An existing consumer
1234
- * manifest (written before this fix, or by a still-running older CLI) holds the RAW
1235
- * hash of what was written, not the normalized one; keep matching it directly so an
1236
- * upgrade never mass-classifies a pristine tree as drifted.
1237
- * (A pre-1.0.2 raw entry whose block was ALSO reformatted across a template change
1238
- * needs one `--force`; bounded, and deliberately not solved with a version ledger.)
1239
- * 2. `sha256(normalizeForLedger(current)) === manifestHash` — the ledger proper.
1240
- * `manifestHash` normally holds `sha256(normalizeForLedger(<bytes written at the
1241
- * last sync>))` (see `writeUnit`); normalizing `current` the same way and comparing
1242
- * survives a downstream formatter reformatting the file AND a version bump that
1243
- * changed the template's own words between the sync that wrote this manifest entry
1244
- * and the version being synced now — the argo cross-version false positive.
1241
+ * - unchanged: on disk matches a KNOWN-SHIPPED rendering of this template (any one is sufficient) —
1242
+ * but != desired as-is → safe overwrite:
1243
+ * 1. `sha256(current) === manifestHash` — legacy raw-hash path (manifests written before
1244
+ * the ledger normalized hold the RAW hash; keep matching so an upgrade never
1245
+ * mass-classifies a pristine tree as drifted).
1246
+ * 2. `sha256(normalizeForLedger(current)) === manifestHash` — the ledger proper (see
1247
+ * `writeUnit`): survives a downstream formatter AND a version bump that changed the
1248
+ * template's own words since the manifest entry was written (the argo false positive).
1245
1249
  * 3. `normalizeForLedger(current) === normalizeForLedger(desired)` — same-version
1246
- * fallback for when there is no manifest entry to compare against at all (e.g. it
1247
- * was dropped), but the on-disk bytes still match today's rendering modulo
1248
- * formatting noise.
1250
+ * fallback when no manifest entry exists at all.
1249
1251
  * - drifted : on disk matches NONE of the above (a real, word-level local edit) → skip unless
1250
1252
  * --force.
1251
1253
  */
@@ -738,8 +738,8 @@ const PROSE_CONTEXT_TAG = /<(?:Prose|ArticleLayout|Modal|Drawer)(?![\w])/
738
738
  * does not need to: both mean "a raw control here is not homeless".
739
739
  *
740
740
  * The three subtree homes are the plugin's `BASALT_HOST_TAGS`, mirrored here so one law does not
741
- * read differently in the two lanes. The plugin gates them on the tag's basalt IMPORT; a 12-line
742
- * regex window has no import graph, so this lane matches by name and accepts the missed warn on a
741
+ * read differently in the two lanes. The plugin gates them on the tag's basalt IMPORT; a regex walk
742
+ * has no import graph, so this lane matches by name and accepts the missed warn on a
743
743
  * consumer's own `PanelRow` — the same direction every approximation in this scan already leans.
744
744
  *
745
745
  * The name set is the plugin's `CONTROL_HOST_TAGS` ∪ `BASALT_HOST_TAGS`; `oxlint-plugin.test.ts` ›
@@ -749,16 +749,31 @@ const CONTROL_HOST_TAG =
749
749
  /<(?:SettingsRow|FormRow|FormGroup|Modal|Drawer|Popover\.Dropdown|Menu\.Dropdown|Composer|FilterSet|PageAside|PanelRow)(?![\w])/
750
750
 
751
751
  /**
752
- * How far ABOVE a control the host-tag window reaches, in lines.
753
- *
754
- * The text lane has no ancestry, so "inside a SettingsRow" is approximated by "a SettingsRow opens
755
- * within the last N lines". 12 covers every row shape in the five consumer repos (label +
756
- * description + the `control={` line); past that the window would start swallowing the next row's
757
- * control, which is the direction that makes the kind silent rather than noisy. The plugin rule
758
- * (`basalt/control-outside-home`) is the one that answers this exactly — this kind exists for the
759
- * PreToolUse hook lane, which sees one file's TEXT and no AST at all.
752
+ * Open and close tags of the same host names, for the ancestry walk in {@link insideHostTag}. The
753
+ * opening alternative tolerates `=>` inside props (`onChange={(v) => …}`) like
754
+ * {@link RAW_SELECTION_CONTROL_TAG} does, and a `/>` ending marks a self-closing host, which opens
755
+ * nothing.
760
756
  */
761
- const CONTROL_HOST_WINDOW_LINES = 12
757
+ const CONTROL_HOST_TAG_SCAN = new RegExp(
758
+ `<(/?)(?:${/\(\?:([^)]*)\)/.exec(CONTROL_HOST_TAG.source)?.[1] ?? ''})(?![\\w])(?:=>|[^>])*?>`,
759
+ 'g',
760
+ )
761
+
762
+ /**
763
+ * Whether `offset` sits inside a host tag — one opened before it and not yet closed. The text lane
764
+ * has no AST, but the nesting of host tags in plain JSX is countable: +1 per opening tag, −1 per
765
+ * closing one, self-closing tags neither. That is what the plugin's `control-outside-home` answers
766
+ * by walking ancestors, so a control 40 lines under its `<SettingsRow>` is as homed here as there,
767
+ * and one after the row closed is not — the cases a fixed line window got wrong in both directions.
768
+ */
769
+ function insideHostTag(codeText: string, offset: number): boolean {
770
+ let depth = 0
771
+ for (const m of codeText.slice(0, offset).matchAll(CONTROL_HOST_TAG_SCAN)) {
772
+ if (m[1] === '/') depth = Math.max(0, depth - 1)
773
+ else if (!m[0].endsWith('/>')) depth += 1
774
+ }
775
+ return depth > 0
776
+ }
762
777
 
763
778
  /**
764
779
  * A file whose BASENAME declares it is an overlay's or a form's own body — the cross-file half of
@@ -768,7 +783,7 @@ const CONTROL_HOST_WINDOW_LINES = 12
768
783
  *
769
784
  * Law C1's cross-file case is advisory by declaration (`docs/CONTROLS-SPEC.md` §6, "Honest
770
785
  * coverage"), and this kind was paying for it: a `<Select>` inside `edit-session-modal.tsx` whose
771
- * `<Modal>` is rendered by the parent route is outside BOTH the 12-line host window and any
786
+ * `<Modal>` is rendered by the parent route is outside any
772
787
  * ancestry walk, because the host tag is not in the file at all. argo carried 9 of them.
773
788
  *
774
789
  * KEBAB and PascalCase both count, because a repo picks one file-naming law and the convention has
@@ -917,12 +932,14 @@ export type GraceEntry = { since: string; promote: string; why: string }
917
932
  export const GRACE_PERIOD_KINDS: Partial<Record<GuardKind, GraceEntry>> = {
918
933
  'unknown-vx-token': {
919
934
  since: '1.34.0',
920
- promote: '1.35.0',
935
+ promote: '1.36.0',
921
936
  why:
922
937
  'New kind at 1.33.0 (consumer-loop r2 B3): obsidian lost its 44px touch floor to a removed ' +
923
938
  '`var(--vx-space-touch-target)` that nothing reported. WIDENED at 1.34.0 (image-gen r4: ' +
924
939
  '`var(--vx-surface-2)` rendered transparent, unreported) to every unemitted name inside a ' +
925
- 'basalt-owned family, so the grace restarts: warn through 1.34.x, error at 1.35.0.',
940
+ 'basalt-owned family, so the grace restarts: warn through 1.34.x, error at 1.35.0. EXTENDED one minor at 1.35.0: that ' +
941
+ 'minor ships the shell a11y fixes consumers are upgrading for, and the promotion also turns the ' +
942
+ 'seriesTokens warning into a throw — not a change to bundle into that bump. Error at 1.36.0.',
926
943
  },
927
944
  }
928
945
 
@@ -2232,7 +2249,7 @@ export const GUARD_RULES = {
2232
2249
  },
2233
2250
  'raw-selection-control': {
2234
2251
  kind: 'raw-selection-control',
2235
- pattern: RAW_SELECTION_CONTROL_TAG, // handled inline (full-text tag-scoped scan + host window)
2252
+ pattern: RAW_SELECTION_CONTROL_TAG, // handled inline (full-text tag-scoped scan + host ancestry)
2236
2253
  // JSX-tag-shaped (`<Select …>`) — never appears in CSS text.
2237
2254
  appliesTo: (relPath) => !relPath.endsWith('.css'),
2238
2255
  message:
@@ -2760,7 +2777,7 @@ export function checkSource(text: string, relPath: string, cfg: GuardConfig): Fi
2760
2777
  }
2761
2778
  }
2762
2779
 
2763
- // raw-selection-control — full-text tag scan plus the host WINDOW (see CONTROL_HOST_WINDOW_LINES).
2780
+ // raw-selection-control — full-text tag scan plus the host ancestry walk (see insideHostTag).
2764
2781
  // Three file-level exemptions mirror the plugin rule's, so the two lanes agree on the same file:
2765
2782
  // a file that DEFINES a basalt control (and imports none — see CONTROL_OWNER_DEF) cannot be told
2766
2783
  // to use one, a file importing `@mantine/form` is a form — C1's third home, whose inputs are not
@@ -2774,8 +2791,7 @@ export function checkSource(text: string, relPath: string, cfg: GuardConfig): Fi
2774
2791
  ) {
2775
2792
  for (const m of codeText.matchAll(RAW_SELECTION_CONTROL_TAG)) {
2776
2793
  const startLine = codeText.slice(0, m.index ?? 0).split('\n').length
2777
- const windowStart = Math.max(0, startLine - 1 - CONTROL_HOST_WINDOW_LINES)
2778
- if (CONTROL_HOST_TAG.test(codeLines.slice(windowStart, startLine).join('\n'))) continue
2794
+ if (insideHostTag(codeText, m.index ?? 0)) continue
2779
2795
  const endLine = startLine + (m[0].split('\n').length - 1)
2780
2796
  if (isAllowedInRange(startLine, endLine, 'raw-selection-control')) continue
2781
2797
  findings.push({