@sxl-studio/token-transformer 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.en.md +638 -0
  2. package/README.md +715 -0
  3. package/config.example.json +45 -0
  4. package/dist/cli.d.ts +2 -0
  5. package/dist/cli.js +160 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/core/loader.d.ts +8 -0
  8. package/dist/core/loader.js +105 -0
  9. package/dist/core/loader.js.map +1 -0
  10. package/dist/core/parser.d.ts +5 -0
  11. package/dist/core/parser.js +186 -0
  12. package/dist/core/parser.js.map +1 -0
  13. package/dist/core/types.d.ts +83 -0
  14. package/dist/core/types.js +2 -0
  15. package/dist/core/types.js.map +1 -0
  16. package/dist/core/writer.d.ts +6 -0
  17. package/dist/core/writer.js +124 -0
  18. package/dist/core/writer.js.map +1 -0
  19. package/dist/index.d.ts +7 -0
  20. package/dist/index.js +7 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/transformers/css.d.ts +2 -0
  23. package/dist/transformers/css.js +485 -0
  24. package/dist/transformers/css.js.map +1 -0
  25. package/dist/transformers/kotlin.d.ts +2 -0
  26. package/dist/transformers/kotlin.js +445 -0
  27. package/dist/transformers/kotlin.js.map +1 -0
  28. package/dist/transformers/swiftui.d.ts +2 -0
  29. package/dist/transformers/swiftui.js +436 -0
  30. package/dist/transformers/swiftui.js.map +1 -0
  31. package/dist/transformers/vue3.d.ts +28 -0
  32. package/dist/transformers/vue3.js +534 -0
  33. package/dist/transformers/vue3.js.map +1 -0
  34. package/dist/utils/color.d.ts +11 -0
  35. package/dist/utils/color.js +101 -0
  36. package/dist/utils/color.js.map +1 -0
  37. package/dist/utils/dimension.d.ts +7 -0
  38. package/dist/utils/dimension.js +62 -0
  39. package/dist/utils/dimension.js.map +1 -0
  40. package/dist/utils/naming.d.ts +13 -0
  41. package/dist/utils/naming.js +58 -0
  42. package/dist/utils/naming.js.map +1 -0
  43. package/package.json +40 -0
