basalt-ui 1.40.2 → 1.41.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 +4 -2
- package/CHANGELOG.md +22 -0
- package/MIGRATING.md +40 -12
- package/README.md +1 -1
- package/agent/rules/basalt-batteries.md +1 -1
- package/agent/skills/basalt-app/SKILL.md +1 -1
- package/agent/skills/basalt-design/SKILL.md +1 -1
- package/agent/templates/DESIGN.md.tpl +1 -1
- package/configs/check.yml +1 -1
- package/configs/oxlint-plugin.js +5 -5
- package/configs/oxlint-plugin.test.ts +1 -1
- package/dist/agent/foreign.d.ts +3 -2
- package/dist/agent/foreign.d.ts.map +1 -1
- package/dist/charts/primitives/HoverOverlay.d.ts.map +1 -1
- package/dist/charts/primitives/HoverOverlay.js +2 -1
- package/dist/cli/doctor.d.ts +5 -2
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +29 -0
- package/dist/cli/index.d.ts +61 -4
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +112 -6
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +10 -0
- package/dist/cli/sync.d.ts.map +1 -1
- package/dist/cli/sync.js +18 -1
- package/dist/commands/shortcut-format.d.ts +9 -4
- package/dist/commands/shortcut-format.d.ts.map +1 -1
- package/dist/commands/shortcut-format.js +35 -5
- package/dist/content/copy-action.d.ts +1 -1
- package/dist/content/glyphs.d.ts +1 -1
- package/dist/data/virtual-list.d.ts +1 -1
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/index.js +14 -1
- package/dist/theme/segmented-control.module.css +8 -0
- package/dist/tokens/derive.d.ts.map +1 -1
- package/dist/tokens/derive.js +3 -1
- package/dist/tokens.css +1 -1
- package/llms.txt +2 -2
- package/package.json +1 -1
- package/src/agent/foreign.ts +3 -2
- package/src/charts/index.ts +2 -2
- package/src/charts/primitives/HoverOverlay.tsx +2 -1
- package/src/cli/doctor.ts +47 -4
- package/src/cli/index.ts +180 -11
- package/src/cli/init.ts +14 -0
- package/src/cli/sync.ts +24 -1
- package/src/commands/shortcut-format.ts +49 -10
- package/src/content/copy-action.tsx +1 -1
- package/src/content/glyphs.tsx +1 -1
- package/src/data/virtual-list.tsx +1 -1
- package/src/guard/index.ts +1 -1
- package/src/theme/index.ts +17 -1
- package/src/theme/segmented-control.module.css +8 -0
- package/src/tokens/derive.ts +3 -1
- /package/agent/templates/{CLAUDE-block.md.tpl → AGENTS-block.md.tpl} +0 -0
package/dist/cli/index.js
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
readFileSync,
|
|
8
8
|
rmdirSync,
|
|
9
9
|
statSync,
|
|
10
|
+
realpathSync,
|
|
10
11
|
unlinkSync,
|
|
11
12
|
writeFileSync
|
|
12
13
|
} from "node:fs";
|
|
@@ -233,6 +234,8 @@ function waiverHintFor(relPath, profile) {
|
|
|
233
234
|
const BLOCK_BEGIN_PREFIX = "<!-- basalt:begin";
|
|
234
235
|
const BLOCK_END = "<!-- basalt:end -->";
|
|
235
236
|
const MANIFEST_PATH = ".basalt/manifest.json";
|
|
237
|
+
const AGENTS_MD = "AGENTS.md";
|
|
238
|
+
const LEGACY_BLOCK_HOST = "CLAUDE.md";
|
|
236
239
|
function sha256(text) {
|
|
237
240
|
return createHash("sha256").update(text, "utf8").digest("hex");
|
|
238
241
|
}
|
|
@@ -308,6 +311,91 @@ function applyBlock(host, block) {
|
|
|
308
311
|
${block.trim()}
|
|
309
312
|
`;
|
|
310
313
|
}
|
|
314
|
+
function sameFile(a, b) {
|
|
315
|
+
try {
|
|
316
|
+
return realpathSync(a) === realpathSync(b);
|
|
317
|
+
} catch (error) {
|
|
318
|
+
if (error.code === "ENOENT") return false;
|
|
319
|
+
throw error;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
function hasManagedBlock(host) {
|
|
323
|
+
return host !== null && host.includes(BLOCK_BEGIN_PREFIX);
|
|
324
|
+
}
|
|
325
|
+
function scanBlock(host) {
|
|
326
|
+
const begin = hasManagedBlock(host);
|
|
327
|
+
if (!begin && !host.includes(BLOCK_END)) return { region: null, problem: null };
|
|
328
|
+
const bad = (problem) => ({ region: null, problem });
|
|
329
|
+
if (!begin) return bad(`\`${BLOCK_END}\` with no \`${BLOCK_BEGIN_PREFIX}\``);
|
|
330
|
+
let region;
|
|
331
|
+
try {
|
|
332
|
+
region = findBlockRegion(host);
|
|
333
|
+
} catch (error) {
|
|
334
|
+
return bad(error.message);
|
|
335
|
+
}
|
|
336
|
+
if (region === null) return bad(`\`${BLOCK_BEGIN_PREFIX}\` has no matching \`${BLOCK_END}\``);
|
|
337
|
+
if (host.indexOf(BLOCK_END) < region.start || host.indexOf(BLOCK_END, region.end) !== -1) {
|
|
338
|
+
return bad(`an extra or misplaced \`${BLOCK_END}\` outside the basalt block`);
|
|
339
|
+
}
|
|
340
|
+
return { region, problem: null };
|
|
341
|
+
}
|
|
342
|
+
function isAgentsImportLine(line) {
|
|
343
|
+
return line.trim() === `@${AGENTS_MD}`;
|
|
344
|
+
}
|
|
345
|
+
function importsAgentsMd(text) {
|
|
346
|
+
return text.split(/\r?\n/).some(isAgentsImportLine);
|
|
347
|
+
}
|
|
348
|
+
function migrateBlockToAgentsMd(cwd, manifest, opts = {}) {
|
|
349
|
+
const legacyHash = manifest.files[LEGACY_BLOCK_HOST];
|
|
350
|
+
if (legacyHash !== void 0) {
|
|
351
|
+
manifest.files[AGENTS_MD] ??= legacyHash;
|
|
352
|
+
delete manifest.files[LEGACY_BLOCK_HOST];
|
|
353
|
+
}
|
|
354
|
+
const none = { pending: false, deletedHost: false, problem: null };
|
|
355
|
+
const legacyAbs = resolve(cwd, LEGACY_BLOCK_HOST);
|
|
356
|
+
const agentsAbs = resolve(cwd, AGENTS_MD);
|
|
357
|
+
const legacy = readIfExists(legacyAbs);
|
|
358
|
+
if (legacy === null) return none;
|
|
359
|
+
try {
|
|
360
|
+
if (sameFile(legacyAbs, agentsAbs)) return none;
|
|
361
|
+
} catch (error) {
|
|
362
|
+
const why = error.code ?? error.message;
|
|
363
|
+
return { ...none, problem: `cannot tell whether ${LEGACY_BLOCK_HOST} is ${AGENTS_MD} (${why})` };
|
|
364
|
+
}
|
|
365
|
+
const legacyScan = scanBlock(legacy);
|
|
366
|
+
const { region } = legacyScan;
|
|
367
|
+
if (legacyScan.problem !== null) {
|
|
368
|
+
return { ...none, problem: `${LEGACY_BLOCK_HOST}: ${legacyScan.problem}` };
|
|
369
|
+
}
|
|
370
|
+
if (region === null) return none;
|
|
371
|
+
const agents = readIfExists(agentsAbs) ?? "";
|
|
372
|
+
const agentsScan = scanBlock(agents);
|
|
373
|
+
if (agentsScan.problem !== null)
|
|
374
|
+
return { ...none, problem: `${AGENTS_MD}: ${agentsScan.problem}` };
|
|
375
|
+
const legacyBlock = legacy.slice(region.start, region.end);
|
|
376
|
+
if (agentsScan.region !== null && normalizeForLedger(agents.slice(agentsScan.region.start, agentsScan.region.end)) !== normalizeForLedger(legacyBlock)) {
|
|
377
|
+
return {
|
|
378
|
+
...none,
|
|
379
|
+
problem: `${LEGACY_BLOCK_HOST} and ${AGENTS_MD} each carry a basalt block and they differ \u2014 delete the stale block from ${LEGACY_BLOCK_HOST} (or the one in ${AGENTS_MD}, if ${LEGACY_BLOCK_HOST}'s is the one you want kept), then re-run.`
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
const before = legacy.slice(0, region.start).trimEnd();
|
|
383
|
+
const after = legacy.slice(region.end).trimStart();
|
|
384
|
+
const remainder = before === "" || after === "" ? `${before}${after}` : `${before}
|
|
385
|
+
|
|
386
|
+
${after}`;
|
|
387
|
+
const deletedHost = remainder.split(/\r?\n/).every((l) => l.trim() === "" || isAgentsImportLine(l));
|
|
388
|
+
if (opts.dryRun === true) return { pending: true, deletedHost, problem: null };
|
|
389
|
+
if (agentsScan.region === null) writeFileEnsuringDir(agentsAbs, applyBlock(agents, legacyBlock));
|
|
390
|
+
if (deletedHost) unlinkSync(legacyAbs);
|
|
391
|
+
else writeFileSync(legacyAbs, `${remainder.trimEnd()}
|
|
392
|
+
`);
|
|
393
|
+
return { pending: true, deletedHost, problem: null };
|
|
394
|
+
}
|
|
395
|
+
function blockMigrationProblem(cwd) {
|
|
396
|
+
const { problem } = migrateBlockToAgentsMd(cwd, { version: 1, files: {} }, { dryRun: true });
|
|
397
|
+
return problem === null ? null : `${problem.replace(/\.$/, "")}. Nothing else was reconciled \u2014 resolve this by hand, then re-run.`;
|
|
398
|
+
}
|
|
311
399
|
function hasDependency(cwd, pkgName) {
|
|
312
400
|
try {
|
|
313
401
|
const pkg = JSON.parse(readFileSync(resolve(cwd, "package.json"), "utf8"));
|
|
@@ -397,15 +485,15 @@ function managedFiles(peers, placement = ROOT_PLACEMENT) {
|
|
|
397
485
|
source: `agent/skills/${name}/SKILL.md`,
|
|
398
486
|
render: (ctx) => readSource(ctx.pkgRoot, `agent/skills/${name}/SKILL.md`)
|
|
399
487
|
}));
|
|
400
|
-
const
|
|
401
|
-
dest:
|
|
488
|
+
const agentsBlock = {
|
|
489
|
+
dest: AGENTS_MD,
|
|
402
490
|
mode: "managed",
|
|
403
491
|
markers: true,
|
|
404
|
-
source: "agent/templates/
|
|
492
|
+
source: "agent/templates/AGENTS-block.md.tpl",
|
|
405
493
|
// With markers, render() returns the fully-rendered region INCLUDING its begin/end markers.
|
|
406
|
-
// The writer splices it into the consumer's host
|
|
494
|
+
// The writer splices it into the consumer's host AGENTS.md at apply time.
|
|
407
495
|
render: (ctx) => {
|
|
408
|
-
const tpl = readSource(ctx.pkgRoot, "agent/templates/
|
|
496
|
+
const tpl = readSource(ctx.pkgRoot, "agent/templates/AGENTS-block.md.tpl");
|
|
409
497
|
if (tpl === null) return null;
|
|
410
498
|
return fillTemplate(tpl, ctx.vars).trim();
|
|
411
499
|
}
|
|
@@ -498,7 +586,7 @@ pre-commit:
|
|
|
498
586
|
if (peers.hasQuery && placement.relocatedQueryClient === null) scaffolds.push(queryClient);
|
|
499
587
|
if (peers.hasRouter && peers.hasQuery) scaffolds.push(rootRoute);
|
|
500
588
|
const rootTooling = placement.isPackageRepoRoot ? [lefthook, ci] : [];
|
|
501
|
-
return [...rules, ...skills,
|
|
589
|
+
return [...rules, ...skills, agentsBlock, design, oxfmt, ...rootTooling, oxlintrc, ...scaffolds];
|
|
502
590
|
}
|
|
503
591
|
function placementNotices(cwd, placement) {
|
|
504
592
|
const out = [];
|
|
@@ -558,6 +646,14 @@ Retired but locally edited, so left in place \u2014 your agent still loads them.
|
|
|
558
646
|
` + pruned.drifted.map((dest) => ` \xB7 ${dest}`).join("\n")
|
|
559
647
|
);
|
|
560
648
|
}
|
|
649
|
+
function reportBlockMigration(migration, command) {
|
|
650
|
+
if (!migration.pending) return;
|
|
651
|
+
const tail = migration.deletedHost ? `${LEGACY_BLOCK_HOST} held nothing else and was deleted.` : `the rest of ${LEGACY_BLOCK_HOST} is yours; while it exists Claude Code loads it INSTEAD of ${AGENTS_MD} unless it imports @${AGENTS_MD} \u2014 move your content over and delete it.`;
|
|
652
|
+
console.log(
|
|
653
|
+
`
|
|
654
|
+
basalt-ui ${command}: moved the basalt block from ${LEGACY_BLOCK_HOST} to ${AGENTS_MD} \u2014 ${tail}`
|
|
655
|
+
);
|
|
656
|
+
}
|
|
561
657
|
function pruneRetiredManagedFiles(cwd, manifest, files, opts = {}) {
|
|
562
658
|
const result = { removed: [], drifted: [] };
|
|
563
659
|
for (const dest of retiredManagedDests(manifest, files)) {
|
|
@@ -944,6 +1040,8 @@ function run(argv, cwd = process.cwd()) {
|
|
|
944
1040
|
}
|
|
945
1041
|
}
|
|
946
1042
|
export {
|
|
1043
|
+
AGENTS_MD,
|
|
1044
|
+
LEGACY_BLOCK_HOST,
|
|
947
1045
|
MANIFEST_PATH,
|
|
948
1046
|
OXLINT_FILES,
|
|
949
1047
|
OXLINT_NO_BIN,
|
|
@@ -954,6 +1052,7 @@ export {
|
|
|
954
1052
|
SKIP,
|
|
955
1053
|
basaltBinCommand,
|
|
956
1054
|
basaltPresetEntry,
|
|
1055
|
+
blockMigrationProblem,
|
|
957
1056
|
checkTheme,
|
|
958
1057
|
classify,
|
|
959
1058
|
conflictingProfileFlags,
|
|
@@ -966,11 +1065,15 @@ export {
|
|
|
966
1065
|
fontsCss,
|
|
967
1066
|
guardHook,
|
|
968
1067
|
hasBasaltKey,
|
|
1068
|
+
hasManagedBlock,
|
|
1069
|
+
importsAgentsMd,
|
|
969
1070
|
init,
|
|
970
1071
|
inspectLefthookGate,
|
|
1072
|
+
isAgentsImportLine,
|
|
971
1073
|
isStringArray,
|
|
972
1074
|
managedFiles,
|
|
973
1075
|
mergeOxlintExtends,
|
|
1076
|
+
migrateBlockToAgentsMd,
|
|
974
1077
|
namesShipped,
|
|
975
1078
|
normalizeColorFunctions,
|
|
976
1079
|
normalizeForLedger,
|
|
@@ -989,6 +1092,7 @@ export {
|
|
|
989
1092
|
reconcileRoots,
|
|
990
1093
|
relativePosix,
|
|
991
1094
|
renderContext,
|
|
1095
|
+
reportBlockMigration,
|
|
992
1096
|
reportPrune,
|
|
993
1097
|
resolveGuardConfig,
|
|
994
1098
|
resolvePeerFlags,
|
|
@@ -997,6 +1101,8 @@ export {
|
|
|
997
1101
|
retiredManagedDests,
|
|
998
1102
|
rootsNotices,
|
|
999
1103
|
run,
|
|
1104
|
+
sameFile,
|
|
1105
|
+
scanBlock,
|
|
1000
1106
|
scannableFiles,
|
|
1001
1107
|
sha256,
|
|
1002
1108
|
shippedAssetPath,
|
package/dist/cli/init.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAmB,aAAa,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAmB,aAAa,EAAE,MAAM,SAAS,CAAA;AA8C7D,yGAAyG;AACzG,wBAAgB,IAAI,CAAC,GAAG,GAAE,MAAsB,EAAE,aAAa,GAAE,aAAkB,GAAG,MAAM,CAuL3F"}
|
package/dist/cli/init.js
CHANGED
|
@@ -3,9 +3,11 @@ import { resolve } from "node:path";
|
|
|
3
3
|
import { deriveSpacing } from "../tokens/index.js";
|
|
4
4
|
import {
|
|
5
5
|
MANIFEST_PATH,
|
|
6
|
+
blockMigrationProblem,
|
|
6
7
|
findBasaltInstall,
|
|
7
8
|
managedFiles,
|
|
8
9
|
mergeOxlintExtends,
|
|
10
|
+
migrateBlockToAgentsMd,
|
|
9
11
|
normalizeForLedger,
|
|
10
12
|
patchPackageJson,
|
|
11
13
|
placementNotices,
|
|
@@ -13,6 +15,7 @@ import {
|
|
|
13
15
|
readManifest,
|
|
14
16
|
reconcileRoots,
|
|
15
17
|
renderContext,
|
|
18
|
+
reportBlockMigration,
|
|
16
19
|
reportPrune,
|
|
17
20
|
resolvePeerFlags,
|
|
18
21
|
resolvePlacement,
|
|
@@ -31,6 +34,11 @@ const KEPT_FILE_COST = {
|
|
|
31
34
|
"DESIGN.md": "the design brief Claude reads is yours, not the seeded one."
|
|
32
35
|
};
|
|
33
36
|
function init(cwd = process.cwd(), scaffoldFlags = {}) {
|
|
37
|
+
const blockProblem = blockMigrationProblem(cwd);
|
|
38
|
+
if (blockProblem !== null) {
|
|
39
|
+
console.error(`\u2716 basalt-ui init: ${blockProblem}`);
|
|
40
|
+
return 1;
|
|
41
|
+
}
|
|
34
42
|
const install = findBasaltInstall(cwd);
|
|
35
43
|
if (install.dir === null) {
|
|
36
44
|
console.error(
|
|
@@ -50,6 +58,7 @@ function init(cwd = process.cwd(), scaffoldFlags = {}) {
|
|
|
50
58
|
const peers = resolvePeerFlags(cwd, scaffoldFlags);
|
|
51
59
|
const placement = resolvePlacement(cwd);
|
|
52
60
|
const files = managedFiles(peers, placement);
|
|
61
|
+
const migration = migrateBlockToAgentsMd(cwd, manifest);
|
|
53
62
|
const writtenFiles = [];
|
|
54
63
|
const keptFiles = [];
|
|
55
64
|
const missingSources = [];
|
|
@@ -79,6 +88,7 @@ function init(cwd = process.cwd(), scaffoldFlags = {}) {
|
|
|
79
88
|
`basalt-ui init: ${writtenFiles.length} written, ${keptFiles.length} kept, manifest at ${MANIFEST_PATH}`
|
|
80
89
|
);
|
|
81
90
|
reportPrune(pruned);
|
|
91
|
+
reportBlockMigration(migration, "init");
|
|
82
92
|
if (missingSources.length > 0) {
|
|
83
93
|
console.log(
|
|
84
94
|
`basalt-ui init: ${missingSources.length} shipped asset(s) not present, skipped: ${missingSources.join(", ")}`
|
package/dist/cli/sync.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/cli/sync.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/cli/sync.ts"],"names":[],"mappings":"AAmDA,gGAAgG;AAChG,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAGjE;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,mGAAmG;IACnG,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAC1B,CAAA;AAED;;;;;;;;;GASG;AACH;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAKrF;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQ5D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,IAAI,CAAC,IAAI,GAAE,WAAgB,EAAE,aAAa,GAAE,MAAsB,GAAG,MAAM,CAsN1F"}
|
package/dist/cli/sync.js
CHANGED
|
@@ -10,8 +10,12 @@ import {
|
|
|
10
10
|
diffSummary,
|
|
11
11
|
findBasaltInstall,
|
|
12
12
|
inspectLefthookGate,
|
|
13
|
+
AGENTS_MD,
|
|
14
|
+
blockMigrationProblem,
|
|
13
15
|
isStringArray,
|
|
16
|
+
LEGACY_BLOCK_HOST,
|
|
14
17
|
managedFiles,
|
|
18
|
+
migrateBlockToAgentsMd,
|
|
15
19
|
normalizeForLedger,
|
|
16
20
|
noteRelocation,
|
|
17
21
|
OXLINT_FILES,
|
|
@@ -25,6 +29,7 @@ import {
|
|
|
25
29
|
reconcileRoots,
|
|
26
30
|
relativePosix,
|
|
27
31
|
renderContext,
|
|
32
|
+
reportBlockMigration,
|
|
28
33
|
reportPrune,
|
|
29
34
|
resolvePeerFlags,
|
|
30
35
|
resolvePlacement,
|
|
@@ -72,12 +77,18 @@ function sync(opts = {}, invocationCwd = process.cwd()) {
|
|
|
72
77
|
);
|
|
73
78
|
return 1;
|
|
74
79
|
}
|
|
80
|
+
const blockProblem = blockMigrationProblem(cwd);
|
|
81
|
+
if (blockProblem !== null) {
|
|
82
|
+
console.error(`\u2716 basalt-ui sync: ${blockProblem}`);
|
|
83
|
+
return 1;
|
|
84
|
+
}
|
|
75
85
|
const rootsState = reconcileRoots(cwd, { write: opts.check !== true });
|
|
76
86
|
const ctx = renderContext(cwd);
|
|
77
87
|
const manifest = readManifest(cwd);
|
|
78
88
|
const peers = resolvePeerFlags(cwd, {});
|
|
79
89
|
const placement = resolvePlacement(cwd);
|
|
80
90
|
const files = managedFiles(peers, placement);
|
|
91
|
+
const migration = migrateBlockToAgentsMd(cwd, manifest, { dryRun: opts.check === true });
|
|
81
92
|
let updated = 0;
|
|
82
93
|
let created = 0;
|
|
83
94
|
let recreated = 0;
|
|
@@ -155,10 +166,15 @@ function sync(opts = {}, invocationCwd = process.cwd()) {
|
|
|
155
166
|
`basalt-ui sync --check: ${retired.length} retired rule/skill file(s) still present: ${retired.join(", ")} \u2014 run \`basalt-ui sync\`.`
|
|
156
167
|
);
|
|
157
168
|
}
|
|
169
|
+
if (migration.pending) {
|
|
170
|
+
console.error(
|
|
171
|
+
`basalt-ui sync --check: the basalt block is still in ${LEGACY_BLOCK_HOST} \u2014 it now lives in ${AGENTS_MD}. Run \`basalt-ui sync\` to move it.`
|
|
172
|
+
);
|
|
173
|
+
}
|
|
158
174
|
if (staleForCheck > 0) {
|
|
159
175
|
console.error(`basalt-ui sync --check: ${staleForCheck} managed file(s) out of date.`);
|
|
160
|
-
return 1;
|
|
161
176
|
}
|
|
177
|
+
if (staleForCheck > 0 || migration.pending) return 1;
|
|
162
178
|
const n = placementSkips.length;
|
|
163
179
|
const skips = n === 0 ? "" : ` (${n} permanent placement skip(s) \u2014 --verbose for detail)`;
|
|
164
180
|
console.log(`\u2713 basalt-ui sync --check: all managed files current.${skips}`);
|
|
@@ -172,6 +188,7 @@ function sync(opts = {}, invocationCwd = process.cwd()) {
|
|
|
172
188
|
`basalt-ui sync: ${updated} updated, ${created} created, ${recreated} recreated, ${skippedDrift} skipped (drift), ${pruned.removed.length} retired.`
|
|
173
189
|
);
|
|
174
190
|
reportPrune(pruned);
|
|
191
|
+
reportBlockMigration(migration, "sync");
|
|
175
192
|
if (driftLines.length > 0) {
|
|
176
193
|
console.log("Locally-edited files were skipped (run with --force to overwrite):");
|
|
177
194
|
for (const l of driftLines) console.log(l);
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* parseShortcut('Mod+S', false) // ['Ctrl', 'S']
|
|
10
10
|
*
|
|
11
11
|
* // Single display string for Spotlight description:
|
|
12
|
-
* formatShortcutDisplay('Mod+S', true) // '⌘
|
|
12
|
+
* formatShortcutDisplay('Mod+S', true) // '⌘S' on mac
|
|
13
13
|
* formatShortcutDisplay('Mod+S', false) // 'Ctrl+S' on windows
|
|
14
14
|
*/
|
|
15
15
|
/**
|
|
@@ -22,16 +22,20 @@ export declare function detectMac(): boolean;
|
|
|
22
22
|
* Convert a shortcut string to a list of Kbd-friendly tokens.
|
|
23
23
|
* 'Mod+S' → ['⌘', 'S'] (mac) or ['Ctrl', 'S'] (other).
|
|
24
24
|
* 'Shift+Mod+P' → ['⇧', '⌘', 'P'] (mac) or ['Shift', 'Ctrl', 'P'] (other).
|
|
25
|
+
* Named keys read as glyphs on mac and Title-case words elsewhere:
|
|
26
|
+
* 'Mod+Backspace' → ['⌘', '⌫'] (mac) or ['Ctrl', 'Backspace'] (other).
|
|
25
27
|
* isMac is the post-mount platform flag; defaults false on SSR / first render.
|
|
26
28
|
*
|
|
27
29
|
* @example
|
|
28
30
|
* parseShortcut('Mod+S', true) // ['⌘', 'S']
|
|
29
31
|
* parseShortcut('Shift+Mod+P', false) // ['Shift', 'Ctrl', 'P']
|
|
32
|
+
* parseShortcut('ArrowLeft', true) // ['←']
|
|
30
33
|
*/
|
|
31
34
|
export declare function parseShortcut(shortcut: string, isMac: boolean): string[];
|
|
32
35
|
/**
|
|
33
36
|
* Format a shortcut string for inline display (e.g. Spotlight action description).
|
|
34
|
-
* Returns a compact string like '⌘
|
|
37
|
+
* Returns a compact string like '⌘S' / '⌘⌫' (mac, glyphs with no separator) or 'Ctrl+S' /
|
|
38
|
+
* 'Ctrl+Backspace' (elsewhere, Title-case words joined with '+').
|
|
35
39
|
*
|
|
36
40
|
* isMac is the post-mount platform flag. Pass false on SSR / first client render.
|
|
37
41
|
*
|
|
@@ -40,9 +44,10 @@ export declare function parseShortcut(shortcut: string, isMac: boolean): string[
|
|
|
40
44
|
* always-on and produces the same tokens via parseShortcut.
|
|
41
45
|
*
|
|
42
46
|
* @example
|
|
43
|
-
* formatShortcutDisplay('Mod+S', true)
|
|
47
|
+
* formatShortcutDisplay('Mod+S', true) // '⌘S'
|
|
48
|
+
* formatShortcutDisplay('Mod+Backspace', true) // '⌘⌫'
|
|
44
49
|
* formatShortcutDisplay('Mod+S', false) // 'Ctrl+S'
|
|
45
|
-
* formatShortcutDisplay('Shift+Mod+P', true) // '
|
|
50
|
+
* formatShortcutDisplay('Shift+Mod+P', true) // '⇧⌘P'
|
|
46
51
|
*/
|
|
47
52
|
export declare function formatShortcutDisplay(shortcut: string, isMac: boolean): string;
|
|
48
53
|
//# sourceMappingURL=shortcut-format.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shortcut-format.d.ts","sourceRoot":"","sources":["../../src/commands/shortcut-format.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH;;;;GAIG;AACH,wBAAgB,SAAS,IAAI,OAAO,CAMnC;
|
|
1
|
+
{"version":3,"file":"shortcut-format.d.ts","sourceRoot":"","sources":["../../src/commands/shortcut-format.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH;;;;GAIG;AACH,wBAAgB,SAAS,IAAI,OAAO,CAMnC;AAmCD;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,CAqBxE;AAID;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAG9E"}
|
|
@@ -4,9 +4,36 @@ function detectMac() {
|
|
|
4
4
|
if (uadPlatform !== void 0) return /mac|iphone|ipad/i.test(uadPlatform);
|
|
5
5
|
return /Mac|iPhone|iPad/.test(navigator.userAgent);
|
|
6
6
|
}
|
|
7
|
+
const NAMED_KEYS = {
|
|
8
|
+
backspace: ["\u232B", "Backspace"],
|
|
9
|
+
delete: ["\u2326", "Delete"],
|
|
10
|
+
del: ["\u2326", "Delete"],
|
|
11
|
+
arrowleft: ["\u2190", "Left"],
|
|
12
|
+
arrowright: ["\u2192", "Right"],
|
|
13
|
+
arrowup: ["\u2191", "Up"],
|
|
14
|
+
arrowdown: ["\u2193", "Down"],
|
|
15
|
+
left: ["\u2190", "Left"],
|
|
16
|
+
right: ["\u2192", "Right"],
|
|
17
|
+
up: ["\u2191", "Up"],
|
|
18
|
+
down: ["\u2193", "Down"],
|
|
19
|
+
escape: ["\u238B", "Esc"],
|
|
20
|
+
esc: ["\u238B", "Esc"],
|
|
21
|
+
enter: ["\u21A9", "Enter"],
|
|
22
|
+
return: ["\u21A9", "Enter"],
|
|
23
|
+
tab: ["\u21E5", "Tab"],
|
|
24
|
+
space: ["\u2423", "Space"],
|
|
25
|
+
home: ["\u2196", "Home"],
|
|
26
|
+
end: ["\u2198", "End"],
|
|
27
|
+
pageup: ["\u21DE", "PgUp"],
|
|
28
|
+
pagedown: ["\u21DF", "PgDn"]
|
|
29
|
+
};
|
|
30
|
+
function plainKey(key) {
|
|
31
|
+
return key.length === 1 ? key.toUpperCase() : key.charAt(0).toUpperCase() + key.slice(1);
|
|
32
|
+
}
|
|
7
33
|
function parseShortcut(shortcut, isMac) {
|
|
8
34
|
return shortcut.split("+").map((key) => {
|
|
9
|
-
|
|
35
|
+
const lower = key.toLowerCase();
|
|
36
|
+
switch (lower) {
|
|
10
37
|
case "mod":
|
|
11
38
|
return isMac ? "\u2318" : "Ctrl";
|
|
12
39
|
case "shift":
|
|
@@ -16,15 +43,18 @@ function parseShortcut(shortcut, isMac) {
|
|
|
16
43
|
case "meta":
|
|
17
44
|
return isMac ? "\u2318" : "Meta";
|
|
18
45
|
case "ctrl":
|
|
19
|
-
return isMac ? "
|
|
20
|
-
default:
|
|
21
|
-
|
|
46
|
+
return isMac ? "\u2303" : "Ctrl";
|
|
47
|
+
default: {
|
|
48
|
+
const named = NAMED_KEYS[lower];
|
|
49
|
+
if (named !== void 0) return isMac ? named[0] : named[1];
|
|
50
|
+
return plainKey(key);
|
|
51
|
+
}
|
|
22
52
|
}
|
|
23
53
|
});
|
|
24
54
|
}
|
|
25
55
|
function formatShortcutDisplay(shortcut, isMac) {
|
|
26
56
|
const tokens = parseShortcut(shortcut, isMac);
|
|
27
|
-
return
|
|
57
|
+
return tokens.join(isMac ? "" : "+");
|
|
28
58
|
}
|
|
29
59
|
export {
|
|
30
60
|
detectMac,
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* The check + tooltip are the entire success signal — no notification (docs/CONTENT-SPEC.md §7).
|
|
8
8
|
* `color="teal"` resolves through the bridged Mantine family, so it stays on the token layer in
|
|
9
|
-
* both schemes (see the package
|
|
9
|
+
* both schemes (see the package MAINTAINING.md on `cssVariablesResolver`).
|
|
10
10
|
*
|
|
11
11
|
* Not part of the public surface — reach it through `CodeBlock` / `HeadingAnchor`.
|
|
12
12
|
*/
|
package/dist/content/glyphs.d.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* hand-drawn ones that drift apart.
|
|
5
5
|
*
|
|
6
6
|
* Inline SVG rather than an icon dep: the framework takes icons as `ReactNode` from the consumer
|
|
7
|
-
* (see the package
|
|
7
|
+
* (see the package MAINTAINING.md) and ships none, but these are internal chrome of a shipped component,
|
|
8
8
|
* not a consumer-facing slot. `currentColor` + `1em`-agnostic sizing keeps them steerable from CSS
|
|
9
9
|
* — the heading anchor sizes its glyph as an optical ratio of whatever step the heading lands on
|
|
10
10
|
* (docs/DESIGN-SPEC.md §3), while the code-block chrome pins a fixed 14px.
|
|
@@ -103,7 +103,7 @@ export type BasaltVirtualListHandle = {
|
|
|
103
103
|
/**
|
|
104
104
|
* The underlying `@tanstack/react-virtual` instance — the full escape hatch. Returns the RAW
|
|
105
105
|
* `@tanstack/react-virtual` `Virtualizer`, so a future major of that library reaching this shape
|
|
106
|
-
* ships here as a plain `feat:` under the no-majors doctrine (
|
|
106
|
+
* ships here as a plain `feat:` under the no-majors doctrine (root `AGENTS.md` "Commit type
|
|
107
107
|
* discipline"), not a silent break.
|
|
108
108
|
*/
|
|
109
109
|
getVirtualizer: () => Virtualizer<HTMLDivElement, Element>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/theme/index.ts"],"names":[],"mappings":"AAiEA,OAAO,KAAK,EACV,oBAAoB,EAGpB,oBAAoB,EAErB,MAAM,eAAe,CAAA;AAStB,OAAO,KAAK,EAAe,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAGpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAQlD;;;;;GAKG;AACH,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAIlD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAMvD,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAA;AAgBnE,OAAO,QAAQ,eAAe,CAAC;IAC7B,UAAU,iBAAiB;QACzB,YAAY,CAAC,EAAE,YAAY,CAAA;QAC3B,WAAW,CAAC,EAAE,iBAAiB,CAAA;QAC/B,YAAY,CAAC,EAAE,YAAY,CAAA;QAC3B,aAAa,CAAC,EAAE,WAAW,CAAA;KAC5B;CACF;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/theme/index.ts"],"names":[],"mappings":"AAiEA,OAAO,KAAK,EACV,oBAAoB,EAGpB,oBAAoB,EAErB,MAAM,eAAe,CAAA;AAStB,OAAO,KAAK,EAAe,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AAE/E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAGpD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAQlD;;;;;GAKG;AACH,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAIlD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAMvD,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAA;AAgBnE,OAAO,QAAQ,eAAe,CAAC;IAC7B,UAAU,iBAAiB;QACzB,YAAY,CAAC,EAAE,YAAY,CAAA;QAC3B,WAAW,CAAC,EAAE,iBAAiB,CAAA;QAC/B,YAAY,CAAC,EAAE,YAAY,CAAA;QAC3B,aAAa,CAAC,EAAE,WAAW,CAAA;KAC5B;CACF;AAuiCD;+EAC+E;AAC/E,eAAO,MAAM,SAAS,EAAE,oBAAuD,CAAA;AAkU/E;;8FAE8F;AAC9F,eAAO,MAAM,oBAAoB,EAAE,oBACc,CAAA;AAEjD,kEAAkE;AAClE,MAAM,MAAM,wBAAwB,GAAG;IACrC;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAA;IAE9B;;;;;;;;;;;;;;;;OAgBG;IACH,KAAK,CAAC,EAAE,iBAAiB,CAAA;IAEzB;;;;;;;;;;;;;;;;OAgBG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAC7B,CAAA;AA0BD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,CAAC,EAAE,IAAI,CAAC,oBAAoB,EAAE,aAAa,CAAC,EACrD,OAAO,CAAC,EAAE,wBAAwB,GACjC,oBAAoB,CAmCtB"}
|
package/dist/theme/index.js
CHANGED
|
@@ -156,13 +156,17 @@ const basaltVariantColorResolver = (input) => {
|
|
|
156
156
|
const isDefaultColor = input.color === void 0 || input.color === input.theme.primaryColor;
|
|
157
157
|
return isDefaultColor ? { ...resolved, hover: `color-mix(in srgb, var(--vx-ink) 6%, transparent)` } : resolved;
|
|
158
158
|
}
|
|
159
|
+
if (input.variant === "outline") {
|
|
160
|
+
return { ...resolved, color: `color-mix(in srgb, ${resolved.color} 70%, var(--vx-ink))` };
|
|
161
|
+
}
|
|
159
162
|
if (input.variant !== "light") return resolved;
|
|
160
163
|
const ink = `var(--mantine-color-${colorName}-light-color)`;
|
|
161
164
|
return {
|
|
162
165
|
...resolved,
|
|
163
166
|
background: `color-mix(in srgb, ${ink} 13%, transparent)`,
|
|
164
167
|
hover: `color-mix(in srgb, ${ink} 20%, transparent)`,
|
|
165
|
-
|
|
168
|
+
// Same pull toward ink as `outline`: the saturated tone text sat at 3.2–4.4:1 on its own tint.
|
|
169
|
+
color: `color-mix(in srgb, ${ink} 70%, var(--vx-ink))`,
|
|
166
170
|
border: "none"
|
|
167
171
|
};
|
|
168
172
|
};
|
|
@@ -1003,6 +1007,12 @@ function buildCssVariablesResolver(data) {
|
|
|
1003
1007
|
// secondary / muted text
|
|
1004
1008
|
"--mantine-color-text": `var(--vx-ink, ${INK.ink.light})`,
|
|
1005
1009
|
// primary body/heading text
|
|
1010
|
+
// Field errors: Mantine's own error red measures 1.98:1 (dark) / 4.37:1 (light). The solid status red
|
|
1011
|
+
// pulled toward ink clears AA on every text surface in both schemes.
|
|
1012
|
+
"--mantine-color-error": "color-mix(in srgb, var(--vx-bad-solid) 85%, var(--vx-ink))",
|
|
1013
|
+
// Links: Mantine reads the accent FILL shade (4.38:1 on the light page, under WCAG AA); the hover
|
|
1014
|
+
// accent is the next step darker and clears 4.5:1 on every light text surface.
|
|
1015
|
+
"--mantine-color-anchor": "var(--vx-accent-hover)",
|
|
1006
1016
|
// `--app-shell-border-color` is set by `components.AppShell.extend({ vars })` above — this
|
|
1007
1017
|
// entry was dead (an element-level declaration always beats an inherited `:root` value).
|
|
1008
1018
|
// THE strict-surface lever. Mantine components do NOT chain border/surface colors through
|
|
@@ -1031,6 +1041,9 @@ function buildCssVariablesResolver(data) {
|
|
|
1031
1041
|
"--mantine-color-default-border": "transparent",
|
|
1032
1042
|
"--mantine-color-dimmed": `var(--vx-neutral, ${NEUTRAL.neutral.dark})`,
|
|
1033
1043
|
"--mantine-color-text": `var(--vx-ink, ${INK.ink.dark})`,
|
|
1044
|
+
// Field errors: Mantine's own error red measures 1.98:1 (dark) / 4.37:1 (light). The solid status red
|
|
1045
|
+
// pulled toward ink clears AA on every text surface in both schemes.
|
|
1046
|
+
"--mantine-color-error": "color-mix(in srgb, var(--vx-bad-solid) 85%, var(--vx-ink))",
|
|
1034
1047
|
// See the light block above — `--app-shell-border-color` is set by `AppShell.extend` now.
|
|
1035
1048
|
// Dark components read `--mantine-color-dark-4` (border) raw. `buildDarkTuple` already sets
|
|
1036
1049
|
// dark-4, but to a slightly lighter step than the hairline token, so layout borders read
|
|
@@ -13,6 +13,14 @@
|
|
|
13
13
|
font-weight: 600;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
/*
|
|
17
|
+
* Inactive labels read ink2, not Mantine's gray-7 (4.0:1 on the light track): the active segment is
|
|
18
|
+
* told apart by the raised pill and weight 600, so the inactive text can stay at full AA contrast.
|
|
19
|
+
*/
|
|
20
|
+
.label:not([data-active], [data-disabled]) {
|
|
21
|
+
color: var(--vx-ink2);
|
|
22
|
+
}
|
|
23
|
+
|
|
16
24
|
/*
|
|
17
25
|
* Mantine's own `.control` ships `flex: 1` with no `min-width` override, so its initial value
|
|
18
26
|
* (`auto`) floors every option at its min-content width — a `fullWidth` track therefore still
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"derive.d.ts","sourceRoot":"","sources":["../../src/tokens/derive.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAExC,MAAM,MAAM,YAAY,GAAG;IACzB;;;;;;;;OAQG;IACH,MAAM,EAAE,MAAM,CAAA;IACd,sEAAsE;IACtE,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAA;IAC/C;kGAC8F;IAC9F,UAAU,EAAE,MAAM,CAAA;IAClB;mDAC+C;IAC/C,SAAS,EAAE,MAAM,CAAA;IACjB;;;;;;OAMG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;;;OAMG;IACH,gBAAgB,EAAE,MAAM,CAAA;CACzB,CAAA;AAED,8FAA8F;AAC9F,eAAO,MAAM,qBAAqB,EAAE,YAOnC,CAAA;AAID;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAEjF;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAEnE;AAuHD,MAAM,MAAM,UAAU,GAClB,MAAM,GACN,KAAK,GACL,MAAM,GACN,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,MAAM,GACN,MAAM,GACN,OAAO,GACP,MAAM,GACN,QAAQ,GACR,QAAQ,CAAA;AA6DZ,MAAM,MAAM,UAAU,GAClB,IAAI,GACJ,OAAO,GACP,YAAY,GACZ,UAAU,GACV,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,UAAU,CAAA;AA2Bd,MAAM,MAAM,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"derive.d.ts","sourceRoot":"","sources":["../../src/tokens/derive.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA;AAExC,MAAM,MAAM,YAAY,GAAG;IACzB;;;;;;;;OAQG;IACH,MAAM,EAAE,MAAM,CAAA;IACd,sEAAsE;IACtE,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,CAAA;IAC/C;kGAC8F;IAC9F,UAAU,EAAE,MAAM,CAAA;IAClB;mDAC+C;IAC/C,SAAS,EAAE,MAAM,CAAA;IACjB;;;;;;OAMG;IACH,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;;;OAMG;IACH,gBAAgB,EAAE,MAAM,CAAA;CACzB,CAAA;AAED,8FAA8F;AAC9F,eAAO,MAAM,qBAAqB,EAAE,YAOnC,CAAA;AAID;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,YAAY,CAEjF;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAEnE;AAuHD,MAAM,MAAM,UAAU,GAClB,MAAM,GACN,KAAK,GACL,MAAM,GACN,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,MAAM,GACN,MAAM,GACN,OAAO,GACP,MAAM,GACN,QAAQ,GACR,QAAQ,CAAA;AA6DZ,MAAM,MAAM,UAAU,GAClB,IAAI,GACJ,OAAO,GACP,YAAY,GACZ,UAAU,GACV,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,UAAU,CAAA;AA2Bd,MAAM,MAAM,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAA;AAUvD,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAA;AAS/C;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,6FAA6F;IAC7F,UAAU,EAAE,MAAM,CAAA;IAClB,0EAA0E;IAC1E,eAAe,EAAE,MAAM,CAAA;IACvB,6EAA6E;IAC7E,iBAAiB,EAAE,MAAM,CAAA;IACzB,4EAA4E;IAC5E,gBAAgB,EAAE,MAAM,CAAA;CACzB,CAAA;AAED;8BAC8B;AAC9B,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,SAAS,CAAA;IACjB,WAAW,EAAE,SAAS,CAAA;IACtB,UAAU,EAAE,SAAS,CAAA;IACrB,eAAe,EAAE,SAAS,CAAA;IAC1B,QAAQ,EAAE,SAAS,CAAA;IACnB,IAAI,EAAE,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;IACnC,OAAO,EAAE,MAAM,CAAC,UAAU,EAAE,SAAS,CAAC,CAAA;IACtC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAA;IAC9B,MAAM,EAAE,MAAM,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;CACrC,CAAA;AAED;;8DAE8D;AAC9D,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,cAAc,CAQjE;AAED,gGAAgG;AAChG,wBAAgB,eAAe,CAC7B,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,QAAQ,GAAG,SAAS,CAAC,EAChD,MAAM,EAAE,YAAY,GACnB,cAAc,CA+GhB"}
|
package/dist/tokens/derive.js
CHANGED
|
@@ -127,7 +127,9 @@ const SURFACE_TONE = {
|
|
|
127
127
|
}
|
|
128
128
|
};
|
|
129
129
|
const INK_TONE = {
|
|
130
|
-
light
|
|
130
|
+
// light `faint` is tone 44.5 so tertiary text clears WCAG AA (4.5:1) on every text surface
|
|
131
|
+
// (bg / panel / subtle / field); 48.44 landed at 4.23–4.31:1 on bg and subtle.
|
|
132
|
+
light: { ink: 15.16, ink2: 27.09, muted: 34.88, faint: 44.5 },
|
|
131
133
|
dark: { ink: 90.94, ink2: 88.12, muted: 84.91, faint: 66.24 }
|
|
132
134
|
};
|
|
133
135
|
const STATUS_HUE = { good: 151.975, warn: 76.64, bad: 29.905 };
|
package/dist/tokens.css
CHANGED
|
@@ -291,7 +291,7 @@ html[data-mantine-color-scheme='light'] {
|
|
|
291
291
|
--vx-ink: #262629;
|
|
292
292
|
--vx-ink2: #404043;
|
|
293
293
|
--vx-muted: #525255;
|
|
294
|
-
--vx-faint: #
|
|
294
|
+
--vx-faint: #69696c;
|
|
295
295
|
--vx-accent: #4374a6;
|
|
296
296
|
--vx-accent-hover: #3c6895;
|
|
297
297
|
--vx-accent-fill: #4374a6;
|
package/llms.txt
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# basalt-ui v1.
|
|
1
|
+
# basalt-ui v1.41.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.
|
|
22
|
+
Version: 1.41.0
|
|
23
23
|
|
|
24
24
|
## basalt-ui
|
|
25
25
|
Import: import { ... } from 'basalt-ui'
|
package/package.json
CHANGED
package/src/agent/foreign.ts
CHANGED
|
@@ -97,8 +97,9 @@ export type PartRenderContext<TPart = ForeignPart> = {
|
|
|
97
97
|
export type PartRenderer<TPart = ForeignPart> = (ctx: PartRenderContext<TPart>) => ReactNode
|
|
98
98
|
|
|
99
99
|
/**
|
|
100
|
-
* Canonical const-generic factory (`packages/basalt-ui/
|
|
101
|
-
*
|
|
100
|
+
* Canonical const-generic factory (`packages/basalt-ui/MAINTAINING.md` § "Token system — the
|
|
101
|
+
* derived palette", "Series color is consumer data") — identity passthrough, exact-keyed return,
|
|
102
|
+
* no builder, no config bag. Mirrors
|
|
102
103
|
* `defineSeries` (`tokens/index.ts:648-650`) and `defineNotifications`
|
|
103
104
|
* (`notifications/define-notifications.ts:112-115`).
|
|
104
105
|
*
|
package/src/charts/index.ts
CHANGED
|
@@ -166,8 +166,8 @@ export {
|
|
|
166
166
|
} from './sparklines'
|
|
167
167
|
|
|
168
168
|
// ── Re-exported visx primitives ──────────────────────────────────────────
|
|
169
|
-
// Bespoke charts (genuinely unique compositions per
|
|
170
|
-
// visx primitives. Re-exporting them keeps the dependency declared in one
|
|
169
|
+
// Bespoke charts (genuinely unique compositions, per `agent/rules/basalt-charts.md` "Adding a
|
|
170
|
+
// chart") need raw visx primitives. Re-exporting them keeps the dependency declared in one
|
|
171
171
|
// place and preserves the rule that consumers only import from `basalt-ui/charts`.
|
|
172
172
|
export { Group } from '@visx/group'
|
|
173
173
|
export { GridRows, GridColumns } from '@visx/grid'
|
|
@@ -66,7 +66,8 @@ export function HoverOverlay({
|
|
|
66
66
|
'aria-orientation': 'horizontal' as const,
|
|
67
67
|
'aria-valuemin': 0,
|
|
68
68
|
...(valueMax !== undefined && { 'aria-valuemax': valueMax }),
|
|
69
|
-
|
|
69
|
+
// `aria-valuenow` is required on a slider: 0 (the first point) until the cursor lands on one.
|
|
70
|
+
'aria-valuenow': valueNow ?? 0,
|
|
70
71
|
...(valueText !== undefined && { 'aria-valuetext': valueText }),
|
|
71
72
|
onKeyDown,
|
|
72
73
|
...(onBlur !== undefined && { onBlur }),
|