basalt-ui 1.22.0 → 1.23.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 +9 -1
- package/CHANGELOG.md +19 -0
- package/MIGRATING.md +125 -12
- package/README.md +45 -11
- package/agent/rules/basalt-app.md +26 -2
- package/agent/rules/basalt-charts.md +40 -5
- package/agent/rules/basalt-tokens.md +17 -1
- package/agent/skills/basalt-charts/SKILL.md +23 -8
- package/agent/templates/DESIGN.md.tpl +3 -1
- package/configs/oxlint-plugin.js +49 -8
- package/configs/oxlint-plugin.test.ts +88 -31
- package/dist/charts/hooks/useBandPlot.d.ts +138 -0
- package/dist/charts/hooks/useBandPlot.d.ts.map +1 -0
- package/dist/charts/hooks/useBandPlot.js +127 -0
- package/dist/charts/index.d.ts +4 -0
- package/dist/charts/index.d.ts.map +1 -1
- package/dist/charts/index.js +14 -0
- package/dist/charts/kinds/BandStrip.d.ts +113 -0
- package/dist/charts/kinds/BandStrip.d.ts.map +1 -0
- package/dist/charts/kinds/BandStrip.js +218 -0
- package/dist/charts/kinds/BandStrip.test.d.ts +2 -0
- package/dist/charts/kinds/BandStrip.test.d.ts.map +1 -0
- package/dist/charts/kinds/Bars.d.ts +5 -1
- package/dist/charts/kinds/Bars.d.ts.map +1 -1
- package/dist/charts/kinds/Bars.js +2 -0
- package/dist/charts/kinds/MirroredBars.d.ts +93 -0
- package/dist/charts/kinds/MirroredBars.d.ts.map +1 -0
- package/dist/charts/kinds/MirroredBars.js +315 -0
- package/dist/charts/kinds/MirroredBars.test.d.ts +2 -0
- package/dist/charts/kinds/MirroredBars.test.d.ts.map +1 -0
- package/dist/charts/kinds/MultiLine.d.ts +5 -1
- package/dist/charts/kinds/MultiLine.d.ts.map +1 -1
- package/dist/charts/kinds/MultiLine.js +2 -0
- package/dist/charts/kinds/StackedArea.d.ts +5 -1
- package/dist/charts/kinds/StackedArea.d.ts.map +1 -1
- package/dist/charts/kinds/StackedArea.js +2 -0
- package/dist/charts/kinds/ZonedLine.d.ts +5 -1
- package/dist/charts/kinds/ZonedLine.d.ts.map +1 -1
- package/dist/charts/kinds/ZonedLine.js +2 -0
- package/dist/charts/primitives/CartesianChart.d.ts +18 -2
- package/dist/charts/primitives/CartesianChart.d.ts.map +1 -1
- package/dist/charts/primitives/CartesianChart.js +5 -2
- package/dist/charts/primitives/HatchPattern.d.ts +31 -0
- package/dist/charts/primitives/HatchPattern.d.ts.map +1 -0
- package/dist/charts/primitives/HatchPattern.js +31 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +47 -8
- package/dist/cli/shipped-versions.test.d.ts +2 -0
- package/dist/cli/shipped-versions.test.d.ts.map +1 -0
- package/dist/guard/index.d.ts.map +1 -1
- package/dist/guard/index.js +32 -11
- package/dist/vite.d.ts +42 -3
- package/dist/vite.d.ts.map +1 -1
- package/dist/vite.js +67 -30
- package/llms.txt +2 -2
- package/package.json +1 -1
- package/src/charts/hooks/useBandPlot.ts +302 -0
- package/src/charts/index.ts +14 -0
- package/src/charts/kinds/BandStrip.test.tsx +200 -0
- package/src/charts/kinds/BandStrip.tsx +364 -0
- package/src/charts/kinds/Bars.tsx +7 -1
- package/src/charts/kinds/DualPanel.test.tsx +10 -4
- package/src/charts/kinds/MirroredBars.test.tsx +193 -0
- package/src/charts/kinds/MirroredBars.tsx +455 -0
- package/src/charts/kinds/MultiLine.tsx +7 -1
- package/src/charts/kinds/StackedArea.tsx +7 -1
- package/src/charts/kinds/ZonedLine.tsx +7 -1
- package/src/charts/primitives/CartesianChart.test.tsx +86 -4
- package/src/charts/primitives/CartesianChart.tsx +28 -3
- package/src/charts/primitives/HatchPattern.tsx +55 -0
- package/src/cli/index.ts +125 -18
- package/src/cli/shipped-versions.test.ts +83 -0
- package/src/cli/toolchain-wiring.test.ts +171 -4
- package/src/cli/waiver-audit.test.ts +7 -3
- package/src/guard/check-source.test.ts +138 -42
- package/src/guard/index.ts +83 -17
- package/src/vite.test.ts +79 -0
- package/src/vite.ts +141 -39
package/dist/cli/index.js
CHANGED
|
@@ -160,6 +160,16 @@ function hasBasaltProject(dir) {
|
|
|
160
160
|
return false;
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
|
+
function descendantProjects(cwd, depth = 2) {
|
|
164
|
+
if (depth === 0) return [];
|
|
165
|
+
const out = [];
|
|
166
|
+
for (const name of subdirNames(cwd, { skipDotDirs: true })) {
|
|
167
|
+
const dir = resolve(cwd, name);
|
|
168
|
+
if (hasBasaltProject(dir)) out.push(dir);
|
|
169
|
+
else out.push(...descendantProjects(dir, depth - 1));
|
|
170
|
+
}
|
|
171
|
+
return out;
|
|
172
|
+
}
|
|
163
173
|
function resolveProjectDir(cwd) {
|
|
164
174
|
const override = process.env["BASALT_CWD"];
|
|
165
175
|
if (override !== void 0 && override.length > 0) {
|
|
@@ -167,7 +177,8 @@ function resolveProjectDir(cwd) {
|
|
|
167
177
|
return { dir, relocatedFrom: dir === cwd ? null : cwd, ambiguous: null };
|
|
168
178
|
}
|
|
169
179
|
if (hasBasaltProject(cwd)) return { dir: cwd, relocatedFrom: null, ambiguous: null };
|
|
170
|
-
const
|
|
180
|
+
const declared = collectWorkspacePackages(cwd).packages.filter((pkg) => pkg.dir !== cwd && hasBasaltProject(pkg.dir)).map((pkg) => pkg.dir);
|
|
181
|
+
const candidates = declared.length > 0 ? declared : descendantProjects(cwd);
|
|
171
182
|
if (candidates.length === 1) {
|
|
172
183
|
return { dir: candidates[0], relocatedFrom: cwd, ambiguous: null };
|
|
173
184
|
}
|
|
@@ -239,7 +250,7 @@ function checkTheme(invocationCwd = process.cwd(), flags = []) {
|
|
|
239
250
|
const project = resolveProjectDir(invocationCwd);
|
|
240
251
|
if (project.ambiguous !== null) {
|
|
241
252
|
console.error(
|
|
242
|
-
`\u2716 basalt-ui check-theme: no basalt config at ${invocationCwd}, and ${project.ambiguous.length}
|
|
253
|
+
`\u2716 basalt-ui check-theme: no basalt config at ${invocationCwd}, and ${project.ambiguous.length} packages below it carry one (${project.ambiguous.map((d) => relativePosix(invocationCwd, d)).join(", ")}) \u2014 run it from one of them, or set BASALT_CWD to pick.`
|
|
243
254
|
);
|
|
244
255
|
return 1;
|
|
245
256
|
}
|
|
@@ -565,8 +576,9 @@ basalt.exemptRules entries (${exemptCount}):`);
|
|
|
565
576
|
`
|
|
566
577
|
${live} live, ${dead} dead, ${outOfReach} unjudgeable, ${unaccountable} unaccountable (reported as theme-allow-unscoped by a normal run).`
|
|
567
578
|
);
|
|
579
|
+
const includes = cfg.include ?? [];
|
|
568
580
|
lines.push(
|
|
569
|
-
`Scope: the ${scanned.length} file(s) check-theme scans under basalt.roots (${resolveRoots(cfg).join(", ")}). A waiver
|
|
581
|
+
`Scope: the ${scanned.length} file(s) check-theme scans \u2014 everything under basalt.roots (${resolveRoots(cfg).join(", ")}), plus each root's sibling index.html and public/ tree, ` + (includes.length === 0 ? "plus anything named in basalt.include (none). " : `plus basalt.include (${includes.join(", ")}). `) + "A waiver in a file none of those reach is not audited \u2014 widen roots, or name it in basalt.include, or accept that nothing polices that file."
|
|
570
582
|
);
|
|
571
583
|
if (dead > 0) {
|
|
572
584
|
lines.push(
|
|
@@ -860,6 +872,16 @@ function migrateLegacyOxfmt(cwd, pkgRoot, manifest) {
|
|
|
860
872
|
const shipped = readSource(pkgRoot, "configs/oxfmt.json");
|
|
861
873
|
if (shipped !== null && onDisk === shipped) unlinkSync(legacyAbs);
|
|
862
874
|
}
|
|
875
|
+
const DESIGN_VERSION_LINE = /^(> Managed by basalt-ui) \(\d+\.\d+\.\d+\)\./m;
|
|
876
|
+
function migrateDesignVersionLine(cwd) {
|
|
877
|
+
const dest = resolve(cwd, "DESIGN.md");
|
|
878
|
+
const onDisk = readIfExists(dest);
|
|
879
|
+
if (onDisk === null || !DESIGN_VERSION_LINE.test(onDisk)) return;
|
|
880
|
+
writeFileEnsuringDir(
|
|
881
|
+
dest,
|
|
882
|
+
onDisk.replace(DESIGN_VERSION_LINE, "$1 \u2014 run `basalt-ui doctor` for the version.")
|
|
883
|
+
);
|
|
884
|
+
}
|
|
863
885
|
function writeFileEnsuringDir(abs, content) {
|
|
864
886
|
mkdirSync(dirname(abs), { recursive: true });
|
|
865
887
|
writeFileSync(abs, content);
|
|
@@ -1287,10 +1309,15 @@ function findManifestAbove(dir) {
|
|
|
1287
1309
|
}
|
|
1288
1310
|
}
|
|
1289
1311
|
function sync(opts = {}, invocationCwd = process.cwd()) {
|
|
1312
|
+
const syncFlags = opts.flags ?? [];
|
|
1313
|
+
if (conflictingProfileFlags(syncFlags)) {
|
|
1314
|
+
console.error("basalt-ui sync: --tokens-only and --framework are alternatives \u2014 pass one.");
|
|
1315
|
+
return 1;
|
|
1316
|
+
}
|
|
1290
1317
|
const project = resolveProjectDir(invocationCwd);
|
|
1291
1318
|
if (project.ambiguous !== null) {
|
|
1292
1319
|
console.error(
|
|
1293
|
-
`\u2716 basalt-ui sync: no basalt config at ${invocationCwd}, and ${project.ambiguous.length}
|
|
1320
|
+
`\u2716 basalt-ui sync: no basalt config at ${invocationCwd}, and ${project.ambiguous.length} packages below it carry one (${project.ambiguous.map((d) => relativePosix(invocationCwd, d)).join(", ")}) \u2014 run it from one of them, or set BASALT_CWD to pick.`
|
|
1294
1321
|
);
|
|
1295
1322
|
return 1;
|
|
1296
1323
|
}
|
|
@@ -1300,6 +1327,12 @@ function sync(opts = {}, invocationCwd = process.cwd()) {
|
|
|
1300
1327
|
`basalt-ui sync: no basalt config at ${project.relocatedFrom} \u2014 running in ${relativePosix(project.relocatedFrom, cwd)}, where it lives.`
|
|
1301
1328
|
);
|
|
1302
1329
|
}
|
|
1330
|
+
if (declaredProfile(readBasaltConfig(cwd), syncFlags) === "tokens-only") {
|
|
1331
|
+
console.log(
|
|
1332
|
+
`basalt-ui sync: ${MANIFEST_PATH}: n/a \u2014 a tokens-only consumer has no scaffold to reconcile. The token layer is refreshed by re-running \`basalt-ui tokens:css\`, and \`tokens:css --check\` is its drift gate. Pass --framework to force the full profile.`
|
|
1333
|
+
);
|
|
1334
|
+
return 0;
|
|
1335
|
+
}
|
|
1303
1336
|
if (!existsSync(resolve(cwd, MANIFEST_PATH))) {
|
|
1304
1337
|
const elsewhere = findManifestAbove(cwd);
|
|
1305
1338
|
const wouldWrite = managedFiles(resolvePeerFlags(cwd, {}), resolvePlacement(cwd)).length;
|
|
@@ -1311,7 +1344,10 @@ function sync(opts = {}, invocationCwd = process.cwd()) {
|
|
|
1311
1344
|
const rootsState = reconcileRoots(cwd, { write: opts.check !== true });
|
|
1312
1345
|
const ctx = renderContext(cwd);
|
|
1313
1346
|
const manifest = readManifest(cwd);
|
|
1314
|
-
if (!opts.check)
|
|
1347
|
+
if (!opts.check) {
|
|
1348
|
+
migrateLegacyOxfmt(cwd, ctx.pkgRoot, manifest);
|
|
1349
|
+
migrateDesignVersionLine(cwd);
|
|
1350
|
+
}
|
|
1315
1351
|
const peers = resolvePeerFlags(cwd, {});
|
|
1316
1352
|
const placement = resolvePlacement(cwd);
|
|
1317
1353
|
const files = managedFiles(peers, placement);
|
|
@@ -1634,7 +1670,7 @@ function doctor(invocationCwd = process.cwd(), flags = []) {
|
|
|
1634
1670
|
`
|
|
1635
1671
|
basalt-ui doctor \u2014 ${invocationCwd}
|
|
1636
1672
|
|
|
1637
|
-
\u2716 no basalt config at ${invocationCwd}, and ${project.ambiguous.length}
|
|
1673
|
+
\u2716 no basalt config at ${invocationCwd}, and ${project.ambiguous.length} packages below it carry one (${project.ambiguous.map((d) => relativePosix(invocationCwd, d)).join(", ")}) \u2014 run doctor from one of them, or set BASALT_CWD to pick.
|
|
1638
1674
|
|
|
1639
1675
|
1 hard failure(s), 0 warning(s).
|
|
1640
1676
|
`
|
|
@@ -2205,7 +2241,7 @@ async function guardHook(cwd = process.cwd()) {
|
|
|
2205
2241
|
}
|
|
2206
2242
|
return 0;
|
|
2207
2243
|
}
|
|
2208
|
-
const USAGE = "Usage: basalt-ui <init [--with-router] [--with-query] [--merge-lint]
|
|
2244
|
+
const USAGE = "Usage: basalt-ui <init [--with-router] [--with-query] [--merge-lint] |\n sync [--force] [--check] [--tokens-only|--framework] |\n check-theme [--audit-allows] | check-coverage | info [--json] |\n doctor [--tokens-only|--framework] | guard-hook | tokens:css | fonts:css | help>\n\ncheck-theme [--tokens-only|--framework] [--audit-allows]\n --audit-allows reports instead of scanning: every `theme-allow` annotation and every\n `basalt.exemptRules` entry, with what each one still suppresses \u2014 proved by re-running the\n guard with that one waiver neutralized, not by reading its text. Exits 1 on a waiver that\n suppresses nothing (dead), which is what makes it usable as a CI gate.\n\ntokens:css [--out <path>] [--check] [--selector-attribute <attr> | --selector-class <class>]\n [--light-class <class>] [--dark-value <v>] [--light-value <v>]\n [--default-scheme <dark|light|none>] [--media-fallback] [--only <core|all>]\n [--no-legacy-aliases]\n Emit the --vx-* stylesheet (stdout unless --out). Defaults reproduce basalt-ui/tokens.css.\n --selector-class emits `:root.dark` instead of an attribute selector (the Tailwind convention).\n --check writes nothing and exits 1 when --out differs from what would be emitted (a CI gate).\n --no-legacy-aliases drops the deprecated camelCase spellings (--vx-accentFill and friends),\n which are emitted by default as aliases of the canonical kebab-case names.\n\nfonts:css [--out <path>] [--check]\n Emit the shipped --basalt-font-* stacks as plain CSS \u2014 the typeface half of the token layer,\n otherwise reachable only by importing styles.css.\n\ndoctor [--tokens-only|--framework]\n Auto-detects a tokens-only consumer (no manifest + no @mantine/core) and checks only what\n applies. A check that cannot RUN is reported as SKIPPED and exits non-zero.\n\nsync [--force] [--check] [--tokens-only|--framework]\n Refreshes an EXISTING install; it never creates one (that is init). A tokens-only consumer\n has no scaffold to reconcile, so sync reports n/a and exits 0 there \u2014 as doctor does.\n\ncheck-theme / doctor / sync all resolve their project the same way: they honour BASALT_CWD, and\nrelocate to the single package below the cwd carrying a basalt config when invoked from a repo\nroot that has none \u2014 several carrying one is ambiguous and exits 1 in ALL THREE.\n--tokens-only and --framework are alternatives; passing both is an error.\n\nEvery subcommand accepts --help / -h to print this message and exit without running.";
|
|
2209
2245
|
function run(argv, cwd = process.cwd()) {
|
|
2210
2246
|
const [cmd, ...flags] = argv;
|
|
2211
2247
|
if (cmd === "help" || cmd === "--help" || cmd === "-h" || flags.includes("--help") || flags.includes("-h")) {
|
|
@@ -2220,7 +2256,10 @@ function run(argv, cwd = process.cwd()) {
|
|
|
2220
2256
|
mergeLint: flags.includes("--merge-lint")
|
|
2221
2257
|
});
|
|
2222
2258
|
case "sync":
|
|
2223
|
-
return sync(
|
|
2259
|
+
return sync(
|
|
2260
|
+
{ force: flags.includes("--force"), check: flags.includes("--check"), flags },
|
|
2261
|
+
cwd
|
|
2262
|
+
);
|
|
2224
2263
|
case "check-theme":
|
|
2225
2264
|
return checkTheme(cwd, flags);
|
|
2226
2265
|
case "check-coverage":
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shipped-versions.test.d.ts","sourceRoot":"","sources":["../../src/cli/shipped-versions.test.ts"],"names":[],"mappings":""}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/guard/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAE7E,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,CAAA;AAyb9D,8EAA8E;AAC9E,eAAO,MAAM,oBAAoB,EAAE,WAoBlC,CAAA;AAmJD,sGAAsG;AACtG,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,UAAU,CAAA;CAC7C,CAAA;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,WAAW,EAChB,eAAe,EAAE,SAAS,MAAM,EAAE,GACjC,sBAAsB,EAAE,CAc1B;AAID;;;;;;;;;GASG;AACH,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,MAAM,CAkB9C,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/guard/index.ts"],"names":[],"mappings":"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"}
|
package/dist/guard/index.js
CHANGED
|
@@ -108,7 +108,7 @@ const RADIUS_PROP_RE = /\bradius=(?:\{[0-9]+\}|"[0-9]+")/g;
|
|
|
108
108
|
const MOTION_TRANSITION_NUMERIC = /\btransition\s*=\s*\{\{[^}]*\b(?:duration|stiffness|damping|mass)\s*:\s*-?\d/g;
|
|
109
109
|
const MOTION_TRANSITION_EASE_ARRAY = /\btransition\s*=\s*\{\{[^}]*\bease\s*:\s*\[/g;
|
|
110
110
|
const RAW_CHART_LEGEND_ARRAY = /<ChartLegend\b[^>]*?\bitems\s*=\s*\{\s*\[/g;
|
|
111
|
-
const CHART_ENTRY_POINT_TAG = /<(?:MultiLine|Bars|Donut|DualPanel|Heatmap|ZonedLine|StackedArea|LineSparkline|BarSparkline)\b(?:<[^<>]*>)?(?:=>|[^>])*?>/g;
|
|
111
|
+
const CHART_ENTRY_POINT_TAG = /<(?:MultiLine|Bars|BandStrip|Donut|DualPanel|Heatmap|MirroredBars|ZonedLine|StackedArea|LineSparkline|BarSparkline)\b(?:<[^<>]*>)?(?:=>|[^>])*?>/g;
|
|
112
112
|
const HAS_ARIA_LABEL_PROP = /\bariaLabel\s*=/;
|
|
113
113
|
const RAW_FORM_CONTROL = /<(?:input|select|textarea)\b/g;
|
|
114
114
|
const RAW_FORM_CONTROL_TAG = /<(?:input|select|textarea)\b(?:=>|[^>])*?>/g;
|
|
@@ -250,10 +250,23 @@ function parseAllowAnnotation(rest, scope) {
|
|
|
250
250
|
return { rules, unknownRules, hasReason: reason.length >= MIN_ALLOW_REASON_LENGTH, scope };
|
|
251
251
|
}
|
|
252
252
|
const MAX_CSS_CONTINUATION_LINES = 8;
|
|
253
|
-
|
|
253
|
+
function commentBlockEnd(lines, index, tokenAt, syntax) {
|
|
254
|
+
const line = lines[index] ?? "";
|
|
255
|
+
if (syntax === "ts" && /\/\/\s*$/.test(line.slice(0, tokenAt))) return index;
|
|
256
|
+
const closer = syntax === "markup" ? "-->" : "*/";
|
|
257
|
+
if (line.slice(tokenAt).includes(closer)) return index;
|
|
258
|
+
for (let ahead = index + 1; ahead < lines.length; ahead++) {
|
|
259
|
+
if ((lines[ahead] ?? "").includes(closer)) return ahead;
|
|
260
|
+
}
|
|
261
|
+
return index;
|
|
262
|
+
}
|
|
254
263
|
const COMMENT_OPENER_BEFORE = /(?:\/\/|\/\*|<!--)\s*$/;
|
|
255
264
|
const COMMENT_ONLY_LINE = /^\s*(?:\{\s*\/\*|\/\/|\/\*|\*|<!--)/;
|
|
256
265
|
const JSX_COMMENT_CLOSE = /\*\/\s*\}\s*$/;
|
|
266
|
+
function isCommentOnly(raw, stripped) {
|
|
267
|
+
const code = stripped.trim();
|
|
268
|
+
return code === "" || COMMENT_ONLY_LINE.test(raw) || code === "}" && JSX_COMMENT_CLOSE.test(raw);
|
|
269
|
+
}
|
|
257
270
|
const ANNOTATION_PREFIX = /(?:^|\/\/|\/\*\*?|<!--|^\s*\*)\s*$/;
|
|
258
271
|
function escapeRegExp(value) {
|
|
259
272
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -273,7 +286,7 @@ function collectAllowAnnotations(lines, codeLines, allowComment, syntax) {
|
|
|
273
286
|
list.push(annotation);
|
|
274
287
|
byLine.set(index, list);
|
|
275
288
|
};
|
|
276
|
-
const record = (index, annotation, trailing) => {
|
|
289
|
+
const record = (index, annotation, trailing, tokenAt) => {
|
|
277
290
|
declared.push({ line: index + 1, annotation });
|
|
278
291
|
if (annotation.scope === "file") {
|
|
279
292
|
fileScoped.push(annotation);
|
|
@@ -281,11 +294,14 @@ function collectAllowAnnotations(lines, codeLines, allowComment, syntax) {
|
|
|
281
294
|
}
|
|
282
295
|
add(index, annotation);
|
|
283
296
|
if (!trailing) {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
297
|
+
const closesAt = commentBlockEnd(lines, index, tokenAt, syntax);
|
|
298
|
+
for (let ahead = 1; index + ahead < lines.length; ahead++) {
|
|
299
|
+
const at = index + ahead;
|
|
300
|
+
add(at, annotation);
|
|
301
|
+
if (at <= closesAt) continue;
|
|
302
|
+
const raw = lines[at] ?? "";
|
|
288
303
|
if (raw.trim() === "") break;
|
|
304
|
+
if (!isCommentOnly(raw, codeLines[at] ?? "")) break;
|
|
289
305
|
}
|
|
290
306
|
return;
|
|
291
307
|
}
|
|
@@ -301,11 +317,15 @@ function collectAllowAnnotations(lines, codeLines, allowComment, syntax) {
|
|
|
301
317
|
for (let i = 0; i < lines.length; i++) {
|
|
302
318
|
const line = lines[i] ?? "";
|
|
303
319
|
const stripped = codeLines[i] ?? "";
|
|
304
|
-
const
|
|
305
|
-
const isCommentOnlyLine = code === "" || COMMENT_ONLY_LINE.test(line) || code === "}" && JSX_COMMENT_CLOSE.test(line);
|
|
320
|
+
const isCommentOnlyLine = isCommentOnly(line, stripped);
|
|
306
321
|
if (syntax === "markup") {
|
|
307
322
|
for (const m of line.matchAll(jsonKey)) {
|
|
308
|
-
record(
|
|
323
|
+
record(
|
|
324
|
+
i,
|
|
325
|
+
parseAllowAnnotation(m[2] ?? "", m[1] === void 0 ? "line" : "file"),
|
|
326
|
+
false,
|
|
327
|
+
m.index
|
|
328
|
+
);
|
|
309
329
|
}
|
|
310
330
|
}
|
|
311
331
|
for (const m of line.matchAll(token)) {
|
|
@@ -317,7 +337,8 @@ function collectAllowAnnotations(lines, codeLines, allowComment, syntax) {
|
|
|
317
337
|
record(
|
|
318
338
|
i,
|
|
319
339
|
parseAllowAnnotation(rest, m[1] === void 0 ? "line" : "file"),
|
|
320
|
-
!isCommentOnlyLine
|
|
340
|
+
!isCommentOnlyLine,
|
|
341
|
+
at
|
|
321
342
|
);
|
|
322
343
|
}
|
|
323
344
|
}
|
package/dist/vite.d.ts
CHANGED
|
@@ -33,6 +33,29 @@ export type BasaltViteOptions = {
|
|
|
33
33
|
enforcementNotice?: boolean;
|
|
34
34
|
};
|
|
35
35
|
export declare function basaltViteConfig(opts: BasaltViteOptions): UserConfig;
|
|
36
|
+
/**
|
|
37
|
+
* One icon a consumer names itself — a manifest `icons` member, plus optionally the head `<link>`
|
|
38
|
+
* that points at the same file.
|
|
39
|
+
*
|
|
40
|
+
* The field names are the manifest's own, verbatim, so what a consumer writes here is what ships in
|
|
41
|
+
* `site.webmanifest`. `src` is root-relative (`'/favicon.svg'` or `'favicon.svg'`, both resolve the
|
|
42
|
+
* same) and is prefixed with Vite's `base` exactly like basalt's built-in set.
|
|
43
|
+
*/
|
|
44
|
+
export type BasaltAppIcon = {
|
|
45
|
+
/** Root-relative path under `public/`. Prefixed with Vite's resolved `base`. */
|
|
46
|
+
src: string;
|
|
47
|
+
/** Manifest `sizes`. `'any'` for a scalable SVG; `'192x192'` for a raster. */
|
|
48
|
+
sizes?: string;
|
|
49
|
+
/** MIME type, e.g. `'image/svg+xml'`. */
|
|
50
|
+
type?: string;
|
|
51
|
+
/** Manifest `purpose`, e.g. `'any maskable'`. */
|
|
52
|
+
purpose?: string;
|
|
53
|
+
/**
|
|
54
|
+
* Emit a head `<link rel="…">` for this icon too. Omitted → manifest only, which is what an app
|
|
55
|
+
* that links its own favicon from `index.html` wants.
|
|
56
|
+
*/
|
|
57
|
+
rel?: 'icon' | 'shortcut icon' | 'apple-touch-icon' | 'mask-icon';
|
|
58
|
+
};
|
|
36
59
|
export type BasaltAppOptions = {
|
|
37
60
|
/** App display name — used verbatim as the manifest `name` and (unless overridden) OG title. */
|
|
38
61
|
name: string;
|
|
@@ -81,12 +104,28 @@ export type BasaltAppOptions = {
|
|
|
81
104
|
/** Manifest `id`. Default: the resolved `startUrl` (default- or explicitly-derived, per above). */
|
|
82
105
|
id?: string;
|
|
83
106
|
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
107
|
+
* Which icons the plugin knows about — three forms, one question each.
|
|
108
|
+
*
|
|
109
|
+
* - **omitted / `{ dir }`** — basalt's own six-filename set (the realfavicongenerator layout argo
|
|
110
|
+
* ships), optionally under a subdirectory of `public/`. Unchanged default.
|
|
111
|
+
* - **`false`** — no head `<link>` icons and no manifest `icons` member, so a manifest is never
|
|
112
|
+
* emitted pointing at files that 404.
|
|
113
|
+
* - **an array** — the icons this app ACTUALLY has, named by the consumer.
|
|
114
|
+
*
|
|
115
|
+
* The array is the form for every app that was not scaffolded from basalt's icon set, which is
|
|
116
|
+
* most of them. `{ dir }` can only move the six fixed filenames; it cannot rename one, so an app
|
|
117
|
+
* whose single icon is `favicon.svg` had no way to say so and had to keep a hand-written manifest
|
|
118
|
+
* beside the generated head — the last thing standing between rb and deleting a file carrying a
|
|
119
|
+
* permanent `theme-allow-file`. One SVG at `sizes: 'any'` is a complete, installable icon set.
|
|
120
|
+
*
|
|
121
|
+
* Every entry becomes a manifest icon; an entry becomes a head `<link>` only when it names a
|
|
122
|
+
* {@link BasaltAppIcon.rel}. That split is deliberate — an app that already links its favicon
|
|
123
|
+
* from its own `index.html` wants the manifest fixed without a duplicate tag, and an app that
|
|
124
|
+
* wants the plugin to own the head says so per icon. An empty array reads as `false`.
|
|
86
125
|
*/
|
|
87
126
|
icons?: false | {
|
|
88
127
|
dir?: string;
|
|
89
|
-
};
|
|
128
|
+
} | readonly BasaltAppIcon[];
|
|
90
129
|
/** Emits `<meta name="darkreader-lock">` when `'lock'` (default). Pass `false` to omit it. */
|
|
91
130
|
darkreader?: 'lock' | false;
|
|
92
131
|
/** Site-wide SEO metadata — only the keys provided are emitted, no per-page SEO. */
|
package/dist/vite.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vite.d.ts","sourceRoot":"","sources":["../src/vite.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAA6B,YAAY,EAAE,UAAU,EAAE,MAAM,MAAM,CAAA;AAI/E,MAAM,MAAM,iBAAiB,GAAG;IAC9B,4FAA4F;IAC5F,IAAI,EAAE,MAAM,CAAA;IACZ,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IACvB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,kFAAkF;IAClF,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC5B,CAAA;AA6CD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,iBAAiB,GAAG,UAAU,CAgFpE;AAgBD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,gGAAgG;IAChG,IAAI,EAAE,MAAM,CAAA;IACZ,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gGAAgG;IAChG,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;IACrD;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAA;IAC/C;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,wDAAwD;IACxD,OAAO,CAAC,EAAE,YAAY,GAAG,YAAY,GAAG,YAAY,GAAG,SAAS,CAAA;IAChE;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,mGAAmG;IACnG,EAAE,CAAC,EAAE,MAAM,CAAA;IACX
|
|
1
|
+
{"version":3,"file":"vite.d.ts","sourceRoot":"","sources":["../src/vite.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAA6B,YAAY,EAAE,UAAU,EAAE,MAAM,MAAM,CAAA;AAI/E,MAAM,MAAM,iBAAiB,GAAG;IAC9B,4FAA4F;IAC5F,IAAI,EAAE,MAAM,CAAA;IACZ,6EAA6E;IAC7E,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IACvB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,kFAAkF;IAClF,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC5B,CAAA;AA6CD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,iBAAiB,GAAG,UAAU,CAgFpE;AAgBD;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,gFAAgF;IAChF,GAAG,EAAE,MAAM,CAAA;IACX,8EAA8E;IAC9E,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,yCAAyC;IACzC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,GAAG,eAAe,GAAG,kBAAkB,GAAG,WAAW,CAAA;CAClE,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,gGAAgG;IAChG,IAAI,EAAE,MAAM,CAAA;IACZ,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gGAAgG;IAChG,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAA;IACrD;;;;;;;;;OASG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAA;IAC/C;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,wDAAwD;IACxD,OAAO,CAAC,EAAE,YAAY,GAAG,YAAY,GAAG,YAAY,GAAG,SAAS,CAAA;IAChE;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,mGAAmG;IACnG,EAAE,CAAC,EAAE,MAAM,CAAA;IACX;;;;;;;;;;;;;;;;;;;OAmBG;IACH,KAAK,CAAC,EAAE,KAAK,GAAG;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,aAAa,EAAE,CAAA;IAC3D,8FAA8F;IAC9F,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;IAC3B,oFAAoF;IACpF,GAAG,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,SAAS,GAAG,qBAAqB,CAAA;KAAE,CAAA;IACvF,8FAA8F;IAC9F,QAAQ,CAAC,EAAE,KAAK,CAAA;IAChB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAClD,CAAA;AA0kBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,YAAY,EAAE,CAMzE"}
|
package/dist/vite.js
CHANGED
|
@@ -133,6 +133,18 @@ function withIconPath(dir, file) {
|
|
|
133
133
|
function withBase(base, path) {
|
|
134
134
|
return base + path.slice(1);
|
|
135
135
|
}
|
|
136
|
+
function isIconList(icons) {
|
|
137
|
+
return Array.isArray(icons);
|
|
138
|
+
}
|
|
139
|
+
function resolveIcons(icons) {
|
|
140
|
+
if (icons === false) return { mode: "none" };
|
|
141
|
+
if (icons === void 0) return { mode: "default", dir: void 0 };
|
|
142
|
+
if (!isIconList(icons)) return { mode: "default", dir: icons.dir };
|
|
143
|
+
return icons.length === 0 ? { mode: "none" } : { mode: "explicit", icons };
|
|
144
|
+
}
|
|
145
|
+
function iconHref(base, src) {
|
|
146
|
+
return withBase(base, src.startsWith("/") ? src : `/${src}`);
|
|
147
|
+
}
|
|
136
148
|
function hasViewportMeta(html) {
|
|
137
149
|
return /<meta\s+[^>]*name=["']viewport["']/i.test(html);
|
|
138
150
|
}
|
|
@@ -207,8 +219,7 @@ function buildStaticTags(input) {
|
|
|
207
219
|
shortName,
|
|
208
220
|
themeColor,
|
|
209
221
|
bootStyle,
|
|
210
|
-
|
|
211
|
-
iconsDir,
|
|
222
|
+
icons,
|
|
212
223
|
darkreader,
|
|
213
224
|
manifestEnabled,
|
|
214
225
|
base,
|
|
@@ -234,13 +245,13 @@ function buildStaticTags(input) {
|
|
|
234
245
|
}
|
|
235
246
|
);
|
|
236
247
|
tags.push({ tag: "style", children: bootStyle });
|
|
237
|
-
if (
|
|
248
|
+
if (icons.mode === "default") {
|
|
238
249
|
tags.push(
|
|
239
250
|
{
|
|
240
251
|
tag: "link",
|
|
241
252
|
attrs: {
|
|
242
253
|
rel: "shortcut icon",
|
|
243
|
-
href: withBase(base, withIconPath(
|
|
254
|
+
href: withBase(base, withIconPath(icons.dir, ICON_FILES.favicon))
|
|
244
255
|
}
|
|
245
256
|
},
|
|
246
257
|
{
|
|
@@ -248,7 +259,7 @@ function buildStaticTags(input) {
|
|
|
248
259
|
attrs: {
|
|
249
260
|
rel: "icon",
|
|
250
261
|
type: "image/svg+xml",
|
|
251
|
-
href: withBase(base, withIconPath(
|
|
262
|
+
href: withBase(base, withIconPath(icons.dir, ICON_FILES.svg))
|
|
252
263
|
}
|
|
253
264
|
},
|
|
254
265
|
{
|
|
@@ -256,7 +267,7 @@ function buildStaticTags(input) {
|
|
|
256
267
|
attrs: {
|
|
257
268
|
rel: "icon",
|
|
258
269
|
sizes: "96x96",
|
|
259
|
-
href: withBase(base, withIconPath(
|
|
270
|
+
href: withBase(base, withIconPath(icons.dir, ICON_FILES.png96))
|
|
260
271
|
}
|
|
261
272
|
},
|
|
262
273
|
{
|
|
@@ -264,11 +275,25 @@ function buildStaticTags(input) {
|
|
|
264
275
|
attrs: {
|
|
265
276
|
rel: "apple-touch-icon",
|
|
266
277
|
sizes: "180x180",
|
|
267
|
-
href: withBase(base, withIconPath(
|
|
278
|
+
href: withBase(base, withIconPath(icons.dir, ICON_FILES.appleTouch))
|
|
268
279
|
}
|
|
269
280
|
}
|
|
270
281
|
);
|
|
271
282
|
}
|
|
283
|
+
if (icons.mode === "explicit") {
|
|
284
|
+
for (const icon of icons.icons) {
|
|
285
|
+
if (icon.rel === void 0) continue;
|
|
286
|
+
tags.push({
|
|
287
|
+
tag: "link",
|
|
288
|
+
attrs: {
|
|
289
|
+
rel: icon.rel,
|
|
290
|
+
...icon.type === void 0 ? {} : { type: icon.type },
|
|
291
|
+
...icon.sizes === void 0 ? {} : { sizes: icon.sizes },
|
|
292
|
+
href: iconHref(base, icon.src)
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
}
|
|
272
297
|
tags.push(
|
|
273
298
|
{ tag: "meta", attrs: { name: "apple-mobile-web-app-title", content: shortName } },
|
|
274
299
|
{ tag: "meta", attrs: { name: "apple-mobile-web-app-capable", content: "yes" } },
|
|
@@ -286,6 +311,34 @@ function buildStaticTags(input) {
|
|
|
286
311
|
);
|
|
287
312
|
return tags;
|
|
288
313
|
}
|
|
314
|
+
function manifestIcons(icons, base) {
|
|
315
|
+
if (icons.mode === "none") return {};
|
|
316
|
+
if (icons.mode === "default") {
|
|
317
|
+
return {
|
|
318
|
+
icons: [
|
|
319
|
+
{
|
|
320
|
+
src: withBase(base, withIconPath(icons.dir, ICON_FILES.manifest192)),
|
|
321
|
+
sizes: "192x192",
|
|
322
|
+
type: "image/png"
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
src: withBase(base, withIconPath(icons.dir, ICON_FILES.manifest512)),
|
|
326
|
+
sizes: "512x512",
|
|
327
|
+
type: "image/png",
|
|
328
|
+
purpose: "any maskable"
|
|
329
|
+
}
|
|
330
|
+
]
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
return {
|
|
334
|
+
icons: icons.icons.map((icon) => ({
|
|
335
|
+
src: iconHref(base, icon.src),
|
|
336
|
+
...icon.sizes === void 0 ? {} : { sizes: icon.sizes },
|
|
337
|
+
...icon.type === void 0 ? {} : { type: icon.type },
|
|
338
|
+
...icon.purpose === void 0 ? {} : { purpose: icon.purpose }
|
|
339
|
+
}))
|
|
340
|
+
};
|
|
341
|
+
}
|
|
289
342
|
function buildManifestJson(input) {
|
|
290
343
|
const {
|
|
291
344
|
options,
|
|
@@ -296,8 +349,7 @@ function buildManifestJson(input) {
|
|
|
296
349
|
display,
|
|
297
350
|
schemeColor,
|
|
298
351
|
backgroundColor,
|
|
299
|
-
|
|
300
|
-
iconsDir,
|
|
352
|
+
icons,
|
|
301
353
|
base
|
|
302
354
|
} = input;
|
|
303
355
|
const manifest = {
|
|
@@ -316,21 +368,9 @@ function buildManifestJson(input) {
|
|
|
316
368
|
// `{ manifest: true, icons: false }` shipped a manifest pointing at two PNGs the app never
|
|
317
369
|
// ships — an installable app with broken icons, and the reason rb went hybrid (plugin for the
|
|
318
370
|
// head, a hand-written manifest for the rest). A manifest with NO icons member is valid.
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
src: withBase(base, withIconPath(iconsDir, ICON_FILES.manifest192)),
|
|
323
|
-
sizes: "192x192",
|
|
324
|
-
type: "image/png"
|
|
325
|
-
},
|
|
326
|
-
{
|
|
327
|
-
src: withBase(base, withIconPath(iconsDir, ICON_FILES.manifest512)),
|
|
328
|
-
sizes: "512x512",
|
|
329
|
-
type: "image/png",
|
|
330
|
-
purpose: "any maskable"
|
|
331
|
-
}
|
|
332
|
-
]
|
|
333
|
-
} : {}
|
|
371
|
+
// The `'explicit'` arm is the other half of that fix: honest about icons it cannot see was
|
|
372
|
+
// only worth having once a consumer could tell it which icons it DOES have.
|
|
373
|
+
...manifestIcons(icons, base)
|
|
334
374
|
};
|
|
335
375
|
return JSON.stringify(manifest, null, 2);
|
|
336
376
|
}
|
|
@@ -338,8 +378,7 @@ function createMainPlugin(options) {
|
|
|
338
378
|
const shortName = options.shortName ?? options.name;
|
|
339
379
|
const display = options.display ?? "standalone";
|
|
340
380
|
const darkreader = options.darkreader ?? "lock";
|
|
341
|
-
const
|
|
342
|
-
const iconsDir = options.icons === false ? void 0 : options.icons?.dir;
|
|
381
|
+
const icons = resolveIcons(options.icons);
|
|
343
382
|
const manifestEnabled = options.manifest !== false;
|
|
344
383
|
const themeColor = resolveThemeColors(options.themeColor);
|
|
345
384
|
const colorScheme = options.colorScheme ?? "dark";
|
|
@@ -371,8 +410,7 @@ function createMainPlugin(options) {
|
|
|
371
410
|
display,
|
|
372
411
|
schemeColor,
|
|
373
412
|
backgroundColor,
|
|
374
|
-
|
|
375
|
-
iconsDir,
|
|
413
|
+
icons,
|
|
376
414
|
base
|
|
377
415
|
});
|
|
378
416
|
staticTags = buildStaticTags({
|
|
@@ -380,8 +418,7 @@ function createMainPlugin(options) {
|
|
|
380
418
|
shortName,
|
|
381
419
|
themeColor,
|
|
382
420
|
bootStyle,
|
|
383
|
-
|
|
384
|
-
iconsDir,
|
|
421
|
+
icons,
|
|
385
422
|
darkreader,
|
|
386
423
|
manifestEnabled,
|
|
387
424
|
base,
|
package/llms.txt
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# basalt-ui v1.
|
|
1
|
+
# basalt-ui v1.23.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.23.0
|
|
23
23
|
|
|
24
24
|
## basalt-ui
|
|
25
25
|
Import: import { ... } from 'basalt-ui'
|