@@ -0,0 +1,124 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { loadTokens, groupTokensByFile } from "./loader.js";
4
+ import { transformCSS } from "../transformers/css.js";
5
+ import { transformSwiftUI } from "../transformers/swiftui.js";
6
+ import { transformKotlin } from "../transformers/kotlin.js";
7
+ export async function runTransform(config) {
8
+ const { tokens, collections, errors: loadErrors } = await loadTokens(config);
9
+ const results = [];
10
+ for (const [platform, platformConfig] of Object.entries(config.platforms)) {
11
+ if (!platformConfig)
12
+ continue;
13
+ const result = {
14
+ platform,
15
+ files: [],
16
+ tokenCount: 0,
17
+ errors: [...loadErrors],
18
+ };
19
+ try {
20
+ if (platformConfig.fileMapping && platformConfig.fileMapping.length > 0) {
21
+ result.files = buildMappedFiles(tokens, collections, platformConfig, platform);
22
+ }
23
+ else {
24
+ result.files = buildAutoFiles(tokens, collections, platformConfig, platform);
25
+ }
26
+ result.tokenCount = result.files.reduce((sum, f) => sum + f.tokenCount, 0);
27
+ }
28
+ catch (err) {
29
+ result.errors.push(`Transform error (${platform}): ${err}`);
30
+ }
31
+ results.push(result);
32
+ }
33
+ return results;
34
+ }
35
+ function buildMappedFiles(allTokens, _collections, config, platform) {
36
+ const files = [];
37
+ for (const mapping of config.fileMapping) {
38
+ const filtered = filterTokens(allTokens, mapping);
39
+ if (filtered.length === 0)
40
+ continue;
41
+ const content = transformTokens(filtered, config, platform, allTokens);
42
+ files.push({
43
+ path: path.join(config.outputDir, mapping.output),
44
+ content,
45
+ tokenCount: filtered.length,
46
+ });
47
+ }
48
+ return files;
49
+ }
50
+ function buildAutoFiles(allTokens, collections, config, platform) {
51
+ const files = [];
52
+ const groups = groupTokensByFile(allTokens, collections);
53
+ const ext = platformExtension(platform);
54
+ for (const [groupKey, tokens] of groups) {
55
+ const sanitized = groupKey
56
+ .replace(/\.json$/, "")
57
+ .replace(/[/\\]/g, path.sep);
58
+ const filePath = path.join(config.outputDir, `${sanitized}${ext}`);
59
+ const content = transformTokens(tokens, config, platform, allTokens);
60
+ files.push({
61
+ path: filePath,
62
+ content,
63
+ tokenCount: tokens.length,
64
+ });
65
+ }
66
+ return files;
67
+ }
68
+ function filterTokens(tokens, mapping) {
69
+ let filtered = tokens;
70
+ if (mapping.sources.length > 0) {
71
+ filtered = filtered.filter(t => mapping.sources.some(s => {
72
+ if (s.includes("*")) {
73
+ const regex = new RegExp("^" + s.replace(/\*/g, ".*") + "$");
74
+ return regex.test(t.sourceFile || "");
75
+ }
76
+ return (t.sourceFile || "") === s;
77
+ }));
78
+ }
79
+ if (mapping.filter) {
80
+ if (mapping.filter.types && mapping.filter.types.length > 0) {
81
+ filtered = filtered.filter(t => mapping.filter.types.includes(t.type));
82
+ }
83
+ if (mapping.filter.paths && mapping.filter.paths.length > 0) {
84
+ filtered = filtered.filter(t => mapping.filter.paths.some(p => t.path.startsWith(p)));
85
+ }
86
+ if (mapping.filter.excludePaths && mapping.filter.excludePaths.length > 0) {
87
+ filtered = filtered.filter(t => !mapping.filter.excludePaths.some(p => t.path.startsWith(p)));
88
+ }
89
+ }
90
+ return filtered;
91
+ }
92
+ function transformTokens(tokens, config, platform, allTokens) {
93
+ switch (platform) {
94
+ case "css": return transformCSS(tokens, config);
95
+ case "swiftui": return transformSwiftUI(tokens, config, allTokens);
96
+ case "kotlin": return transformKotlin(tokens, config, allTokens);
97
+ }
98
+ }
99
+ function platformExtension(platform) {
100
+ switch (platform) {
101
+ case "css": return ".css";
102
+ case "swiftui": return ".swift";
103
+ case "kotlin": return ".kt";
104
+ }
105
+ }
106
+ export function writeOutputFiles(results) {
107
+ let written = 0;
108
+ const errors = [];
109
+ for (const result of results) {
110
+ for (const file of result.files) {
111
+ try {
112
+ const dir = path.dirname(file.path);
113
+ fs.mkdirSync(dir, { recursive: true });
114
+ fs.writeFileSync(file.path, file.content, "utf-8");
115
+ written++;
116
+ }
117
+ catch (err) {
118
+ errors.push(`Failed to write ${file.path}: ${err}`);
119
+ }
120
+ }
121
+ }
122
+ return { written, errors };
123
+ }
124
+ //# sourceMappingURL=writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writer.js","sourceRoot":"","sources":["../../src/core/writer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export { runTransform, writeOutputFiles } from "./core/writer.js";
2
+ export { loadTokens } from "./core/loader.js";
3
+ export { parseTokenFile, buildValueMap, resolveAllAliases } from "./core/parser.js";
4
+ export { transformCSS } from "./transformers/css.js";
5
+ export { transformSwiftUI } from "./transformers/swiftui.js";
6
+ export { transformKotlin } from "./transformers/kotlin.js";
7
+ export type { TransformConfig, PlatformConfig, Platform, FlatToken, TransformResult, OutputFile, SourceConfig, FileMapping, TokenFilter, CodeSyntaxConfig, GlobalSettings, } from "./core/types.js";
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ export { runTransform, writeOutputFiles } from "./core/writer.js";
2
+ export { loadTokens } from "./core/loader.js";
3
+ export { parseTokenFile, buildValueMap, resolveAllAliases } from "./core/parser.js";
4
+ export { transformCSS } from "./transformers/css.js";
5
+ export { transformSwiftUI } from "./transformers/swiftui.js";
6
+ export { transformKotlin } from "./transformers/kotlin.js";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACpF,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { FlatToken, PlatformConfig } from "../core/types.js";
2
+ export declare function transformCSS(tokens: FlatToken[], config: PlatformConfig): string;
@@ -0,0 +1,485 @@
1
+ import { cssVarName, toKebabCase, resolveCodeSyntax } from "../utils/naming.js";
2
+ import { parseColor, rgbaToCSS } from "../utils/color.js";
3
+ import { toCssDimension } from "../utils/dimension.js";
4
+ let _currentPrefix;
5
+ let _resolveAliases = false;
6
+ let _splitEffects = true;
7
+ let _showDescriptions = true;
8
+ export function transformCSS(tokens, config) {
9
+ const prefix = config.prefix ?? config.codeSyntax?.prefix;
10
+ _currentPrefix = prefix;
11
+ _resolveAliases = config.resolveAliases ?? false;
12
+ _splitEffects = config.splitEffects ?? true;
13
+ _showDescriptions = config.showDescriptions ?? true;
14
+ const lines = [];
15
+ lines.push(":root {");
16
+ for (const token of tokens) {
17
+ const codeSyntaxWeb = getCodeSyntax(token, "Web");
18
+ const varName = codeSyntaxWeb
19
+ ? extractCssVarName(codeSyntaxWeb)
20
+ : cssVarName(token.path, prefix);
21
+ if (_showDescriptions && token.description) {
22
+ lines.push(` /* ${token.description} */`);
23
+ }
24
+ const isEffectsType = token.type === "effects" || token.type === "blur" || token.type === "backdrop-blur" || token.type === "glass";
25
+ const isPureAliasPreserve = token.isAlias && token.aliasPath && !_resolveAliases;
26
+ if (_splitEffects && isEffectsType && !isPureAliasPreserve) {
27
+ const decls = buildEffectsDeclarations(token, varName);
28
+ for (const d of decls) {
29
+ if (_showDescriptions && d.comment)
30
+ lines.push(` /* ${d.comment} */`);
31
+ lines.push(` ${d.name}: ${d.value};`);
32
+ }
33
+ }
34
+ else {
35
+ const value = resolveTokenValue(token);
36
+ lines.push(` ${varName}: ${value};`);
37
+ }
38
+ }
39
+ lines.push("}");
40
+ return lines.join("\n") + "\n";
41
+ }
42
+ function isAliasRef(val) {
43
+ return typeof val === "string" && /^\{[^{}]+\}$/.test(val.trim());
44
+ }
45
+ function aliasToVar(val) {
46
+ const ref = val.trim().slice(1, -1);
47
+ return `var(${cssVarName(ref, _currentPrefix)})`;
48
+ }
49
+ function cssField(rawVal, resolvedVal, formatter) {
50
+ if (!_resolveAliases && isAliasRef(rawVal))
51
+ return aliasToVar(rawVal);
52
+ const val = resolvedVal ?? rawVal;
53
+ if (formatter)
54
+ return formatter(val);
55
+ return stringifyValue(val);
56
+ }
57
+ function asObj(v) {
58
+ return (typeof v === "object" && v !== null && !Array.isArray(v))
59
+ ? v
60
+ : null;
61
+ }
62
+ function resolveTokenValue(token) {
63
+ if (token.isAlias && token.aliasPath && !_resolveAliases) {
64
+ return `var(${cssVarName(token.aliasPath, _currentPrefix)})`;
65
+ }
66
+ const raw = token.value;
67
+ const resolved = token.resolvedValue ?? token.value;
68
+ switch (token.type) {
69
+ case "color":
70
+ return formatCssColor(resolved);
71
+ case "dimension":
72
+ case "sizing":
73
+ case "spacing":
74
+ case "borderRadius":
75
+ case "borderWidth":
76
+ case "fontSize":
77
+ case "lineHeight":
78
+ case "letterSpacing":
79
+ case "paragraphSpacing":
80
+ case "paragraphIndent":
81
+ return toCssDimension(resolved);
82
+ case "opacity":
83
+ case "number":
84
+ return String(resolved);
85
+ case "fontFamily":
86
+ case "fontFamilies":
87
+ return typeof resolved === "string" ? resolved : String(resolved);
88
+ case "fontWeight":
89
+ case "fontWeights":
90
+ return formatFontWeight(resolved);
91
+ case "textCase":
92
+ return formatTextCase(resolved);
93
+ case "textDecoration":
94
+ return formatTextDecoration(resolved);
95
+ case "boolean":
96
+ return String(resolved);
97
+ case "text":
98
+ case "string":
99
+ return `"${String(resolved)}"`;
100
+ case "typography":
101
+ return formatCssTypography(raw, resolved);
102
+ case "shadow":
103
+ return formatCssShadow(raw, resolved);
104
+ case "border":
105
+ return formatCssBorder(raw, resolved);
106
+ case "fill":
107
+ return formatCssFill(raw, resolved);
108
+ case "gradient":
109
+ return formatCssGradient(raw, resolved);
110
+ case "fontStyle":
111
+ return formatCssFontStyle(resolved);
112
+ case "effects":
113
+ case "blur":
114
+ case "backdrop-blur":
115
+ return formatCssEffectsSingle(raw, resolved, token.type);
116
+ case "glass":
117
+ return formatCssGlass(raw, resolved);
118
+ case "transition":
119
+ return formatCssTransition(resolved);
120
+ case "grid":
121
+ return formatCssGrid(resolved);
122
+ case "duration":
123
+ return formatCssDuration(resolved);
124
+ case "cubicBezier":
125
+ return formatCubicBezier(resolved);
126
+ case "strokeStyle":
127
+ return formatStrokeStyle(resolved);
128
+ default:
129
+ return stringifyValue(resolved);
130
+ }
131
+ }
132
+ function formatCssColor(val) {
133
+ if (typeof val === "string") {
134
+ if (val.trim().toLowerCase() === "transparent")
135
+ return "transparent";
136
+ const parsed = parseColor(val);
137
+ return parsed ? rgbaToCSS(parsed) : val;
138
+ }
139
+ return stringifyValue(val);
140
+ }
141
+ function formatFontWeight(val) {
142
+ if (typeof val === "string") {
143
+ const weights = {
144
+ thin: "100", hairline: "100", ultralight: "100",
145
+ extralight: "200",
146
+ light: "300",
147
+ regular: "400", normal: "400",
148
+ medium: "500",
149
+ "semi-bold": "600", semibold: "600", demibold: "600",
150
+ bold: "700",
151
+ "extra-bold": "800", extrabold: "800",
152
+ black: "900", heavy: "900",
153
+ };
154
+ const lower = val.replace(/\s*italic\s*/i, "").trim().toLowerCase();
155
+ return weights[lower] ?? val;
156
+ }
157
+ return String(val);
158
+ }
159
+ function formatTextCase(val) {
160
+ const map = {
161
+ none: "none", uppercase: "uppercase",
162
+ lowercase: "lowercase", capitalize: "capitalize",
163
+ "small-caps": "small-caps",
164
+ };
165
+ return typeof val === "string" ? (map[val] ?? val) : String(val);
166
+ }
167
+ function formatTextDecoration(val) {
168
+ const map = {
169
+ none: "none", underline: "underline",
170
+ "line-through": "line-through",
171
+ "strike-through": "line-through",
172
+ strikethrough: "line-through",
173
+ };
174
+ return typeof val === "string" ? (map[val] ?? val) : String(val);
175
+ }
176
+ function formatCssTypography(raw, resolved) {
177
+ const src = asObj(raw);
178
+ const res = asObj(resolved);
179
+ if (!res)
180
+ return stringifyValue(resolved);
181
+ const family = cssField(src?.fontFamily, res.fontFamily, v => String(v ?? "sans-serif"));
182
+ const weight = cssField(src?.fontWeight, res.fontWeight, formatFontWeight);
183
+ const size = cssField(src?.fontSize, res.fontSize, toCssDimension);
184
+ const lh = cssField(src?.lineHeight, res.lineHeight, v => v ? toCssDimension(v) : "normal");
185
+ return `${weight} ${size}/${lh} ${family}`;
186
+ }
187
+ function formatCssShadow(raw, resolved) {
188
+ if (Array.isArray(raw)) {
189
+ const resArr = Array.isArray(resolved) ? resolved : raw;
190
+ return raw.map((s, i) => formatSingleShadow(s, resArr[i] ?? s)).join(", ");
191
+ }
192
+ return formatSingleShadow(raw, resolved);
193
+ }
194
+ function formatSingleShadow(raw, resolved) {
195
+ const src = asObj(raw);
196
+ const res = asObj(resolved);
197
+ if (!res)
198
+ return stringifyValue(resolved);
199
+ const isInner = String(res.type ?? src?.type) === "innerShadow";
200
+ const x = cssField(src?.offsetX, res.offsetX, v => toCssDimension(v ?? 0));
201
+ const y = cssField(src?.offsetY, res.offsetY, v => toCssDimension(v ?? 0));
202
+ const blur = cssField(src?.blur, res.blur, v => toCssDimension(v ?? 0));
203
+ const spread = cssField(src?.spread, res.spread, v => toCssDimension(v ?? 0));
204
+ const color = cssField(src?.color, res.color, v => formatCssColor(v ?? "rgba(0,0,0,0.1)"));
205
+ return `${isInner ? "inset " : ""}${x} ${y} ${blur} ${spread} ${color}`;
206
+ }
207
+ function formatCssBorder(raw, resolved) {
208
+ const src = asObj(raw);
209
+ const res = asObj(resolved);
210
+ if (!res)
211
+ return stringifyValue(resolved);
212
+ const width = cssField(src?.width, res.width, v => toCssDimension(v ?? "1px"));
213
+ const style = cssField(src?.style, res.style, v => String(v ?? "solid"));
214
+ const color = cssField(src?.color, res.color, v => formatCssColor(v ?? "#000"));
215
+ return `${width} ${style} ${color}`;
216
+ }
217
+ function formatCssFill(raw, resolved) {
218
+ if (typeof raw === "string") {
219
+ if (!_resolveAliases && isAliasRef(raw))
220
+ return aliasToVar(raw);
221
+ return formatCssColor(resolved);
222
+ }
223
+ if (Array.isArray(raw)) {
224
+ const res = Array.isArray(resolved) ? resolved : raw;
225
+ const layers = raw.map((layer, i) => formatFillLayer(layer, res[i])).filter(Boolean);
226
+ return layers.join(", ") || "transparent";
227
+ }
228
+ if (typeof raw === "object" && raw !== null) {
229
+ return formatFillLayer(raw, resolved) || "transparent";
230
+ }
231
+ return stringifyValue(resolved);
232
+ }
233
+ function formatFillLayer(rawLayer, resolvedLayer) {
234
+ if (typeof rawLayer === "string") {
235
+ if (!_resolveAliases && isAliasRef(rawLayer))
236
+ return aliasToVar(rawLayer);
237
+ return formatCssColor(resolvedLayer ?? rawLayer);
238
+ }
239
+ if (typeof rawLayer !== "object" || rawLayer === null)
240
+ return "";
241
+ const rl = rawLayer;
242
+ const rs = asObj(resolvedLayer) ?? rl;
243
+ if (rl.type === "solid")
244
+ return cssField(rl.color, rs.color, formatCssColor);
245
+ if (rl.type === "gradient" && rl.gradient) {
246
+ return formatCssGradient(rl.gradient, rs.gradient ?? rl.gradient);
247
+ }
248
+ if (rl.type === "image")
249
+ return `url(${rl.imageUrl})`;
250
+ if (rl.color)
251
+ return cssField(rl.color, rs.color, formatCssColor);
252
+ return stringifyValue(resolvedLayer);
253
+ }
254
+ function formatCssGradient(raw, resolved) {
255
+ const src = asObj(raw);
256
+ const res = asObj(resolved ?? raw);
257
+ if (!res)
258
+ return stringifyValue(resolved ?? raw);
259
+ const type = String(res.type ?? src?.type ?? "linear");
260
+ const rawStops = (src?.stops ?? res.stops);
261
+ const resStops = (res.stops ?? rawStops);
262
+ const stops = rawStops ?? [];
263
+ const stopStr = stops.map((s, i) => {
264
+ const rs = resStops?.[i] ?? s;
265
+ const color = cssField(s.color, rs.color, v => formatCssColor(v ?? rs.color));
266
+ const pos = (rs.position ?? s.position) !== undefined
267
+ ? ` ${(rs.position ?? s.position) * 100}%` : "";
268
+ return `${color}${pos}`;
269
+ }).join(", ");
270
+ switch (type) {
271
+ case "linear": {
272
+ const angle = res.angle !== undefined ? `${res.angle}deg, ` : "";
273
+ return `linear-gradient(${angle}${stopStr})`;
274
+ }
275
+ case "radial":
276
+ return `radial-gradient(${stopStr})`;
277
+ case "angular":
278
+ case "diamond":
279
+ return `conic-gradient(${stopStr})`;
280
+ default:
281
+ return `linear-gradient(${stopStr})`;
282
+ }
283
+ }
284
+ function buildEffectsDeclarations(token, baseName) {
285
+ const raw = token.value;
286
+ const resolved = token.resolvedValue ?? token.value;
287
+ if (token.type === "blur") {
288
+ return [{ name: baseName, value: formatBlurValue(raw, resolved), comment: "filter" }];
289
+ }
290
+ if (token.type === "backdrop-blur") {
291
+ return [{ name: baseName, value: formatBlurValue(raw, resolved), comment: "backdrop-filter" }];
292
+ }
293
+ if (token.type === "glass") {
294
+ const res = asObj(resolved) ?? asObj(raw);
295
+ const radius = res?.radius ?? 8;
296
+ return [
297
+ { name: baseName, value: `blur(${radius}px)`, comment: "backdrop-filter (glass)" },
298
+ { name: `${baseName}-refraction`, value: String(res?.refraction ?? 0.2) },
299
+ { name: `${baseName}-depth`, value: String(res?.depth ?? 12) },
300
+ { name: `${baseName}-dispersion`, value: String(res?.dispersion ?? 0.1) },
301
+ { name: `${baseName}-light-intensity`, value: String(res?.lightIntensity ?? 0.3) },
302
+ { name: `${baseName}-light-angle`, value: `${res?.lightAngle ?? 45}deg` },
303
+ ];
304
+ }
305
+ const items = Array.isArray(raw) ? raw : [raw];
306
+ const resItems = Array.isArray(resolved) ? resolved : [resolved];
307
+ const shadows = [];
308
+ const filterParts = [];
309
+ const backdropParts = [];
310
+ for (let i = 0; i < items.length; i++) {
311
+ const e = asObj(items[i]);
312
+ const r = asObj(resItems[i]) ?? e;
313
+ if (!e && !r)
314
+ continue;
315
+ const rawObj = e ?? r;
316
+ const resObj = r ?? e;
317
+ const t = String(rawObj.type ?? resObj.type ?? "");
318
+ if (t === "dropShadow" || t === "innerShadow") {
319
+ shadows.push(formatSingleShadow(rawObj, resObj));
320
+ }
321
+ else if (t === "layerBlur") {
322
+ const radius = cssField(rawObj.radius, resObj.radius, v => toCssDimension(v ?? 0));
323
+ filterParts.push(`blur(${radius})`);
324
+ }
325
+ else if (t === "backgroundBlur") {
326
+ const radius = cssField(rawObj.radius, resObj.radius, v => toCssDimension(v ?? 0));
327
+ backdropParts.push(`blur(${radius})`);
328
+ }
329
+ }
330
+ const decls = [];
331
+ const hasShadows = shadows.length > 0;
332
+ const hasFilter = filterParts.length > 0;
333
+ const hasBackdrop = backdropParts.length > 0;
334
+ if (hasShadows) {
335
+ decls.push({ name: baseName, value: shadows.join(", "), comment: "box-shadow" });
336
+ }
337
+ if (hasFilter) {
338
+ const name = hasShadows || hasBackdrop ? `${baseName}-blur` : baseName;
339
+ decls.push({ name, value: filterParts.join(" "), comment: "filter" });
340
+ }
341
+ if (hasBackdrop) {
342
+ const name = hasShadows || hasFilter ? `${baseName}-backdrop-blur` : baseName;
343
+ decls.push({ name, value: backdropParts.join(" "), comment: "backdrop-filter" });
344
+ }
345
+ if (decls.length === 0) {
346
+ decls.push({ name: baseName, value: "none" });
347
+ }
348
+ return decls;
349
+ }
350
+ function formatBlurValue(raw, resolved) {
351
+ const src = asObj(raw);
352
+ const res = asObj(resolved);
353
+ const obj = res ?? src;
354
+ if (!obj)
355
+ return stringifyValue(resolved);
356
+ const radius = cssField(src?.blur ?? src?.radius, obj.blur ?? obj.radius, v => toCssDimension(v ?? 0));
357
+ return `blur(${radius})`;
358
+ }
359
+ function formatCssEffectsSingle(raw, resolved, type) {
360
+ if (type === "blur" || type === "backdrop-blur") {
361
+ return formatBlurValue(raw, resolved);
362
+ }
363
+ if (Array.isArray(raw)) {
364
+ const resArr = Array.isArray(resolved) ? resolved : raw;
365
+ const shadows = [];
366
+ for (let i = 0; i < raw.length; i++) {
367
+ const e = asObj(raw[i]);
368
+ const r = asObj(resArr[i]) ?? e;
369
+ if (!e && !r)
370
+ continue;
371
+ const rawObj = e ?? r;
372
+ const resObj = r ?? e;
373
+ const t = String(rawObj.type ?? resObj.type ?? "");
374
+ if (t === "dropShadow" || t === "innerShadow") {
375
+ shadows.push(formatSingleShadow(rawObj, resObj));
376
+ }
377
+ }
378
+ return shadows.join(", ") || "none";
379
+ }
380
+ if (typeof raw === "object" && raw !== null) {
381
+ const e = raw;
382
+ const r = asObj(resolved) ?? e;
383
+ const t = String(e.type ?? r.type);
384
+ if (t === "dropShadow" || t === "innerShadow")
385
+ return formatSingleShadow(raw, resolved);
386
+ if (t === "backgroundBlur" || t === "layerBlur")
387
+ return formatBlurValue(raw, resolved);
388
+ }
389
+ return stringifyValue(resolved);
390
+ }
391
+ function formatCssTransition(val) {
392
+ if (typeof val !== "object" || val === null)
393
+ return stringifyValue(val);
394
+ const t = val;
395
+ const duration = t.duration ? formatCssDuration(t.duration) : "0ms";
396
+ const easing = t.timingFunction ?? t.easing ?? "ease";
397
+ const delay = t.delay ? formatCssDuration(t.delay) : "";
398
+ return `all ${duration} ${easing}${delay ? " " + delay : ""}`;
399
+ }
400
+ function formatCssDuration(val) {
401
+ if (typeof val === "number")
402
+ return `${val}ms`;
403
+ if (typeof val === "string") {
404
+ if (/^\d+$/.test(val.trim()))
405
+ return `${val}ms`;
406
+ return val;
407
+ }
408
+ return String(val);
409
+ }
410
+ function formatCubicBezier(val) {
411
+ if (Array.isArray(val) && val.length === 4) {
412
+ return `cubic-bezier(${val.join(", ")})`;
413
+ }
414
+ return stringifyValue(val);
415
+ }
416
+ function formatStrokeStyle(val) {
417
+ if (typeof val === "string")
418
+ return val;
419
+ if (typeof val === "object" && val !== null) {
420
+ const s = val;
421
+ if (s.dashArray && Array.isArray(s.dashArray)) {
422
+ const dashStr = s.dashArray.join(" ");
423
+ const cap = s.lineCap ? ` /* lineCap: ${s.lineCap} */` : "";
424
+ return `dashed /* dashArray: ${dashStr}${cap} */`;
425
+ }
426
+ }
427
+ return stringifyValue(val);
428
+ }
429
+ function formatCssFontStyle(val) {
430
+ if (typeof val === "string") {
431
+ const lower = val.toLowerCase().trim();
432
+ if (lower === "italic" || lower === "oblique")
433
+ return lower;
434
+ if (lower === "normal" || lower === "regular")
435
+ return "normal";
436
+ return lower;
437
+ }
438
+ return "normal";
439
+ }
440
+ function formatCssGlass(raw, resolved) {
441
+ const src = asObj(raw);
442
+ const res = asObj(resolved ?? raw);
443
+ if (!res)
444
+ return stringifyValue(resolved ?? raw);
445
+ const radius = res.radius ?? src?.radius ?? 8;
446
+ const refraction = res.refraction ?? src?.refraction ?? 0.2;
447
+ const depth = res.depth ?? src?.depth ?? 12;
448
+ const dispersion = res.dispersion ?? src?.dispersion ?? 0.1;
449
+ const lightIntensity = res.lightIntensity ?? src?.lightIntensity ?? 0.3;
450
+ const lightAngle = res.lightAngle ?? src?.lightAngle ?? 45;
451
+ return `blur(${radius}px) /* glass: refraction=${refraction} depth=${depth} dispersion=${dispersion} light=${lightIntensity}@${lightAngle}deg */`;
452
+ }
453
+ function formatCssGrid(val) {
454
+ if (typeof val !== "object" || val === null)
455
+ return stringifyValue(val);
456
+ const g = val;
457
+ const columns = g.columns ?? g.count ?? "auto";
458
+ const gap = g.gap ? toCssDimension(g.gap) : "0";
459
+ return `repeat(${columns}, 1fr) /* gap: ${gap} */`;
460
+ }
461
+ function getCodeSyntax(token, platform) {
462
+ const cs = token.extensions?.["figma.codeSyntax"];
463
+ if (!cs?.[platform])
464
+ return undefined;
465
+ return resolveCodeSyntax(cs[platform], token.path);
466
+ }
467
+ function extractCssVarName(cssSyntax) {
468
+ const match = cssSyntax.match(/var\(\s*(--[^)]+)\s*\)/);
469
+ return match ? match[1] : `--${toKebabCase(cssSyntax)}`;
470
+ }
471
+ function stringifyValue(val) {
472
+ if (val === null || val === undefined)
473
+ return "none";
474
+ if (typeof val === "string")
475
+ return val;
476
+ if (typeof val === "number" || typeof val === "boolean")
477
+ return String(val);
478
+ try {
479
+ return JSON.stringify(val);
480
+ }
481
+ catch {
482
+ return String(val);
483
+ }
484
+ }
485
+ //# sourceMappingURL=css.js.map