@terrazzo/plugin-css 2.4.0 → 2.6.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/CHANGELOG.md +19 -0
- package/dist/build.d.ts +19 -0
- package/dist/build.d.ts.map +1 -0
- package/dist/build.js +402 -0
- package/dist/build.js.map +1 -0
- package/dist/index.d.ts +7 -172
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +49 -744
- package/dist/index.js.map +1 -1
- package/dist/lib.d.ts +150 -0
- package/dist/lib.d.ts.map +1 -0
- package/dist/lib.js +129 -0
- package/dist/lib.js.map +1 -0
- package/dist/transform.d.ts +8 -0
- package/dist/transform.d.ts.map +1 -0
- package/dist/transform.js +139 -0
- package/dist/transform.js.map +1 -0
- package/dist/utility-css.d.ts +6 -0
- package/dist/utility-css.d.ts.map +1 -0
- package/dist/utility-css.js +198 -0
- package/dist/utility-css.js.map +1 -0
- package/package.json +11 -12
package/dist/index.js
CHANGED
|
@@ -1,746 +1,51 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
1
|
+
import buildCSS from './build.js';
|
|
2
|
+
import { FILE_PREFIX, PLUGIN_NAME } from './lib.js';
|
|
3
|
+
import transformCSS from './transform.js';
|
|
4
|
+
export * from './build.js';
|
|
5
|
+
export { FILE_PREFIX, FORMAT_ID, PLUGIN_NAME, printNode, printRules, } from './lib.js';
|
|
6
|
+
export * from './transform.js';
|
|
7
|
+
export * from './utility-css.js';
|
|
8
|
+
/* oxlint-disable require-await */
|
|
9
|
+
export default function cssPlugin(options) {
|
|
10
|
+
const { utility, skipBuild, baseScheme, propertyDefinitions } = options ?? {};
|
|
11
|
+
const filename = options?.filename ?? options?.fileName ?? 'index.css';
|
|
12
|
+
const baseSelector = options?.baseSelector ?? ':root';
|
|
13
|
+
return {
|
|
14
|
+
name: PLUGIN_NAME,
|
|
15
|
+
config(_config, context) {
|
|
16
|
+
if (options?.permutations &&
|
|
17
|
+
(options?.modeSelectors || options?.baseSelector || options?.baseScheme)) {
|
|
18
|
+
context.logger.error({
|
|
19
|
+
group: 'plugin',
|
|
20
|
+
label: PLUGIN_NAME,
|
|
21
|
+
message: 'Permutations option is incompatible with modeSelectors, baseSelector, and baseScheme.',
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
async transform(transformOptions) {
|
|
26
|
+
transformCSS({ transform: transformOptions, options: options ?? {} });
|
|
27
|
+
},
|
|
28
|
+
async build({ getTransforms, outputFile, context }) {
|
|
29
|
+
if (skipBuild === true) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
let contents = `${FILE_PREFIX}\n\n`;
|
|
33
|
+
contents += buildCSS({
|
|
34
|
+
include: options?.include,
|
|
35
|
+
exclude: options?.exclude,
|
|
36
|
+
getTransforms,
|
|
37
|
+
permutations: options?.permutations,
|
|
38
|
+
modeSelectors: options?.modeSelectors,
|
|
39
|
+
utility,
|
|
40
|
+
baseSelector,
|
|
41
|
+
baseScheme,
|
|
42
|
+
propertyDefinitions: propertyDefinitions ?? false,
|
|
43
|
+
logger: context.logger,
|
|
44
|
+
omitTypographyShorthand: options?.omitTypographyShorthand,
|
|
45
|
+
subValueVariableName: options?.subValueVariableName,
|
|
46
|
+
});
|
|
47
|
+
outputFile(filename, contents.replace(/\n*$/, '\n'));
|
|
48
|
+
},
|
|
49
|
+
};
|
|
38
50
|
}
|
|
39
|
-
/** Internal printer for individual nodes */
|
|
40
|
-
function printNode(node, { indentChar, indentLv }) {
|
|
41
|
-
let output = "";
|
|
42
|
-
const indent = indentChar.repeat(indentLv);
|
|
43
|
-
if (node.type === "Declaration") {
|
|
44
|
-
if (node.comment) output += `${indent}/* ${node.comment} */\n`;
|
|
45
|
-
output += `${indent}${node.property}: ${node.value};\n`;
|
|
46
|
-
return output;
|
|
47
|
-
}
|
|
48
|
-
if (!node.prelude.length || !node.children.length) return output;
|
|
49
|
-
const mediaQueryWithDecls = node.children.some((s) => s.type === "Declaration") ? node.prelude.find((s) => s.startsWith("@media")) : void 0;
|
|
50
|
-
if (mediaQueryWithDecls) {
|
|
51
|
-
const nonMedia = node.prelude.filter((s) => s !== mediaQueryWithDecls);
|
|
52
|
-
output += `${indent}${mediaQueryWithDecls} {\n`;
|
|
53
|
-
output += printNode(rule([":root"], node.children), {
|
|
54
|
-
indentChar,
|
|
55
|
-
indentLv: indentLv + 1
|
|
56
|
-
});
|
|
57
|
-
output += `${indent}}\n\n`;
|
|
58
|
-
output += printNode(rule(nonMedia, node.children), {
|
|
59
|
-
indentChar,
|
|
60
|
-
indentLv
|
|
61
|
-
});
|
|
62
|
-
return output;
|
|
63
|
-
}
|
|
64
|
-
let childOutput = "";
|
|
65
|
-
for (const child of node.children) childOutput += printNode(child, {
|
|
66
|
-
indentChar,
|
|
67
|
-
indentLv: indentLv + 1
|
|
68
|
-
});
|
|
69
|
-
childOutput = childOutput.trim();
|
|
70
|
-
if (!childOutput) return output;
|
|
71
|
-
output += `${indent}${node.prelude.join(", ")} {\n`;
|
|
72
|
-
output += `${indentChar.repeat(indentLv + 1)}${childOutput}\n`;
|
|
73
|
-
output += `${indent}}\n`;
|
|
74
|
-
return output;
|
|
75
|
-
}
|
|
76
|
-
/** Infer indentation preferences from a user-defined wrapping method. */
|
|
77
|
-
function getIndentFromPrepare(prepare) {
|
|
78
|
-
const str = "//css//";
|
|
79
|
-
const output = prepare(str).replace(/\/\*.*\*\//g, "");
|
|
80
|
-
let indentChar = " ";
|
|
81
|
-
let indentLv = 0;
|
|
82
|
-
let lineStartChar = 0;
|
|
83
|
-
for (let i = 0; i < output.length; i++) if (output[i] === "{") {
|
|
84
|
-
lineStartChar = i + 1;
|
|
85
|
-
indentLv++;
|
|
86
|
-
} else if (output[i] === "}") indentLv--;
|
|
87
|
-
else if (output[i] === "\n") lineStartChar = i + 1;
|
|
88
|
-
else if (output[i] === str[0] && output.slice(i).startsWith(str)) {
|
|
89
|
-
indentChar = output.slice(lineStartChar, i);
|
|
90
|
-
indentChar = indentChar.slice(0, Math.floor(indentChar.length / indentLv));
|
|
91
|
-
break;
|
|
92
|
-
}
|
|
93
|
-
return {
|
|
94
|
-
indentChar: indentChar || " ",
|
|
95
|
-
indentLv
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
/** Syntactic sugar over Rule boilerplate */
|
|
99
|
-
function rule(prelude, children = []) {
|
|
100
|
-
return {
|
|
101
|
-
type: "Rule",
|
|
102
|
-
prelude,
|
|
103
|
-
children
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
/** Syntactic sugar over Declaration boilerplate */
|
|
107
|
-
function decl(property, value, comment) {
|
|
108
|
-
return {
|
|
109
|
-
type: "Declaration",
|
|
110
|
-
property,
|
|
111
|
-
value,
|
|
112
|
-
comment
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
/** Does a node list contain a root-level declaration with this property? */
|
|
116
|
-
function hasDecl(list, property) {
|
|
117
|
-
return list.some((d) => d.type === "Declaration" && d.property === property);
|
|
118
|
-
}
|
|
119
|
-
/** Add a declaration only if it’s unique (note: CSS, by design, allows duplication—it’s how fallbacks happen. Only use this if fallbacks aren’t needed. */
|
|
120
|
-
function addDeclUnique(list, declaration) {
|
|
121
|
-
if (!hasDecl(list, declaration.property)) list.push(declaration);
|
|
122
|
-
}
|
|
123
|
-
//#endregion
|
|
124
|
-
//#region src/utility-css.ts
|
|
125
|
-
const GROUP_REGEX = {
|
|
126
|
-
bg: /(^bg-|-bg-)/,
|
|
127
|
-
border: /(^border-|-border-)/,
|
|
128
|
-
font: /(^font-|-font-)/,
|
|
129
|
-
gap: /(^gap-|-gap-)/,
|
|
130
|
-
m: /(^margin-|-margin-|)/,
|
|
131
|
-
p: /(^padding-|-padding-|)/,
|
|
132
|
-
shadow: /(^shadow-|-shadow-)/,
|
|
133
|
-
text: /(^text-|-text-)/
|
|
134
|
-
};
|
|
135
|
-
/** Make CSS class name from transformed token */
|
|
136
|
-
function makePrelude(token, prefix, subgroup) {
|
|
137
|
-
return [`.${prefix}${subgroup || ""}-${kebabCase(token.token.id).replace(GROUP_REGEX[prefix], "")}`];
|
|
138
|
-
}
|
|
139
|
-
function makeVarValue(token) {
|
|
140
|
-
return makeCSSVar(token.localID ?? token.token.id, { wrapVar: true });
|
|
141
|
-
}
|
|
142
|
-
const utilityMatcher = new CachedWildcardMatcher();
|
|
143
|
-
function generateUtilityCSS(groups, tokens, { logger }) {
|
|
144
|
-
const root = [];
|
|
145
|
-
const groupEntries = Object.entries(groups);
|
|
146
|
-
groupEntries.sort((a, b) => a[0].localeCompare(b[0]));
|
|
147
|
-
for (const [group, selectors] of groupEntries) {
|
|
148
|
-
const selectorMatcher = utilityMatcher.match(selectors);
|
|
149
|
-
const matchingTokens = tokens.filter((token) => selectorMatcher(token.token.id));
|
|
150
|
-
if (!matchingTokens.length) {
|
|
151
|
-
logger.warn({
|
|
152
|
-
group: "plugin",
|
|
153
|
-
label: PLUGIN_NAME,
|
|
154
|
-
message: `utility group "${group}" matched 0 tokens: ${JSON.stringify(selectors)}`
|
|
155
|
-
});
|
|
156
|
-
break;
|
|
157
|
-
}
|
|
158
|
-
switch (group) {
|
|
159
|
-
case "bg":
|
|
160
|
-
for (const token of matchingTokens) {
|
|
161
|
-
const prelude = makePrelude(token, "bg");
|
|
162
|
-
switch (token.token.$type) {
|
|
163
|
-
case "color":
|
|
164
|
-
root.push(rule(prelude, [decl("background-color", makeVarValue(token))]));
|
|
165
|
-
break;
|
|
166
|
-
case "gradient": {
|
|
167
|
-
const value = decl("background-image", `linear-gradient(${makeCSSVar(token.localID ?? token.token.id, { wrapVar: true })})`);
|
|
168
|
-
root.push(rule(prelude, [value]));
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
break;
|
|
173
|
-
case "border":
|
|
174
|
-
for (const token of matchingTokens) {
|
|
175
|
-
const property = {
|
|
176
|
-
border: "border",
|
|
177
|
-
color: "border-color",
|
|
178
|
-
dimension: "border-width",
|
|
179
|
-
strokeStyle: "border-style"
|
|
180
|
-
}[token.token.$type];
|
|
181
|
-
if (property) root.push(rule(makePrelude(token, "border"), [decl(property, makeVarValue(token))]));
|
|
182
|
-
}
|
|
183
|
-
for (const token of matchingTokens) for (const side of [
|
|
184
|
-
"top",
|
|
185
|
-
"right",
|
|
186
|
-
"bottom",
|
|
187
|
-
"left"
|
|
188
|
-
]) {
|
|
189
|
-
const property = {
|
|
190
|
-
border: `border-${side}`,
|
|
191
|
-
color: `border-${side}-color`,
|
|
192
|
-
dimension: `border-${side}-width`,
|
|
193
|
-
strokeStyle: `border-${side}-style`
|
|
194
|
-
}[token.token.$type];
|
|
195
|
-
if (property) root.push(rule(makePrelude(token, "border", `-${side}`), [decl(property, makeVarValue(token))]));
|
|
196
|
-
}
|
|
197
|
-
break;
|
|
198
|
-
case "font":
|
|
199
|
-
for (const token of matchingTokens) {
|
|
200
|
-
const prelude = makePrelude(token, "font");
|
|
201
|
-
if (token.token.$type === "typography" && token.type === "MULTI_VALUE") {
|
|
202
|
-
const value = Object.keys(token.value).map((property) => decl(property, makeCSSVar(`${token.localID ?? token.token.id}-${property}`, { wrapVar: true })));
|
|
203
|
-
root.push(rule(prelude, value));
|
|
204
|
-
} else {
|
|
205
|
-
const property = {
|
|
206
|
-
dimension: "font-size",
|
|
207
|
-
fontFamily: "font-family",
|
|
208
|
-
fontWeight: "font-weight"
|
|
209
|
-
}[token.token.$type];
|
|
210
|
-
if (property) root.push(rule(prelude, [decl(property, makeVarValue(token))]));
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
break;
|
|
214
|
-
case "layout": {
|
|
215
|
-
const filteredTokens = matchingTokens.filter((t) => t.token.$type === "dimension");
|
|
216
|
-
for (const token of filteredTokens) root.push(rule(makePrelude(token, "gap"), [decl("gap", makeVarValue(token))]));
|
|
217
|
-
for (const token of filteredTokens) root.push(rule(makePrelude(token, "gap", "-col"), [decl("column-gap", makeVarValue(token))]));
|
|
218
|
-
for (const token of filteredTokens) root.push(rule(makePrelude(token, "gap", "-row"), [decl("row-gap", makeVarValue(token))]));
|
|
219
|
-
for (const prefix of ["m", "p"]) {
|
|
220
|
-
const property = prefix === "m" ? "margin" : "padding";
|
|
221
|
-
for (const token of filteredTokens) root.push(rule(makePrelude(token, prefix, "a"), [decl(property, makeVarValue(token))]));
|
|
222
|
-
for (const token of filteredTokens) {
|
|
223
|
-
const value = makeVarValue(token);
|
|
224
|
-
root.push(rule(makePrelude(token, prefix, "x"), [
|
|
225
|
-
decl(`${property}-inline`, value),
|
|
226
|
-
decl(`${property}-left`, value),
|
|
227
|
-
decl(`${property}-right`, value)
|
|
228
|
-
]), rule(makePrelude(token, prefix, "y"), [
|
|
229
|
-
decl(`${property}-block`, value),
|
|
230
|
-
decl(`${property}-bottom`, value),
|
|
231
|
-
decl(`${property}-top`, value)
|
|
232
|
-
]));
|
|
233
|
-
}
|
|
234
|
-
for (const side of [
|
|
235
|
-
"top",
|
|
236
|
-
"right",
|
|
237
|
-
"bottom",
|
|
238
|
-
"left"
|
|
239
|
-
]) for (const token of filteredTokens) root.push(rule(makePrelude(token, prefix, side[0]), [decl(`${property}-${side}`, makeVarValue(token))]));
|
|
240
|
-
for (const token of filteredTokens) {
|
|
241
|
-
const value = makeVarValue(token);
|
|
242
|
-
root.push(rule(makePrelude(token, prefix, "bs"), [decl(`${property}-block-start`, value)]), rule(makePrelude(token, prefix, "be"), [decl(`${property}-block-end`, value)]), rule(makePrelude(token, prefix, "is"), [decl(`${property}-inline-start`, value)]), rule(makePrelude(token, prefix, "ie"), [decl(`${property}-inline-end`, value)]));
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
break;
|
|
246
|
-
}
|
|
247
|
-
case "shadow":
|
|
248
|
-
for (const token of matchingTokens) if (token.token.$type === "shadow") root.push(rule(makePrelude(token, "shadow"), [decl("box-shadow", makeVarValue(token))]));
|
|
249
|
-
break;
|
|
250
|
-
case "text":
|
|
251
|
-
for (const token of matchingTokens) {
|
|
252
|
-
const prelude = makePrelude(token, "text");
|
|
253
|
-
const value = makeVarValue(token);
|
|
254
|
-
switch (token.token.$type) {
|
|
255
|
-
case "color":
|
|
256
|
-
root.push(rule(prelude, [decl("color", value)]));
|
|
257
|
-
break;
|
|
258
|
-
case "gradient":
|
|
259
|
-
root.push(rule(prelude, [
|
|
260
|
-
decl("background", `-webkit-linear-gradient(${value})`),
|
|
261
|
-
decl("-webkit-background-clip", "text"),
|
|
262
|
-
decl("-webkit-text-fill-color", "transparent")
|
|
263
|
-
]));
|
|
264
|
-
break;
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
break;
|
|
268
|
-
default:
|
|
269
|
-
logger.warn({
|
|
270
|
-
group: "plugin",
|
|
271
|
-
label: PLUGIN_NAME,
|
|
272
|
-
message: `unknown utility CSS group "${group}", ignoring`
|
|
273
|
-
});
|
|
274
|
-
break;
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
return root;
|
|
278
|
-
}
|
|
279
|
-
//#endregion
|
|
280
|
-
//#region src/build.ts
|
|
281
|
-
const P3_MQ = "@media (color-gamut: p3)";
|
|
282
|
-
const REC2020_MQ = "@media (color-gamut: rec2020)";
|
|
283
|
-
/**
|
|
284
|
-
* Get description from metadata with fallback to token.$description
|
|
285
|
-
* Preserves the descriptions and alias descriptions.
|
|
286
|
-
*/
|
|
287
|
-
function getDescription(token) {
|
|
288
|
-
return token.meta?.["plugin-css"]?.description ?? token.token.$description;
|
|
289
|
-
}
|
|
290
|
-
const TOKEN_TYPE_SYNTAX = {
|
|
291
|
-
color: "<color>",
|
|
292
|
-
dimension: "<length>",
|
|
293
|
-
duration: "<time>",
|
|
294
|
-
fontWeight: "<integer>",
|
|
295
|
-
number: "<number>",
|
|
296
|
-
boolean: "<integer>",
|
|
297
|
-
fontFamily: "*",
|
|
298
|
-
string: "*",
|
|
299
|
-
cubicBezier: "*",
|
|
300
|
-
border: "*",
|
|
301
|
-
shadow: "*",
|
|
302
|
-
gradient: "*",
|
|
303
|
-
typography: "*",
|
|
304
|
-
transition: "*",
|
|
305
|
-
strokeStyle: "*",
|
|
306
|
-
link: "<url>"
|
|
307
|
-
};
|
|
308
|
-
const SUB_PROPERTY_SYNTAX = {
|
|
309
|
-
border: {
|
|
310
|
-
color: "<color>",
|
|
311
|
-
width: "<length>",
|
|
312
|
-
style: "*"
|
|
313
|
-
},
|
|
314
|
-
shadow: {
|
|
315
|
-
color: "<color>",
|
|
316
|
-
"offset-x": "<length>",
|
|
317
|
-
"offset-y": "<length>",
|
|
318
|
-
blur: "<length>",
|
|
319
|
-
spread: "<length>"
|
|
320
|
-
},
|
|
321
|
-
transition: {
|
|
322
|
-
duration: "<time>",
|
|
323
|
-
delay: "<time>",
|
|
324
|
-
"timing-function": "*"
|
|
325
|
-
},
|
|
326
|
-
typography: {
|
|
327
|
-
"font-family": "*",
|
|
328
|
-
"font-size": "<length>",
|
|
329
|
-
"font-weight": "<integer>",
|
|
330
|
-
"line-height": "*",
|
|
331
|
-
"letter-spacing": "<length>",
|
|
332
|
-
"font-style": "*",
|
|
333
|
-
"font-variant": "*",
|
|
334
|
-
"font-variation-settings": "*",
|
|
335
|
-
"text-decoration": "*",
|
|
336
|
-
"text-transform": "*"
|
|
337
|
-
},
|
|
338
|
-
strokeStyle: {
|
|
339
|
-
"dash-array": "*",
|
|
340
|
-
"line-cap": "*"
|
|
341
|
-
}
|
|
342
|
-
};
|
|
343
|
-
function generatePropertyDefinition(localID, syntax, initialValue) {
|
|
344
|
-
const children = [decl("syntax", `'${syntax}'`), decl("inherits", "true")];
|
|
345
|
-
if (initialValue) children.push(decl("initial-value", initialValue));
|
|
346
|
-
return rule([`@property ${localID}`], children);
|
|
347
|
-
}
|
|
348
|
-
function generatePropertyDefinitions(getTransforms, options) {
|
|
349
|
-
const tokens = getTransforms({ format: "css" });
|
|
350
|
-
const properties = [];
|
|
351
|
-
const seen = /* @__PURE__ */ new Set();
|
|
352
|
-
for (const token of tokens) {
|
|
353
|
-
const localID = token.localID;
|
|
354
|
-
if (!localID) continue;
|
|
355
|
-
if (!options.include(token.token.id) || options.exclude(token.token.id)) continue;
|
|
356
|
-
const cssSyntax = TOKEN_TYPE_SYNTAX[token.token.$type] ?? "*";
|
|
357
|
-
if (token.type === "SINGLE_VALUE") {
|
|
358
|
-
if (seen.has(localID)) continue;
|
|
359
|
-
seen.add(localID);
|
|
360
|
-
if (!token.token.aliasOf && cssSyntax !== "*") properties.push(generatePropertyDefinition(localID, cssSyntax, token.value));
|
|
361
|
-
else properties.push(generatePropertyDefinition(localID, "*"));
|
|
362
|
-
} else if (token.type === "MULTI_VALUE") {
|
|
363
|
-
for (const [name, subValue] of Object.entries(token.value)) {
|
|
364
|
-
const subID = name === "." ? localID : `${localID}-${name}`;
|
|
365
|
-
if (seen.has(subID)) continue;
|
|
366
|
-
seen.add(subID);
|
|
367
|
-
const subSyntax = SUB_PROPERTY_SYNTAX[token.token.$type]?.[name] ?? "*";
|
|
368
|
-
if (!token.token.aliasOf && subSyntax !== "*") properties.push(generatePropertyDefinition(subID, subSyntax, subValue));
|
|
369
|
-
else properties.push(generatePropertyDefinition(subID, "*"));
|
|
370
|
-
}
|
|
371
|
-
if (!seen.has(localID)) {
|
|
372
|
-
seen.add(localID);
|
|
373
|
-
properties.push(generatePropertyDefinition(localID, "*"));
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
return properties;
|
|
378
|
-
}
|
|
379
|
-
function buildCSS({ logger, getTransforms, include: userInclude, exclude: userExclude, utility, permutations, modeSelectors, baseSelector, baseScheme, propertyDefinitions = false, omitTypographyShorthand, subValueVariableName }) {
|
|
380
|
-
function makeSubValueId(variableName, subValueName, token) {
|
|
381
|
-
const customName = subValueVariableName?.(variableName, subValueName, token);
|
|
382
|
-
if (customName !== void 0) {
|
|
383
|
-
if (typeof customName !== "string") logger.error({
|
|
384
|
-
group: "plugin",
|
|
385
|
-
label: PLUGIN_NAME,
|
|
386
|
-
message: `subValueVariableName() must return a string; received ${customName}`
|
|
387
|
-
});
|
|
388
|
-
return customName;
|
|
389
|
-
}
|
|
390
|
-
return `${variableName}-${subValueName}`;
|
|
391
|
-
}
|
|
392
|
-
const include = userInclude ? cachedMatcher.tokenIDMatch(userInclude) : () => true;
|
|
393
|
-
const exclude = userExclude ? cachedMatcher.tokenIDMatch(userExclude) : () => false;
|
|
394
|
-
let propertyDefsNodes = [];
|
|
395
|
-
if (propertyDefinitions) propertyDefsNodes = generatePropertyDefinitions(getTransforms, {
|
|
396
|
-
include,
|
|
397
|
-
exclude
|
|
398
|
-
});
|
|
399
|
-
if (permutations?.length) {
|
|
400
|
-
let output = "";
|
|
401
|
-
for (const p of permutations) {
|
|
402
|
-
if (typeof p.prepare !== "function") logger.error({
|
|
403
|
-
group: "plugin",
|
|
404
|
-
label: PLUGIN_NAME,
|
|
405
|
-
message: "prepare(css) must be a function!"
|
|
406
|
-
});
|
|
407
|
-
const tokens = getTransforms({
|
|
408
|
-
format: "css",
|
|
409
|
-
input: p.input
|
|
410
|
-
});
|
|
411
|
-
if (!tokens.length) continue;
|
|
412
|
-
const root = [];
|
|
413
|
-
const hdrColors = {
|
|
414
|
-
p3: [],
|
|
415
|
-
rec2020: []
|
|
416
|
-
};
|
|
417
|
-
const pInclude = p.include ? cachedMatcher.tokenIDMatch(p.include) : () => true;
|
|
418
|
-
const pExclude = p.exclude ? cachedMatcher.tokenIDMatch(p.exclude) : () => false;
|
|
419
|
-
const includeToken = (tokenId) => {
|
|
420
|
-
return include(tokenId) && pInclude(tokenId) && !exclude(tokenId) && !pExclude(tokenId);
|
|
421
|
-
};
|
|
422
|
-
for (const token of tokens) {
|
|
423
|
-
if (!includeToken(token.id)) continue;
|
|
424
|
-
const localID = makeCSSVar(token.localID ?? token.token.id);
|
|
425
|
-
const aliasTokens = token.token.aliasedBy?.length ? getTransforms({
|
|
426
|
-
format: "css",
|
|
427
|
-
id: token.token.aliasedBy,
|
|
428
|
-
input: p.input
|
|
429
|
-
}) : [];
|
|
430
|
-
if (token.type === "SINGLE_VALUE") addDeclUnique(root, decl(localID, token.value, getDescription(token)));
|
|
431
|
-
else if (token.value.srgb && token.value.p3 && token.value.rec2020) {
|
|
432
|
-
addDeclUnique(root, decl(localID, token.value.srgb, getDescription(token)));
|
|
433
|
-
if (token.value.p3 !== token.value.srgb) {
|
|
434
|
-
addDeclUnique(hdrColors.p3, decl(localID, token.value.p3, getDescription(token)));
|
|
435
|
-
addDeclUnique(hdrColors.rec2020, decl(localID, token.value.rec2020, getDescription(token)));
|
|
436
|
-
for (const alias of aliasTokens) if (alias.localID && typeof alias.value === "string") {
|
|
437
|
-
const aliasID = makeCSSVar(alias.localID);
|
|
438
|
-
addDeclUnique(hdrColors.p3, decl(aliasID, alias.value, getDescription(alias)));
|
|
439
|
-
addDeclUnique(hdrColors.rec2020, decl(aliasID, alias.value, getDescription(alias)));
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
} else {
|
|
443
|
-
for (const [name, subValue] of Object.entries(token.value)) addDeclUnique(root, decl(makeSubValueId(localID, name, token), subValue, getDescription(token)));
|
|
444
|
-
const shorthand = generateShorthand({
|
|
445
|
-
token: {
|
|
446
|
-
...token.token,
|
|
447
|
-
$value: token.value
|
|
448
|
-
},
|
|
449
|
-
localID,
|
|
450
|
-
omitTypographyShorthand
|
|
451
|
-
});
|
|
452
|
-
if (shorthand) addDeclUnique(root, decl(localID, shorthand, getDescription(token)));
|
|
453
|
-
}
|
|
454
|
-
for (const alias of aliasTokens) if (alias.localID && typeof alias.value === "string") {
|
|
455
|
-
if (!includeToken(alias.id)) continue;
|
|
456
|
-
addDeclUnique(root, decl(alias.localID, alias.value, getDescription(token)));
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
const indentRules = getIndentFromPrepare(p.prepare);
|
|
460
|
-
if (output) output += "\n";
|
|
461
|
-
output += `${p.prepare(printRules(root, indentRules))}\n`;
|
|
462
|
-
for (const gamut of ["p3", "rec2020"]) if (hdrColors[gamut].length) {
|
|
463
|
-
output += `\n@media (color-gamut: ${gamut}) {\n`;
|
|
464
|
-
output += indentRules.indentChar;
|
|
465
|
-
output += p.prepare(printRules(hdrColors[gamut], indentRules)).replace(/\n(?!\n)/g, `\n${indentRules.indentChar}`);
|
|
466
|
-
output += "\n}\n";
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
if (utility && Object.keys(utility).length) {
|
|
470
|
-
if (output) output += "\n";
|
|
471
|
-
output += printRules(generateUtilityCSS(utility, getTransforms({
|
|
472
|
-
format: "css",
|
|
473
|
-
input: permutations[0]?.input ?? {}
|
|
474
|
-
}), { logger }));
|
|
475
|
-
}
|
|
476
|
-
if (propertyDefsNodes.length && output) output = `${printRules(propertyDefsNodes)}\n\n${output}`;
|
|
477
|
-
return output;
|
|
478
|
-
}
|
|
479
|
-
let output = "";
|
|
480
|
-
const rootTokens = getTransforms({
|
|
481
|
-
format: "css",
|
|
482
|
-
mode: "."
|
|
483
|
-
});
|
|
484
|
-
if (rootTokens.length) {
|
|
485
|
-
const rules = [
|
|
486
|
-
rule([baseSelector], []),
|
|
487
|
-
rule([P3_MQ], [rule([baseSelector])]),
|
|
488
|
-
rule([REC2020_MQ], [rule([baseSelector])])
|
|
489
|
-
];
|
|
490
|
-
const rootRule = rules[0];
|
|
491
|
-
const p3Rule = rules[1].children[0];
|
|
492
|
-
const rec2020Rule = rules[2].children[0];
|
|
493
|
-
if (baseScheme) rootRule.children.unshift(decl("color-scheme", baseScheme));
|
|
494
|
-
for (const token of rootTokens) {
|
|
495
|
-
if (!include(token.token.id) || exclude(token.token.id)) continue;
|
|
496
|
-
const localID = token.localID ?? token.token.id;
|
|
497
|
-
const aliasTokens = token.token.aliasedBy?.length ? getTransforms({
|
|
498
|
-
format: "css",
|
|
499
|
-
id: token.token.aliasedBy
|
|
500
|
-
}) : [];
|
|
501
|
-
if (token.type === "SINGLE_VALUE") addDeclUnique(rootRule.children, decl(localID, token.value, getDescription(token)));
|
|
502
|
-
else if (token.value.srgb && token.value.p3 && token.value.rec2020) {
|
|
503
|
-
addDeclUnique(rootRule.children, decl(localID, token.value.srgb, getDescription(token)));
|
|
504
|
-
if (token.value.p3 !== token.value.srgb) {
|
|
505
|
-
addDeclUnique(p3Rule.children, decl(localID, token.value.p3, getDescription(token)));
|
|
506
|
-
addDeclUnique(rec2020Rule.children, decl(localID, token.value.rec2020, getDescription(token)));
|
|
507
|
-
for (const alias of aliasTokens) if (alias.localID && typeof alias.value === "string") {
|
|
508
|
-
addDeclUnique(p3Rule.children, decl(alias.localID, alias.value, getDescription(alias)));
|
|
509
|
-
addDeclUnique(rec2020Rule.children, decl(alias.localID, alias.value, getDescription(alias)));
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
} else if (token.type === "MULTI_VALUE") {
|
|
513
|
-
for (const [name, value] of Object.entries(token.value)) {
|
|
514
|
-
const property = name === "." ? localID : makeSubValueId(localID, name, token);
|
|
515
|
-
addDeclUnique(rootRule.children, decl(property, value, getDescription(token)));
|
|
516
|
-
}
|
|
517
|
-
const shorthand = generateShorthand({
|
|
518
|
-
token: {
|
|
519
|
-
...token.token,
|
|
520
|
-
$value: token.value
|
|
521
|
-
},
|
|
522
|
-
localID,
|
|
523
|
-
omitTypographyShorthand
|
|
524
|
-
});
|
|
525
|
-
if (shorthand) addDeclUnique(rootRule.children, decl(token.localID ?? token.token.id, shorthand, getDescription(token)));
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
output += printRules(rules);
|
|
529
|
-
}
|
|
530
|
-
for (const selector of modeSelectors ?? []) {
|
|
531
|
-
const selectorTokens = getTransforms({
|
|
532
|
-
format: "css",
|
|
533
|
-
id: selector.tokens,
|
|
534
|
-
mode: selector.mode
|
|
535
|
-
});
|
|
536
|
-
if (!selectorTokens.length) continue;
|
|
537
|
-
const modeRule = rule(selector.selectors);
|
|
538
|
-
if (selector.scheme) modeRule.children.unshift(decl("color-scheme", selector.scheme));
|
|
539
|
-
const hdrColors = {
|
|
540
|
-
p3: [],
|
|
541
|
-
rec2020: []
|
|
542
|
-
};
|
|
543
|
-
for (const token of selectorTokens) {
|
|
544
|
-
const localID = token.localID ?? token.token.id;
|
|
545
|
-
const aliasedBy = token.token.mode[selector.mode]?.aliasedBy?.length ? token.token.mode[selector.mode].aliasedBy : token.token.aliasedBy;
|
|
546
|
-
let aliasTokens = aliasedBy?.length ? getTransforms({
|
|
547
|
-
format: "css",
|
|
548
|
-
id: aliasedBy,
|
|
549
|
-
mode: selector.mode
|
|
550
|
-
}) : [];
|
|
551
|
-
if (new Set(aliasTokens.map((t) => t.id)).size !== aliasTokens.length && selector.mode !== ".") aliasTokens = aliasTokens.filter((t, i) => !aliasTokens.some((t2, i2) => t.id === t2.id && i !== i2 && t.mode === "."));
|
|
552
|
-
if (token.type === "SINGLE_VALUE") addDeclUnique(modeRule.children, decl(localID, token.value, getDescription(token)));
|
|
553
|
-
else if (token.value.srgb && token.value.p3 && token.value.rec2020) {
|
|
554
|
-
addDeclUnique(modeRule.children, decl(localID, token.value.srgb, getDescription(token)));
|
|
555
|
-
if (token.value.p3 !== token.value.srgb) {
|
|
556
|
-
addDeclUnique(hdrColors.p3, decl(localID, token.value.p3, getDescription(token)));
|
|
557
|
-
addDeclUnique(hdrColors.rec2020, decl(localID, token.value.rec2020, getDescription(token)));
|
|
558
|
-
for (const alias of aliasTokens) if (alias.localID && typeof alias.value === "string") for (const gamut of ["p3", "rec2020"]) addDeclUnique(hdrColors[gamut], decl(alias.localID, alias.value, getDescription(alias)));
|
|
559
|
-
}
|
|
560
|
-
} else {
|
|
561
|
-
for (const [name, subValue] of Object.entries(token.value)) {
|
|
562
|
-
const subValueID = makeSubValueId(localID, name, token);
|
|
563
|
-
addDeclUnique(modeRule.children, decl(subValueID, subValue, getDescription(token)));
|
|
564
|
-
}
|
|
565
|
-
const shorthand = generateShorthand({
|
|
566
|
-
token: {
|
|
567
|
-
...token.token,
|
|
568
|
-
$value: token.value
|
|
569
|
-
},
|
|
570
|
-
localID,
|
|
571
|
-
omitTypographyShorthand
|
|
572
|
-
});
|
|
573
|
-
if (shorthand) addDeclUnique(modeRule.children, decl(localID, shorthand, getDescription(token)));
|
|
574
|
-
}
|
|
575
|
-
for (const alias of aliasTokens) if (alias.localID && typeof alias.value === "string") addDeclUnique(modeRule.children, decl(alias.localID, alias.value, getDescription(token)));
|
|
576
|
-
}
|
|
577
|
-
if (output) output += "\n\n";
|
|
578
|
-
output += printRules([
|
|
579
|
-
modeRule,
|
|
580
|
-
rule([P3_MQ], [rule(selector.selectors, hdrColors.p3)]),
|
|
581
|
-
rule([REC2020_MQ], [rule(selector.selectors, hdrColors.rec2020)])
|
|
582
|
-
]);
|
|
583
|
-
}
|
|
584
|
-
if (utility && Object.keys(utility).length) {
|
|
585
|
-
if (output) output += "\n\n";
|
|
586
|
-
output += printRules(generateUtilityCSS(utility, getTransforms({
|
|
587
|
-
format: "css",
|
|
588
|
-
mode: "."
|
|
589
|
-
}), { logger }));
|
|
590
|
-
}
|
|
591
|
-
if (propertyDefsNodes.length && output) output = `${printRules(propertyDefsNodes)}\n\n${output}`;
|
|
592
|
-
return output;
|
|
593
|
-
}
|
|
594
|
-
//#endregion
|
|
595
|
-
//#region src/transform.ts
|
|
596
|
-
function transformCSS({ transform: { context: { logger }, resolver, setTransform, tokens: baseTokens }, options: { permutations, include: userInclude, exclude: userExclude, legacyHex, transform: customTransform, variableName } }) {
|
|
597
|
-
function transformName(token) {
|
|
598
|
-
const customName = variableName?.(token);
|
|
599
|
-
if (customName !== void 0) {
|
|
600
|
-
if (typeof customName !== "string") logger.error({
|
|
601
|
-
group: "plugin",
|
|
602
|
-
label: PLUGIN_NAME,
|
|
603
|
-
message: `variableName() must return a string; received ${customName}`
|
|
604
|
-
});
|
|
605
|
-
return customName;
|
|
606
|
-
}
|
|
607
|
-
return makeCSSVar(token.id);
|
|
608
|
-
}
|
|
609
|
-
const transformAlias = (token) => `var(${transformName(token)})`;
|
|
610
|
-
const include = userInclude ? cachedMatcher.tokenIDMatch(userInclude) : () => true;
|
|
611
|
-
const exclude = userExclude ? cachedMatcher.tokenIDMatch(userExclude) : () => false;
|
|
612
|
-
if (Array.isArray(permutations)) {
|
|
613
|
-
let defaultPermutationI = permutations.findIndex((p) => !Object.keys(p.input ?? {}).length);
|
|
614
|
-
if (defaultPermutationI === -1) defaultPermutationI = 0;
|
|
615
|
-
for (let i = 0; i < permutations.length; i++) {
|
|
616
|
-
const p = permutations[i];
|
|
617
|
-
const inputRaw = p.input;
|
|
618
|
-
const input = !Object.keys(inputRaw ?? {}).length ? JSON.parse(resolver.getPermutationID(inputRaw ?? {})) : inputRaw;
|
|
619
|
-
const pInclude = p.include ? cachedMatcher.tokenIDMatch(p.include) : () => true;
|
|
620
|
-
const pExclude = p.exclude ? cachedMatcher.tokenIDMatch(p.exclude) : () => false;
|
|
621
|
-
const includeToken = (tokenId) => {
|
|
622
|
-
return include(tokenId) && pInclude(tokenId) && !exclude(tokenId) && !pExclude(tokenId);
|
|
623
|
-
};
|
|
624
|
-
try {
|
|
625
|
-
const tokens = resolver.apply(input);
|
|
626
|
-
for (const token of Object.values(tokens)) {
|
|
627
|
-
if (!includeToken(token.id)) continue;
|
|
628
|
-
const options = {
|
|
629
|
-
tokensSet: tokens,
|
|
630
|
-
transformAlias,
|
|
631
|
-
color: { legacyHex },
|
|
632
|
-
permutation: input
|
|
633
|
-
};
|
|
634
|
-
const value = p.transform?.(token, options) ?? customTransform?.(token, options) ?? transformCSSValue(token, options);
|
|
635
|
-
if (value) {
|
|
636
|
-
const localID = transformName(token);
|
|
637
|
-
setTransform(token.id, {
|
|
638
|
-
format: "css",
|
|
639
|
-
value,
|
|
640
|
-
localID,
|
|
641
|
-
input,
|
|
642
|
-
meta: {
|
|
643
|
-
"plugin-css": { description: token.$description },
|
|
644
|
-
"token-listing": { name: localID }
|
|
645
|
-
}
|
|
646
|
-
});
|
|
647
|
-
if (defaultPermutationI === i) setTransform(token.id, {
|
|
648
|
-
format: "css",
|
|
649
|
-
value,
|
|
650
|
-
localID,
|
|
651
|
-
mode: ".",
|
|
652
|
-
meta: {
|
|
653
|
-
"plugin-css": { description: token.$description },
|
|
654
|
-
"token-listing": { name: localID }
|
|
655
|
-
}
|
|
656
|
-
});
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
} catch (err) {
|
|
660
|
-
logger.error({
|
|
661
|
-
group: "plugin",
|
|
662
|
-
label: PLUGIN_NAME,
|
|
663
|
-
message: `There was an error trying to apply input ${resolver.getPermutationID(input)}.`,
|
|
664
|
-
continueOnError: true
|
|
665
|
-
});
|
|
666
|
-
throw err;
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
return;
|
|
670
|
-
}
|
|
671
|
-
for (const token of Object.values(baseTokens)) {
|
|
672
|
-
if (!include(token.id) || exclude(token.id)) continue;
|
|
673
|
-
for (const mode of Object.keys(token.mode)) {
|
|
674
|
-
const tokenArgs = {
|
|
675
|
-
...token,
|
|
676
|
-
...token.mode[mode]
|
|
677
|
-
};
|
|
678
|
-
const options = {
|
|
679
|
-
tokensSet: baseTokens,
|
|
680
|
-
transformAlias,
|
|
681
|
-
color: { legacyHex },
|
|
682
|
-
permutation: { tzMode: "*" }
|
|
683
|
-
};
|
|
684
|
-
const value = customTransform?.(tokenArgs, options) ?? transformCSSValue(tokenArgs, options);
|
|
685
|
-
if (value) {
|
|
686
|
-
const localID = transformName(token);
|
|
687
|
-
setTransform(token.id, {
|
|
688
|
-
format: "css",
|
|
689
|
-
localID,
|
|
690
|
-
value,
|
|
691
|
-
mode,
|
|
692
|
-
meta: {
|
|
693
|
-
"plugin-css": { description: token.$description },
|
|
694
|
-
"token-listing": { name: localID }
|
|
695
|
-
}
|
|
696
|
-
});
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
//#endregion
|
|
702
|
-
//#region src/index.ts
|
|
703
|
-
function cssPlugin(options) {
|
|
704
|
-
const { utility, skipBuild, baseScheme, propertyDefinitions } = options ?? {};
|
|
705
|
-
const filename = options?.filename ?? options?.fileName ?? "index.css";
|
|
706
|
-
const baseSelector = options?.baseSelector ?? ":root";
|
|
707
|
-
return {
|
|
708
|
-
name: PLUGIN_NAME,
|
|
709
|
-
config(_config, context) {
|
|
710
|
-
if (options?.permutations && (options?.modeSelectors || options?.baseSelector || options?.baseScheme)) context.logger.error({
|
|
711
|
-
group: "plugin",
|
|
712
|
-
label: PLUGIN_NAME,
|
|
713
|
-
message: "Permutations option is incompatible with modeSelectors, baseSelector, and baseScheme."
|
|
714
|
-
});
|
|
715
|
-
},
|
|
716
|
-
async transform(transformOptions) {
|
|
717
|
-
transformCSS({
|
|
718
|
-
transform: transformOptions,
|
|
719
|
-
options: options ?? {}
|
|
720
|
-
});
|
|
721
|
-
},
|
|
722
|
-
async build({ getTransforms, outputFile, context }) {
|
|
723
|
-
if (skipBuild === true) return;
|
|
724
|
-
let contents = `${FILE_PREFIX}\n\n`;
|
|
725
|
-
contents += buildCSS({
|
|
726
|
-
include: options?.include,
|
|
727
|
-
exclude: options?.exclude,
|
|
728
|
-
getTransforms,
|
|
729
|
-
permutations: options?.permutations,
|
|
730
|
-
modeSelectors: options?.modeSelectors,
|
|
731
|
-
utility,
|
|
732
|
-
baseSelector,
|
|
733
|
-
baseScheme,
|
|
734
|
-
propertyDefinitions: propertyDefinitions ?? false,
|
|
735
|
-
logger: context.logger,
|
|
736
|
-
omitTypographyShorthand: options?.omitTypographyShorthand,
|
|
737
|
-
subValueVariableName: options?.subValueVariableName
|
|
738
|
-
});
|
|
739
|
-
outputFile(filename, contents.replace(/\n*$/, "\n"));
|
|
740
|
-
}
|
|
741
|
-
};
|
|
742
|
-
}
|
|
743
|
-
//#endregion
|
|
744
|
-
export { FILE_PREFIX, FORMAT_ID, PLUGIN_NAME, cssPlugin as default, printNode, printRules };
|
|
745
|
-
|
|
746
51
|
//# sourceMappingURL=index.js.map
|