@calibrate-ds/generator-react 0.1.87 → 0.1.89
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.
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getPTBTokenVariableName, formatPx } from "@calibrate-ds/core";
|
|
2
|
+
import { isEmittableColorValue } from "./token-value-utils.js";
|
|
2
3
|
function getActiveValue(value) {
|
|
3
4
|
if (value === null || value === undefined)
|
|
4
5
|
return value;
|
|
@@ -201,18 +202,6 @@ function formatCompositeToken(rawValue) {
|
|
|
201
202
|
function formatPxLocal(value) {
|
|
202
203
|
return `${Math.round(value * 1000) / 1000}px`;
|
|
203
204
|
}
|
|
204
|
-
/**
|
|
205
|
-
* E-9: a value that looks like a hex color (leading '#') but contains non-hex
|
|
206
|
-
* digits (e.g. "#GGGGGG") or the wrong length is invalid CSS and must not be
|
|
207
|
-
* emitted verbatim — it silently breaks the whole custom-property. Returns true
|
|
208
|
-
* only for well-formed #RGB / #RGBA / #RRGGBB / #RRGGBBAA. Non-'#' strings are
|
|
209
|
-
* not our concern here (they take other paths) and return true.
|
|
210
|
-
*/
|
|
211
|
-
function isEmittableColorValue(value) {
|
|
212
|
-
if (!value.startsWith("#"))
|
|
213
|
-
return true;
|
|
214
|
-
return /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(value);
|
|
215
|
-
}
|
|
216
205
|
/**
|
|
217
206
|
* Formats a resolved scalar value for CSS output (px suffix, units, font fallbacks).
|
|
218
207
|
*/
|
|
@@ -426,7 +415,11 @@ export function generateTokenCssContent(collection, richGlobalMap) {
|
|
|
426
415
|
}
|
|
427
416
|
const header = `/**\n * Generated Design Tokens: ${collection.name} (CSS Variables)\n * Do not edit. This file is auto-generated by Calibrate.\n */\n`;
|
|
428
417
|
const skippedComment = skippedCount > 0 ? `\n/* Note: ${skippedCount} tokens were skipped from this local CSS output (unresolved or non-scalar). */\n` : "";
|
|
429
|
-
|
|
418
|
+
// E-19 parity: per-collection CSS also emits [data-theme] override blocks for
|
|
419
|
+
// multi-mode collections, mirroring the unified tokens.css path. Uses resolveMap
|
|
420
|
+
// (local + any cross-collection alias targets) so alias mode values still resolve.
|
|
421
|
+
const modeBlocks = generateModeOverrideBlocks([collection], resolveMap);
|
|
422
|
+
return `${header}${skippedComment}\n:root {\n${cssVars}}\n${modeBlocks}`;
|
|
430
423
|
}
|
|
431
424
|
/**
|
|
432
425
|
* Generates a unified CSS Variables file containing all tokens from all collections.
|
|
@@ -567,7 +560,7 @@ export function generateUnifiedTokenCssContent(model) {
|
|
|
567
560
|
// re-emitted — alias tokens stay in :root as var() and cascade automatically,
|
|
568
561
|
// which is exactly the theming architecture (primitives flip, semantics follow).
|
|
569
562
|
// Modes with the same (slugified) name across collections merge into one block.
|
|
570
|
-
const modeBlocks = generateModeOverrideBlocks(model, allTokens);
|
|
563
|
+
const modeBlocks = generateModeOverrideBlocks(model.tokens, allTokens);
|
|
571
564
|
const content = `/**
|
|
572
565
|
* Generated Design Tokens (Unified CSS Variables)
|
|
573
566
|
* Do not edit. This file is auto-generated by Calibrate.
|
|
@@ -596,10 +589,10 @@ function slugifyModeName(name) {
|
|
|
596
589
|
* common case and adds nothing). Emits a token override only when that mode's value
|
|
597
590
|
* actually differs from the default mode's — so the block stays minimal.
|
|
598
591
|
*/
|
|
599
|
-
function generateModeOverrideBlocks(
|
|
592
|
+
function generateModeOverrideBlocks(collections, allTokens) {
|
|
600
593
|
// slug → mode display name (first wins) and accumulated CSS lines
|
|
601
594
|
const blocks = new Map();
|
|
602
|
-
for (const collection of
|
|
595
|
+
for (const collection of collections) {
|
|
603
596
|
const modes = collection.modes;
|
|
604
597
|
if (!modes || modes.length < 2)
|
|
605
598
|
continue;
|
|
@@ -632,6 +625,9 @@ function generateModeOverrideBlocks(model, allTokens) {
|
|
|
632
625
|
continue;
|
|
633
626
|
}
|
|
634
627
|
}
|
|
628
|
+
// E-9 parity: never emit a malformed hex override.
|
|
629
|
+
if (typeof value === "string" && !isEmittableColorValue(value))
|
|
630
|
+
continue;
|
|
635
631
|
const varName = getPTBTokenVariableName(collection.name, t.name);
|
|
636
632
|
const line = ` ${varName}: ${formatCssValue(value, t.type, t.name)};`;
|
|
637
633
|
const bucket = blocks.get(slug) ?? { name: mode.name, lines: [] };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { formatCollectionImportName } from "../components/token-helpers.js";
|
|
2
|
+
import { isEmittableColorValue } from "./token-value-utils.js";
|
|
2
3
|
/**
|
|
3
4
|
* Converts a raw Figma token name to a camelCase JS identifier key.
|
|
4
5
|
* Must produce the same result as the camelCase logic in token-helpers.ts selectTokensForSlots,
|
|
@@ -10,6 +11,10 @@ export function tokenNameToKey(name) {
|
|
|
10
11
|
// Guard against keys that start with a digit (invalid unquoted JS identifier)
|
|
11
12
|
return /^\d/.test(camel) ? `_${camel}` : (camel || "unknown");
|
|
12
13
|
}
|
|
14
|
+
/** Slugify a design-tool mode name into a stable object key ("Dark Mode" → "dark-mode"). */
|
|
15
|
+
function slugifyModeKey(name) {
|
|
16
|
+
return (name ?? "").toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "mode";
|
|
17
|
+
}
|
|
13
18
|
/**
|
|
14
19
|
* Generates TypeScript constant file content for a Token Collection.
|
|
15
20
|
*/
|
|
@@ -20,16 +25,40 @@ export function generateTokenFileContent(collection) {
|
|
|
20
25
|
const exportIdent = `${formatCollectionImportName(collection.name)}Tokens`;
|
|
21
26
|
let tokensContent = "";
|
|
22
27
|
for (const t of collection.tokens ?? []) {
|
|
28
|
+
// E-9 parity: a malformed hex value (e.g. "#GGGGGG") is skipped here just as it is
|
|
29
|
+
// in the CSS emitters, so invalid values never leak into the TS export either.
|
|
30
|
+
if (typeof t.value === "string" && !isEmittableColorValue(t.value))
|
|
31
|
+
continue;
|
|
23
32
|
// Key is camelCase-normalized to match dot-accessor references generated by token-helpers.ts.
|
|
24
33
|
// E.g. Figma token "color/brand/700" → key "colorBrand700" → accessible as tokens.colorBrand700.
|
|
25
34
|
const key = tokenNameToKey(t.name);
|
|
26
35
|
const jsonValue = JSON.stringify(t.value ?? null, null, 4).replace(/\n/g, "\n ");
|
|
36
|
+
// E-19 parity: for multi-mode collections, also emit the per-mode values (keyed by
|
|
37
|
+
// slugified mode name, e.g. { light, dark }) so the TS export carries every theme —
|
|
38
|
+
// not just the default mode — mirroring the [data-theme] blocks in the CSS output.
|
|
39
|
+
// Malformed hex mode values are dropped, consistent with the default value above.
|
|
40
|
+
let byModeLine = "";
|
|
41
|
+
if (t.valuesByMode && collection.modes && collection.modes.length > 1) {
|
|
42
|
+
const byMode = {};
|
|
43
|
+
for (const mode of collection.modes) {
|
|
44
|
+
const mv = t.valuesByMode[mode.id];
|
|
45
|
+
if (mv === undefined)
|
|
46
|
+
continue;
|
|
47
|
+
if (typeof mv === "string" && !isEmittableColorValue(mv))
|
|
48
|
+
continue;
|
|
49
|
+
byMode[slugifyModeKey(mode.name)] = mv;
|
|
50
|
+
}
|
|
51
|
+
if (Object.keys(byMode).length > 0) {
|
|
52
|
+
const byModeJson = JSON.stringify(byMode, null, 4).replace(/\n/g, "\n ");
|
|
53
|
+
byModeLine = `,\n valuesByMode: ${byModeJson}`;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
27
56
|
tokensContent += `
|
|
28
57
|
"${key}": {
|
|
29
58
|
id: "${t.id}",
|
|
30
59
|
name: "${t.name}",
|
|
31
60
|
type: "${t.type}",
|
|
32
|
-
value: ${jsonValue}
|
|
61
|
+
value: ${jsonValue}${byModeLine}
|
|
33
62
|
},`;
|
|
34
63
|
}
|
|
35
64
|
return `/**
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared token-value guards used by every token emitter (unified CSS, per-collection
|
|
3
|
+
* CSS, and the TypeScript export) so a fix applies uniformly instead of to one emitter.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* E-9: a value that looks like a hex color (leading '#') but is malformed — contains
|
|
7
|
+
* non-hex digits (e.g. "#GGGGGG") or is the wrong length — is invalid and must not be
|
|
8
|
+
* emitted verbatim, whether into CSS or the TS token export. Returns true only for
|
|
9
|
+
* well-formed #RGB / #RGBA / #RRGGBB / #RRGGBBAA. Non-'#' strings take other paths and
|
|
10
|
+
* are not this function's concern (returns true).
|
|
11
|
+
*/
|
|
12
|
+
export declare function isEmittableColorValue(value: string): boolean;
|
|
13
|
+
//# sourceMappingURL=token-value-utils.d.ts.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared token-value guards used by every token emitter (unified CSS, per-collection
|
|
3
|
+
* CSS, and the TypeScript export) so a fix applies uniformly instead of to one emitter.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* E-9: a value that looks like a hex color (leading '#') but is malformed — contains
|
|
7
|
+
* non-hex digits (e.g. "#GGGGGG") or is the wrong length — is invalid and must not be
|
|
8
|
+
* emitted verbatim, whether into CSS or the TS token export. Returns true only for
|
|
9
|
+
* well-formed #RGB / #RGBA / #RRGGBB / #RRGGBBAA. Non-'#' strings take other paths and
|
|
10
|
+
* are not this function's concern (returns true).
|
|
11
|
+
*/
|
|
12
|
+
export function isEmittableColorValue(value) {
|
|
13
|
+
if (!value.startsWith("#"))
|
|
14
|
+
return true;
|
|
15
|
+
return /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test(value);
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=token-value-utils.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@calibrate-ds/generator-react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.89",
|
|
4
4
|
"license": "FSL-1.1-MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"react": "^19.0.0",
|
|
38
|
-
"@calibrate-ds/shared-types": "^0.1.
|
|
39
|
-
"@calibrate-ds/core": "^0.1.
|
|
38
|
+
"@calibrate-ds/shared-types": "^0.1.89",
|
|
39
|
+
"@calibrate-ds/core": "^0.1.89"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"typescript": "^5.7.3",
|