basalt-ui 1.33.0 → 1.34.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 +26 -0
- package/MIGRATING.md +108 -15
- package/README.md +3 -0
- package/agent/skills/basalt-app/SKILL.md +5 -3
- package/configs/oxlint-basalt.json +33 -0
- package/configs/oxlint-plugin.js +21 -6
- package/configs/oxlint-plugin.test.ts +98 -10
- package/configs/oxlint.json +2 -30
- package/dist/cli/check-theme.d.ts.map +1 -1
- package/dist/cli/check-theme.js +37 -36
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +3 -5
- package/dist/cli/guard-hook.d.ts.map +1 -1
- package/dist/cli/guard-hook.js +6 -34
- package/dist/cli/index.d.ts +29 -61
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +63 -19
- package/dist/cli/sync.d.ts.map +1 -1
- package/dist/cli/sync.js +7 -16
- package/dist/common/vx-families.d.ts +7 -0
- package/dist/common/vx-families.d.ts.map +1 -0
- package/dist/common/vx-families.js +32 -0
- package/dist/common/vx-family.d.ts +11 -0
- package/dist/common/vx-family.d.ts.map +1 -0
- package/dist/common/vx-family.js +12 -0
- package/dist/guard/index.d.ts +2 -2
- package/dist/guard/index.d.ts.map +1 -1
- package/dist/guard/index.js +11 -13
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -2
- package/dist/shell/app-mobile-nav.d.ts.map +1 -1
- package/dist/shell/app-mobile-nav.js +2 -1
- package/dist/shell/app-mobile-nav.module.css +12 -0
- package/dist/shell/app-sidebar.d.ts.map +1 -1
- package/dist/shell/app-sidebar.js +32 -36
- package/dist/shell/app-sidebar.module.css +6 -0
- package/dist/shell/index.d.ts +0 -1
- package/dist/shell/index.d.ts.map +1 -1
- package/dist/shell/index.js +0 -2
- package/dist/shell/nav-glyph.d.ts +14 -0
- package/dist/shell/nav-glyph.d.ts.map +1 -0
- package/dist/shell/nav-glyph.js +21 -0
- package/dist/shell/nav-types.d.ts +1 -0
- package/dist/shell/nav-types.d.ts.map +1 -1
- package/dist/shell/sidebar-search.d.ts.map +1 -1
- package/dist/shell/sidebar-search.js +1 -3
- package/dist/surfaces.d.ts +2 -2
- package/dist/surfaces.js +2 -2
- package/dist/tokens/index.d.ts +1 -1
- package/dist/tokens/index.d.ts.map +1 -1
- package/dist/tokens/index.js +17 -1
- package/dist/tokens/size-classes.d.ts +12 -0
- package/dist/tokens/size-classes.d.ts.map +1 -1
- package/dist/tokens/size-classes.js +11 -5
- package/llms.txt +4 -4
- package/package.json +1 -1
- package/src/cli/check-theme.ts +60 -37
- package/src/cli/doctor.ts +3 -5
- package/src/cli/guard-hook.ts +8 -35
- package/src/cli/index.ts +102 -91
- package/src/cli/sync.ts +7 -16
- package/src/common/vx-families.ts +36 -0
- package/src/common/vx-family.ts +22 -0
- package/src/guard/index.ts +22 -25
- package/src/index.ts +0 -2
- package/src/shell/app-mobile-nav.module.css +12 -0
- package/src/shell/app-mobile-nav.tsx +8 -1
- package/src/shell/app-sidebar.module.css +6 -0
- package/src/shell/app-sidebar.tsx +52 -50
- package/src/shell/index.tsx +0 -1
- package/src/shell/nav-glyph.tsx +38 -0
- package/src/shell/nav-types.ts +1 -0
- package/src/shell/sidebar-search.tsx +1 -5
- package/src/surfaces.ts +2 -2
- package/src/tokens/index.ts +28 -1
- package/src/tokens/size-classes.ts +18 -5
- package/dist/shell/use-breakpoint.d.ts +0 -10
- package/dist/shell/use-breakpoint.d.ts.map +0 -1
- package/dist/shell/use-breakpoint.js +0 -11
- package/src/shell/use-breakpoint.ts +0 -37
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tokens/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAYH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tokens/index.ts"],"names":[],"mappings":"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"}
|
package/dist/tokens/index.js
CHANGED
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
} from "./palette.js";
|
|
11
11
|
import { SIZE_CLASSES, sizeClassMaxEm } from "./size-classes.js";
|
|
12
12
|
import { HIT_COARSE, HIT_FINE } from "../common/hit-floor.js";
|
|
13
|
+
import { BASALT_VX_FAMILIES } from "../common/vx-families.js";
|
|
14
|
+
import { vxFamilyOf } from "../common/vx-family.js";
|
|
13
15
|
import { BP, p } from "./palette.js";
|
|
14
16
|
import { DEFAULT_DERIVE_CONFIG, deriveTokens, resolveDeriveConfig } from "./derive.js";
|
|
15
17
|
import { deriveRadius } from "./palette.js";
|
|
@@ -17,6 +19,7 @@ import { deriveSpacing } from "./palette.js";
|
|
|
17
19
|
import {
|
|
18
20
|
CONTAINER_CLASSES,
|
|
19
21
|
CONTAINER_GRID_BREAKPOINTS,
|
|
22
|
+
CONTAINER_KEYS,
|
|
20
23
|
resolveContainerClass,
|
|
21
24
|
SIZE_CLASSES as SIZE_CLASSES2
|
|
22
25
|
} from "./size-classes.js";
|
|
@@ -548,9 +551,21 @@ function frameworkDerived(data, only, legacyAliases) {
|
|
|
548
551
|
return legacyAliases ? `${canonical}
|
|
549
552
|
${frameworkDerivedAliases(data)}` : canonical;
|
|
550
553
|
}
|
|
554
|
+
const warnedVxNames = /* @__PURE__ */ new Set();
|
|
555
|
+
function warnConsumerVxName(name) {
|
|
556
|
+
const family = vxFamilyOf(name);
|
|
557
|
+
if (!BASALT_VX_FAMILIES.includes(family) || warnedVxNames.has(name)) return;
|
|
558
|
+
warnedVxNames.add(name);
|
|
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.`
|
|
561
|
+
);
|
|
562
|
+
}
|
|
551
563
|
function seriesTokens(map, prefix = "") {
|
|
552
564
|
const out = {};
|
|
553
|
-
for (const key of Object.keys(map))
|
|
565
|
+
for (const key of Object.keys(map)) {
|
|
566
|
+
if (process.env.NODE_ENV !== "production") warnConsumerVxName(`--vx-${prefix}${String(key)}`);
|
|
567
|
+
out[key] = `var(--vx-${prefix}${String(key)})`;
|
|
568
|
+
}
|
|
554
569
|
return out;
|
|
555
570
|
}
|
|
556
571
|
function defineSeries(map) {
|
|
@@ -679,6 +694,7 @@ export {
|
|
|
679
694
|
BREAKPOINTS,
|
|
680
695
|
CONTAINER_CLASSES,
|
|
681
696
|
CONTAINER_GRID_BREAKPOINTS,
|
|
697
|
+
CONTAINER_KEYS,
|
|
682
698
|
DEFAULT_DERIVE_CONFIG,
|
|
683
699
|
SIZE_CLASSES2 as SIZE_CLASSES,
|
|
684
700
|
VX,
|
|
@@ -19,6 +19,18 @@ export declare const CONTAINER_CLASSES: {
|
|
|
19
19
|
readonly wide: 800;
|
|
20
20
|
};
|
|
21
21
|
export type ContainerClass = keyof typeof CONTAINER_CLASSES;
|
|
22
|
+
/**
|
|
23
|
+
* `CONTAINER_CLASSES` as the CSS lengths `<SimpleGrid type="container">` keys take — Mantine writes
|
|
24
|
+
* each key verbatim into `@container simple-grid (min-width: <key>)`, so a theme name (`sm`) is a
|
|
25
|
+
* dead query and the key has to be a px length: `cols={{ base: 1, [CONTAINER_KEYS.regular]: 2 }}`.
|
|
26
|
+
* `micro` has no key — `base` is that class. `basalt/raw-breakpoint` judges theme names only, so a
|
|
27
|
+
* computed key is green.
|
|
28
|
+
*/
|
|
29
|
+
export declare const CONTAINER_KEYS: {
|
|
30
|
+
readonly compact: "240px";
|
|
31
|
+
readonly regular: "480px";
|
|
32
|
+
readonly wide: "800px";
|
|
33
|
+
};
|
|
22
34
|
/**
|
|
23
35
|
* `CONTAINER_CLASSES` as the five-key map `<Grid type="container" breakpoints={…}>` takes (Mantine
|
|
24
36
|
* types it `Record<MantineSize, string>`), so `Grid.Col` keys resolve onto the grid's own width:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"size-classes.d.ts","sourceRoot":"","sources":["../../src/tokens/size-classes.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,yFAAyF;AACzF,eAAO,MAAM,YAAY;;;;CAAuD,CAAA;AAEhF,2FAA2F;AAC3F,eAAO,MAAM,iBAAiB;;;;;CAA+D,CAAA;AAE7F,MAAM,MAAM,cAAc,GAAG,MAAM,OAAO,iBAAiB,CAAA;AAE3D;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B;;;;;;CAM7B,CAAA;AAEV,qGAAqG;AACrG,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,CAKhE;AAED;;;;GAIG;AACH,eAAO,MAAM,sBAAsB;;;;;;CAMzB,CAAA;AAEV,mEAAmE;AACnE,wBAAgB,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEvC;AAED,iGAAiG;AACjG,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD"}
|
|
1
|
+
{"version":3,"file":"size-classes.d.ts","sourceRoot":"","sources":["../../src/tokens/size-classes.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,yFAAyF;AACzF,eAAO,MAAM,YAAY;;;;CAAuD,CAAA;AAEhF,2FAA2F;AAC3F,eAAO,MAAM,iBAAiB;;;;;CAA+D,CAAA;AAE7F,MAAM,MAAM,cAAc,GAAG,MAAM,OAAO,iBAAiB,CAAA;AAE3D;;;;;;GAMG;AACH,eAAO,MAAM,cAAc;;;;CAIjB,CAAA;AAEV;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B;;;;;;CAM7B,CAAA;AAEV,qGAAqG;AACrG,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,CAKhE;AAED;;;;GAIG;AACH,eAAO,MAAM,sBAAsB;;;;;;CAMzB,CAAA;AAEV,mEAAmE;AACnE,wBAAgB,IAAI,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAEvC;AAED,iGAAiG;AACjG,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpD"}
|
|
@@ -1,11 +1,16 @@
|
|
|
1
1
|
const SIZE_CLASSES = { compact: 0, medium: 840, expanded: 1200 };
|
|
2
2
|
const CONTAINER_CLASSES = { micro: 0, compact: 240, regular: 480, wide: 800 };
|
|
3
|
+
const CONTAINER_KEYS = {
|
|
4
|
+
compact: `${CONTAINER_CLASSES.compact}px`,
|
|
5
|
+
regular: `${CONTAINER_CLASSES.regular}px`,
|
|
6
|
+
wide: `${CONTAINER_CLASSES.wide}px`
|
|
7
|
+
};
|
|
3
8
|
const CONTAINER_GRID_BREAKPOINTS = {
|
|
4
|
-
xs:
|
|
5
|
-
sm:
|
|
6
|
-
md:
|
|
7
|
-
lg:
|
|
8
|
-
xl:
|
|
9
|
+
xs: CONTAINER_KEYS.compact,
|
|
10
|
+
sm: CONTAINER_KEYS.regular,
|
|
11
|
+
md: CONTAINER_KEYS.wide,
|
|
12
|
+
lg: CONTAINER_KEYS.wide,
|
|
13
|
+
xl: CONTAINER_KEYS.wide
|
|
9
14
|
};
|
|
10
15
|
function resolveContainerClass(px) {
|
|
11
16
|
if (px >= CONTAINER_CLASSES.wide) return "wide";
|
|
@@ -29,6 +34,7 @@ function sizeClassMaxEm(minPx) {
|
|
|
29
34
|
export {
|
|
30
35
|
CONTAINER_CLASSES,
|
|
31
36
|
CONTAINER_GRID_BREAKPOINTS,
|
|
37
|
+
CONTAINER_KEYS,
|
|
32
38
|
SIZE_CLASSES,
|
|
33
39
|
SIZE_CLASS_BREAKPOINTS,
|
|
34
40
|
resolveContainerClass,
|
package/llms.txt
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# basalt-ui v1.
|
|
1
|
+
# basalt-ui v1.34.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,11 +19,11 @@
|
|
|
19
19
|
# ./tokens.css subpath. Guide: docs/FRAMEWORK-FREE.md in the repo.
|
|
20
20
|
|
|
21
21
|
Package: basalt-ui
|
|
22
|
-
Version: 1.
|
|
22
|
+
Version: 1.34.0
|
|
23
23
|
|
|
24
24
|
## basalt-ui
|
|
25
25
|
Import: import { ... } from 'basalt-ui'
|
|
26
|
-
Description: BasaltProvider, createBasaltTheme, BasaltShell + sidebar/mobile-nav/breadcrumbs, PageBar, PageAside, useSizeClass
|
|
26
|
+
Description: BasaltProvider, createBasaltTheme, BasaltShell + sidebar/mobile-nav/breadcrumbs, PageBar, PageAside, useSizeClass, NavCountBadge, ThemeToggle, ThreadWorkspace + thread-chat components, WidgetHeader, dashboard composites (DeltaBadge, StatCard with threshold tone, EmptyState, QueryState/LoadingState/ErrorState, SettingsSection/SettingsRow/DangerZone), ConnectivityProvider/useConnectivity/ConnectivityIndicator (auto-mounted, C1: absorbed from the dropped ./connectivity), createBasaltQueryClient/unwrap/BasaltQueryDevtools (C1: absorbed from the dropped ./query), BasaltDevDock (C5: lazy Router/Query devtools + theme lab in one dock)
|
|
27
27
|
Layer: mantine-coupled
|
|
28
28
|
Rule: basalt-mantine
|
|
29
29
|
OptionalPeers: react-markdown@^10.1.0, remark-gfm@^4.0.1, rehype-sanitize@^6.0.0, remend@1.3.0, shiki@^4.3.0, beautiful-mermaid@^1.1.0, @tanstack/react-router-devtools@^1.166.13
|
|
@@ -155,7 +155,7 @@ Layer: non-js-asset
|
|
|
155
155
|
|
|
156
156
|
## basalt-ui/configs/*
|
|
157
157
|
Asset: basalt-ui/configs/*
|
|
158
|
-
Description: Raw toolchain presets for consumer extends: oxlint.json, oxfmt.json, tsconfig.*.json, lefthook.yml, check.yml
|
|
158
|
+
Description: Raw toolchain presets for consumer extends: oxlint.json (or the guards-only oxlint-basalt.json), oxfmt.json, tsconfig.*.json, lefthook.yml, check.yml
|
|
159
159
|
Layer: non-js-asset
|
|
160
160
|
|
|
161
161
|
## basalt-ui/llms.txt
|
package/package.json
CHANGED
package/src/cli/check-theme.ts
CHANGED
|
@@ -3,31 +3,80 @@
|
|
|
3
3
|
* Imports its shared plumbing (config/project resolution) back from `./index`, and its
|
|
4
4
|
* `--audit-allows` mode from `./audit-allows`.
|
|
5
5
|
*/
|
|
6
|
-
import { readFileSync } from 'node:fs'
|
|
7
|
-
import { resolve } from 'node:path'
|
|
6
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
7
|
+
import { dirname, resolve } from 'node:path'
|
|
8
8
|
|
|
9
9
|
import {
|
|
10
10
|
checkSource,
|
|
11
|
-
DEFAULT_GUARD_CONFIG,
|
|
12
11
|
guardKindRemedy,
|
|
13
12
|
TOKENS_ONLY_DISABLED_KINDS,
|
|
14
13
|
unmatchedExemptPatterns,
|
|
15
14
|
} from '../guard'
|
|
16
|
-
import type { Finding
|
|
15
|
+
import type { Finding } from '../guard'
|
|
17
16
|
import { auditAllows } from './audit-allows'
|
|
18
17
|
import { DEFAULT_ROOTS, resolveRoots } from './config'
|
|
19
18
|
import {
|
|
19
|
+
basaltPresetEntry,
|
|
20
20
|
conflictingProfileFlags,
|
|
21
|
+
findRepoRoot,
|
|
21
22
|
declaredProfile,
|
|
22
23
|
hasBasaltKey,
|
|
24
|
+
namesShipped,
|
|
25
|
+
noteRelocation,
|
|
26
|
+
OXLINT_FILES,
|
|
27
|
+
packageRoot,
|
|
28
|
+
parseJsonc,
|
|
23
29
|
readBasaltConfig,
|
|
24
|
-
|
|
30
|
+
readIfExists,
|
|
31
|
+
readSource,
|
|
32
|
+
resolveGuardConfig,
|
|
25
33
|
resolveProjectDir,
|
|
26
34
|
scannableFiles,
|
|
27
35
|
SERIES_MODULE_HINT_RE,
|
|
28
36
|
waiverHintFor,
|
|
29
37
|
} from './index'
|
|
30
38
|
|
|
39
|
+
/**
|
|
40
|
+
* What the `.oxlintrc.json` in `dir` does for the AST lane. A plugin load alone enables no rule, so
|
|
41
|
+
* it counts only beside a `basalt/*` rule of its own; an extends counts when it is a shipped preset.
|
|
42
|
+
*/
|
|
43
|
+
function oxlintLaneAt(dir: string): 'absent' | 'wired' | 'unwired' {
|
|
44
|
+
const raw = readIfExists(resolve(dir, '.oxlintrc.json'))
|
|
45
|
+
if (raw === null) return 'absent'
|
|
46
|
+
const rc = parseJsonc(raw)
|
|
47
|
+
const ownRules = Object.keys(Object(rc?.['rules'])).some((id) => id.startsWith('basalt/'))
|
|
48
|
+
const plugin = ownRules
|
|
49
|
+
? [rc?.['jsPlugins']].flat().find((e) => namesShipped(e, OXLINT_FILES.plugin))
|
|
50
|
+
: undefined
|
|
51
|
+
const entry = basaltPresetEntry(rc?.['extends']) ?? plugin
|
|
52
|
+
return entry !== undefined && existsSync(resolve(dir, entry)) ? 'wired' : 'unwired'
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* One line when the nearest `.oxlintrc.json` up to the repo root does not wire the AST lane: the
|
|
57
|
+
* basalt/* rules — two of the 1.33.0 promotions among them — live only there, and a
|
|
58
|
+
* check-theme-only CI otherwise reads as the whole guard (emailgw r4). Doctor names the fix.
|
|
59
|
+
*/
|
|
60
|
+
function astLaneNotice(cwd: string): string | null {
|
|
61
|
+
const root = findRepoRoot(cwd)
|
|
62
|
+
for (let dir = cwd; ; dir = dirname(dir)) {
|
|
63
|
+
const lane = oxlintLaneAt(dir)
|
|
64
|
+
if (lane === 'wired') return null
|
|
65
|
+
if (lane === 'unwired' || dir === root || dirname(dir) === dir) break
|
|
66
|
+
}
|
|
67
|
+
const preset = readSource(packageRoot(), OXLINT_FILES.guards)
|
|
68
|
+
const count =
|
|
69
|
+
preset === null
|
|
70
|
+
? `every (${OXLINT_FILES.guards} unreadable, so uncounted)`
|
|
71
|
+
: String(preset.match(/"basalt\/[\w-]+":/g)?.length ?? 0)
|
|
72
|
+
return (
|
|
73
|
+
`ℹ basalt-ui check-theme: AST lane not enforced — ${count} basalt/* rule ids unguarded ` +
|
|
74
|
+
'(incl. the promoted control-outside-home, raw-breakpoint): no .oxlintrc.json up to the repo ' +
|
|
75
|
+
'root extends basalt-ui/configs/oxlint.json (or the guards-only oxlint-basalt.json). `basalt-ui ' +
|
|
76
|
+
'doctor` names the fix.'
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
|
|
31
80
|
/**
|
|
32
81
|
* Theme guard — thin FS walker over the headless `../guard` core. Reads BasaltConfig, builds a
|
|
33
82
|
* GuardConfig, walks roots, calls checkSource per file, collects Finding[], groups/reports, returns
|
|
@@ -40,19 +89,10 @@ export function checkTheme(
|
|
|
40
89
|
invocationCwd: string = process.cwd(),
|
|
41
90
|
flags: readonly string[] = [],
|
|
42
91
|
): number {
|
|
43
|
-
if (conflictingProfileFlags(flags))
|
|
44
|
-
console.error(
|
|
45
|
-
'basalt-ui check-theme: --tokens-only and --framework are alternatives — pass one.',
|
|
46
|
-
)
|
|
47
|
-
return 1
|
|
48
|
-
}
|
|
92
|
+
if (conflictingProfileFlags('check-theme', flags)) return 1
|
|
49
93
|
const project = resolveProjectDir(invocationCwd)
|
|
50
94
|
const cwd = project.dir
|
|
51
|
-
|
|
52
|
-
console.log(
|
|
53
|
-
`basalt-ui check-theme: BASALT_CWD relocated from ${project.relocatedFrom} to ${cwd}.`,
|
|
54
|
-
)
|
|
55
|
-
}
|
|
95
|
+
noteRelocation('check-theme', project)
|
|
56
96
|
const cfg = readBasaltConfig(cwd)
|
|
57
97
|
const roots = resolveRoots(cfg)
|
|
58
98
|
const profile = declaredProfile(cfg, flags)
|
|
@@ -64,27 +104,7 @@ export function checkTheme(
|
|
|
64
104
|
)
|
|
65
105
|
}
|
|
66
106
|
|
|
67
|
-
const guardCfg
|
|
68
|
-
spacingSteps: cfg.spacingSteps ?? DEFAULT_GUARD_CONFIG.spacingSteps,
|
|
69
|
-
rawRadius: cfg.rawRadius ?? DEFAULT_GUARD_CONFIG.rawRadius,
|
|
70
|
-
forbiddenAccents: cfg.forbiddenAccents ?? DEFAULT_GUARD_CONFIG.forbiddenAccents,
|
|
71
|
-
mantineShadeIndex: cfg.mantineShadeIndex ?? DEFAULT_GUARD_CONFIG.mantineShadeIndex,
|
|
72
|
-
rawSurface: cfg.rawSurface ?? DEFAULT_GUARD_CONFIG.rawSurface,
|
|
73
|
-
cardWithBorder: cfg.cardWithBorder ?? DEFAULT_GUARD_CONFIG.cardWithBorder,
|
|
74
|
-
offSystemSurfaceVar: cfg.offSystemSurfaceVar ?? DEFAULT_GUARD_CONFIG.offSystemSurfaceVar,
|
|
75
|
-
rawHtmlLayout: cfg.rawHtmlLayout ?? DEFAULT_GUARD_CONFIG.rawHtmlLayout,
|
|
76
|
-
inlineSpacing: cfg.inlineSpacing ?? DEFAULT_GUARD_CONFIG.inlineSpacing,
|
|
77
|
-
inlineDisplay: cfg.inlineDisplay ?? DEFAULT_GUARD_CONFIG.inlineDisplay,
|
|
78
|
-
rawVisxAxis: cfg.rawVisxAxis ?? DEFAULT_GUARD_CONFIG.rawVisxAxis,
|
|
79
|
-
rawMotionValue: cfg.rawMotionValue ?? DEFAULT_GUARD_CONFIG.rawMotionValue,
|
|
80
|
-
chartMissingAriaLabel: cfg.chartMissingAriaLabel ?? DEFAULT_GUARD_CONFIG.chartMissingAriaLabel,
|
|
81
|
-
rawFormControl: cfg.rawFormControl ?? DEFAULT_GUARD_CONFIG.rawFormControl,
|
|
82
|
-
sub16InputFont: cfg.sub16InputFont ?? DEFAULT_GUARD_CONFIG.sub16InputFont,
|
|
83
|
-
allowComment: 'theme-allow',
|
|
84
|
-
exemptRules: resolveExemptRules(cfg),
|
|
85
|
-
severity: cfg.severity ?? DEFAULT_GUARD_CONFIG.severity,
|
|
86
|
-
...(profile === 'tokens-only' ? { profile: 'tokens-only' as const } : {}),
|
|
87
|
-
}
|
|
107
|
+
const guardCfg = resolveGuardConfig(cfg, profile)
|
|
88
108
|
|
|
89
109
|
const findings: Finding[] = []
|
|
90
110
|
const scanned = scannableFiles(cwd, cfg)
|
|
@@ -142,6 +162,9 @@ export function checkTheme(
|
|
|
142
162
|
)
|
|
143
163
|
}
|
|
144
164
|
|
|
165
|
+
const notice = profile === 'tokens-only' ? null : astLaneNotice(cwd)
|
|
166
|
+
if (notice !== null) console.error(notice)
|
|
167
|
+
|
|
145
168
|
if (findings.length === 0) {
|
|
146
169
|
console.log('✓ Theme guard: no off-palette colors.')
|
|
147
170
|
return 0
|
package/src/cli/doctor.ts
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
findBasaltInstall,
|
|
17
17
|
findRepoRoot,
|
|
18
18
|
inspectLefthookGate,
|
|
19
|
+
OXLINT_FILES,
|
|
19
20
|
parseJsonc,
|
|
20
21
|
readBasaltConfig,
|
|
21
22
|
readIfExists,
|
|
@@ -140,10 +141,7 @@ function resolveAiMajorSkewReason(cfg: BasaltConfig): {
|
|
|
140
141
|
* Returns the exit code: 0 = all good, 1 = one or more hard failures.
|
|
141
142
|
*/
|
|
142
143
|
export function doctor(invocationCwd: string = process.cwd(), flags: string[] = []): number {
|
|
143
|
-
if (conflictingProfileFlags(flags))
|
|
144
|
-
console.error('basalt-ui doctor: --tokens-only and --framework are alternatives — pass one.')
|
|
145
|
-
return 1
|
|
146
|
-
}
|
|
144
|
+
if (conflictingProfileFlags('doctor', flags)) return 1
|
|
147
145
|
const project = resolveProjectDir(invocationCwd)
|
|
148
146
|
const cwd = project.dir
|
|
149
147
|
const cfg = readBasaltConfig(cwd)
|
|
@@ -256,7 +254,7 @@ export function doctor(invocationCwd: string = process.cwd(), flags: string[] =
|
|
|
256
254
|
)
|
|
257
255
|
} else {
|
|
258
256
|
const entry = basaltPresetEntry(parsed['extends'])
|
|
259
|
-
const correct = shippedAssetPath(install, cwd,
|
|
257
|
+
const correct = shippedAssetPath(install, cwd, OXLINT_FILES.preset)
|
|
260
258
|
if (entry === null) {
|
|
261
259
|
fail(
|
|
262
260
|
'.oxlintrc.json does NOT extend the shipped preset — every basalt/* design rule is off ' +
|
package/src/cli/guard-hook.ts
CHANGED
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { isAbsolute, relative, resolve } from 'node:path'
|
|
7
7
|
|
|
8
|
-
import { DEFAULT_GUARD_CONFIG } from '../guard'
|
|
9
|
-
import type { GuardConfig } from '../guard'
|
|
10
8
|
import { evaluateGuardHook } from '../guard/guard-hook'
|
|
11
|
-
import { SKIP, declaredProfile, defaultExempt, readBasaltConfig,
|
|
9
|
+
import { SKIP, declaredProfile, defaultExempt, readBasaltConfig, resolveGuardConfig } from './index'
|
|
12
10
|
import { DEFAULT_ROOTS } from './config'
|
|
13
11
|
|
|
12
|
+
const ALLOW = '{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}\n'
|
|
13
|
+
|
|
14
14
|
/**
|
|
15
15
|
* guard-hook — PreToolUse stdin adapter.
|
|
16
16
|
*
|
|
@@ -31,9 +31,7 @@ export async function guardHook(cwd: string = process.cwd()): Promise<number> {
|
|
|
31
31
|
}
|
|
32
32
|
} catch {
|
|
33
33
|
// Unreadable stdin → allow
|
|
34
|
-
process.stdout.write(
|
|
35
|
-
'{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}\n',
|
|
36
|
-
)
|
|
34
|
+
process.stdout.write(ALLOW)
|
|
37
35
|
return 0
|
|
38
36
|
}
|
|
39
37
|
|
|
@@ -42,36 +40,13 @@ export async function guardHook(cwd: string = process.cwd()): Promise<number> {
|
|
|
42
40
|
payload = JSON.parse(raw)
|
|
43
41
|
} catch {
|
|
44
42
|
// Malformed JSON → allow (never block on a bad payload)
|
|
45
|
-
process.stdout.write(
|
|
46
|
-
'{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}\n',
|
|
47
|
-
)
|
|
43
|
+
process.stdout.write(ALLOW)
|
|
48
44
|
return 0
|
|
49
45
|
}
|
|
50
46
|
|
|
51
47
|
const cfg = readBasaltConfig(cwd)
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
rawRadius: cfg.rawRadius ?? DEFAULT_GUARD_CONFIG.rawRadius,
|
|
55
|
-
forbiddenAccents: cfg.forbiddenAccents ?? DEFAULT_GUARD_CONFIG.forbiddenAccents,
|
|
56
|
-
mantineShadeIndex: cfg.mantineShadeIndex ?? DEFAULT_GUARD_CONFIG.mantineShadeIndex,
|
|
57
|
-
rawSurface: cfg.rawSurface ?? DEFAULT_GUARD_CONFIG.rawSurface,
|
|
58
|
-
cardWithBorder: cfg.cardWithBorder ?? DEFAULT_GUARD_CONFIG.cardWithBorder,
|
|
59
|
-
offSystemSurfaceVar: cfg.offSystemSurfaceVar ?? DEFAULT_GUARD_CONFIG.offSystemSurfaceVar,
|
|
60
|
-
rawHtmlLayout: cfg.rawHtmlLayout ?? DEFAULT_GUARD_CONFIG.rawHtmlLayout,
|
|
61
|
-
inlineSpacing: cfg.inlineSpacing ?? DEFAULT_GUARD_CONFIG.inlineSpacing,
|
|
62
|
-
inlineDisplay: cfg.inlineDisplay ?? DEFAULT_GUARD_CONFIG.inlineDisplay,
|
|
63
|
-
rawVisxAxis: cfg.rawVisxAxis ?? DEFAULT_GUARD_CONFIG.rawVisxAxis,
|
|
64
|
-
rawMotionValue: cfg.rawMotionValue ?? DEFAULT_GUARD_CONFIG.rawMotionValue,
|
|
65
|
-
chartMissingAriaLabel: cfg.chartMissingAriaLabel ?? DEFAULT_GUARD_CONFIG.chartMissingAriaLabel,
|
|
66
|
-
rawFormControl: cfg.rawFormControl ?? DEFAULT_GUARD_CONFIG.rawFormControl,
|
|
67
|
-
sub16InputFont: cfg.sub16InputFont ?? DEFAULT_GUARD_CONFIG.sub16InputFont,
|
|
68
|
-
allowComment: 'theme-allow',
|
|
69
|
-
exemptRules: resolveExemptRules(cfg),
|
|
70
|
-
severity: cfg.severity ?? DEFAULT_GUARD_CONFIG.severity,
|
|
71
|
-
// Same detection check-theme uses: the hook must never block an edit over advice the app
|
|
72
|
-
// cannot take ("use @mantine/core's Select") in a repo with no Mantine.
|
|
73
|
-
...(declaredProfile(cfg, []) === 'tokens-only' ? { profile: 'tokens-only' as const } : {}),
|
|
74
|
-
}
|
|
48
|
+
// Same profile as check-theme: never block an edit over advice a no-Mantine app cannot take.
|
|
49
|
+
const guardCfg = resolveGuardConfig(cfg, declaredProfile(cfg, []))
|
|
75
50
|
|
|
76
51
|
// Honor the consumer's roots / exempt / skip config so the hook never blocks edits to exempted
|
|
77
52
|
// palette source or files outside the guarded roots (mirrors checkTheme's file-walk scoping).
|
|
@@ -101,9 +76,7 @@ export async function guardHook(cwd: string = process.cwd()): Promise<number> {
|
|
|
101
76
|
}) + '\n',
|
|
102
77
|
)
|
|
103
78
|
} else {
|
|
104
|
-
process.stdout.write(
|
|
105
|
-
'{"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"allow"}}\n',
|
|
106
|
-
)
|
|
79
|
+
process.stdout.write(ALLOW)
|
|
107
80
|
}
|
|
108
81
|
return 0
|
|
109
82
|
}
|