@bamboocss/core 1.11.1 → 1.11.3
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/dist/chunk-CfYAbeIz.mjs +13 -0
- package/dist/index.cjs +4055 -0
- package/dist/index.d.cts +1025 -0
- package/dist/index.d.mts +1023 -0
- package/dist/index.mjs +3775 -4106
- package/package.json +13 -13
- package/dist/index.js +0 -4327
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,4055 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __exportAll = (all, no_symbols) => {
|
|
10
|
+
let target = {};
|
|
11
|
+
for (var name in all) __defProp(target, name, {
|
|
12
|
+
get: all[name],
|
|
13
|
+
enumerable: true
|
|
14
|
+
});
|
|
15
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
16
|
+
return target;
|
|
17
|
+
};
|
|
18
|
+
var __copyProps = (to, from, except, desc) => {
|
|
19
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
20
|
+
key = keys[i];
|
|
21
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
22
|
+
get: ((k) => from[k]).bind(null, key),
|
|
23
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
return to;
|
|
27
|
+
};
|
|
28
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
29
|
+
value: mod,
|
|
30
|
+
enumerable: true
|
|
31
|
+
}) : target, mod));
|
|
32
|
+
//#endregion
|
|
33
|
+
let _bamboocss_logger = require("@bamboocss/logger");
|
|
34
|
+
let outdent = require("outdent");
|
|
35
|
+
let _bamboocss_shared = require("@bamboocss/shared");
|
|
36
|
+
let postcss = require("postcss");
|
|
37
|
+
postcss = __toESM(postcss);
|
|
38
|
+
let _bamboocss_is_valid_prop = require("@bamboocss/is-valid-prop");
|
|
39
|
+
let _bamboocss_token_dictionary = require("@bamboocss/token-dictionary");
|
|
40
|
+
let lodash_merge = require("lodash.merge");
|
|
41
|
+
lodash_merge = __toESM(lodash_merge);
|
|
42
|
+
let _csstools_postcss_cascade_layers = require("@csstools/postcss-cascade-layers");
|
|
43
|
+
_csstools_postcss_cascade_layers = __toESM(_csstools_postcss_cascade_layers);
|
|
44
|
+
let postcss_nested = require("postcss-nested");
|
|
45
|
+
postcss_nested = __toESM(postcss_nested);
|
|
46
|
+
let postcss_discard_duplicates = require("postcss-discard-duplicates");
|
|
47
|
+
postcss_discard_duplicates = __toESM(postcss_discard_duplicates);
|
|
48
|
+
let postcss_discard_empty = require("postcss-discard-empty");
|
|
49
|
+
postcss_discard_empty = __toESM(postcss_discard_empty);
|
|
50
|
+
let postcss_minify_selectors = require("postcss-minify-selectors");
|
|
51
|
+
postcss_minify_selectors = __toESM(postcss_minify_selectors);
|
|
52
|
+
let postcss_normalize_whitespace = require("postcss-normalize-whitespace");
|
|
53
|
+
postcss_normalize_whitespace = __toESM(postcss_normalize_whitespace);
|
|
54
|
+
let ts_pattern = require("ts-pattern");
|
|
55
|
+
let postcss_selector_parser = require("postcss-selector-parser");
|
|
56
|
+
postcss_selector_parser = __toESM(postcss_selector_parser);
|
|
57
|
+
//#region src/messages.ts
|
|
58
|
+
var messages_exports = /* @__PURE__ */ __exportAll({
|
|
59
|
+
artifactsGenerated: () => artifactsGenerated,
|
|
60
|
+
buildComplete: () => buildComplete,
|
|
61
|
+
codegenComplete: () => codegenComplete,
|
|
62
|
+
configExists: () => configExists,
|
|
63
|
+
configWatch: () => configWatch,
|
|
64
|
+
cssArtifactComplete: () => cssArtifactComplete,
|
|
65
|
+
exclamation: () => exclamation,
|
|
66
|
+
getMessages: () => getMessages,
|
|
67
|
+
noExtract: () => noExtract,
|
|
68
|
+
thankYou: () => thankYou,
|
|
69
|
+
watch: () => watch
|
|
70
|
+
});
|
|
71
|
+
const tick = _bamboocss_logger.colors.green().bold("✔️");
|
|
72
|
+
const artifactsGenerated = (ctx) => {
|
|
73
|
+
const { config: { outdir, themes }, recipes, patterns, tokens, jsx } = ctx;
|
|
74
|
+
return () => [
|
|
75
|
+
outdent.outdent`
|
|
76
|
+
${tick} ${(0, _bamboocss_logger.quote)(outdir, "/css")}: the css function to author styles
|
|
77
|
+
`,
|
|
78
|
+
!tokens.isEmpty && outdent.outdent`
|
|
79
|
+
${tick} ${(0, _bamboocss_logger.quote)(outdir, "/tokens")}: the css variables and js function to query your tokens
|
|
80
|
+
`,
|
|
81
|
+
!patterns.isEmpty() && !ctx.isTemplateLiteralSyntax && outdent.outdent`
|
|
82
|
+
${tick} ${(0, _bamboocss_logger.quote)(outdir, "/patterns")}: functions to implement and apply common layout patterns
|
|
83
|
+
`,
|
|
84
|
+
!recipes.isEmpty() && outdent.outdent`
|
|
85
|
+
${tick} ${(0, _bamboocss_logger.quote)(outdir, "/recipes")}: functions to create multi-variant styles
|
|
86
|
+
`,
|
|
87
|
+
jsx.framework && outdent.outdent`
|
|
88
|
+
${tick} ${(0, _bamboocss_logger.quote)(outdir, "/jsx")}: styled jsx elements for ${jsx.framework}
|
|
89
|
+
`,
|
|
90
|
+
themes && outdent.outdent`
|
|
91
|
+
${tick} ${(0, _bamboocss_logger.quote)(outdir, "/themes")}: theme variants for your design system
|
|
92
|
+
`,
|
|
93
|
+
"\n"
|
|
94
|
+
].filter(Boolean).join("\n");
|
|
95
|
+
};
|
|
96
|
+
const configExists = (cmd) => outdent.outdent`
|
|
97
|
+
\n
|
|
98
|
+
It looks like you already have bamboo created\`.
|
|
99
|
+
|
|
100
|
+
You can now run ${(0, _bamboocss_logger.quote)(cmd, " bamboo --watch")}.
|
|
101
|
+
|
|
102
|
+
`;
|
|
103
|
+
const thankYou = () => outdent.outdent`
|
|
104
|
+
|
|
105
|
+
🚀 Thanks for choosing ${_bamboocss_logger.colors.cyan("Bamboo")})} to write your css.
|
|
106
|
+
|
|
107
|
+
You are set up to start using Bamboo!
|
|
108
|
+
|
|
109
|
+
`;
|
|
110
|
+
const codegenComplete = () => outdent.outdent`
|
|
111
|
+
|
|
112
|
+
${_bamboocss_logger.colors.bold().cyan("Next steps:")}
|
|
113
|
+
|
|
114
|
+
[1] Create a ${(0, _bamboocss_logger.quote)("index.css")} file in your project that contains:
|
|
115
|
+
|
|
116
|
+
@layer reset, base, tokens, recipes, utilities;
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
[2] Import the ${(0, _bamboocss_logger.quote)("index.css")} file at the root of your project.
|
|
120
|
+
|
|
121
|
+
`;
|
|
122
|
+
const noExtract = () => outdent.outdent`
|
|
123
|
+
No style object or props were detected in your source files.
|
|
124
|
+
If this is unexpected, double-check the \`include\` options in your Bamboo config\n
|
|
125
|
+
`;
|
|
126
|
+
const watch = () => outdent.outdent`
|
|
127
|
+
Watching for file changes...
|
|
128
|
+
`;
|
|
129
|
+
const configWatch = () => outdent.outdent`
|
|
130
|
+
Watching for config file changes...
|
|
131
|
+
`;
|
|
132
|
+
const buildComplete = (count) => outdent.outdent`
|
|
133
|
+
Successfully extracted css from ${count} file(s) ✨
|
|
134
|
+
`;
|
|
135
|
+
const randomWords = [
|
|
136
|
+
"Sweet",
|
|
137
|
+
"Divine",
|
|
138
|
+
"Bamboolicious",
|
|
139
|
+
"Super"
|
|
140
|
+
];
|
|
141
|
+
const pickRandom = (arr) => arr[Math.floor(Math.random() * arr.length)];
|
|
142
|
+
const exclamation = () => `🎋 ${pickRandom(randomWords)}! ✨`;
|
|
143
|
+
const cssArtifactComplete = (type) => `Successfully generated ${type} css artifact ✨`;
|
|
144
|
+
const getMessages = (ctx) => ({
|
|
145
|
+
artifactsGenerated: artifactsGenerated(ctx),
|
|
146
|
+
configExists,
|
|
147
|
+
thankYou,
|
|
148
|
+
codegenComplete,
|
|
149
|
+
noExtract,
|
|
150
|
+
watch,
|
|
151
|
+
buildComplete,
|
|
152
|
+
configWatch,
|
|
153
|
+
cssArtifactComplete,
|
|
154
|
+
exclamation
|
|
155
|
+
});
|
|
156
|
+
//#endregion
|
|
157
|
+
//#region src/breakpoints.ts
|
|
158
|
+
var Breakpoints = class {
|
|
159
|
+
breakpoints;
|
|
160
|
+
sorted;
|
|
161
|
+
values;
|
|
162
|
+
keys;
|
|
163
|
+
ranges;
|
|
164
|
+
conditions;
|
|
165
|
+
constructor(breakpoints) {
|
|
166
|
+
this.breakpoints = breakpoints;
|
|
167
|
+
this.sorted = sortBreakpoints(breakpoints);
|
|
168
|
+
this.values = Object.fromEntries(this.sorted);
|
|
169
|
+
this.keys = ["base", ...Object.keys(this.values)];
|
|
170
|
+
this.ranges = this.getRanges();
|
|
171
|
+
this.conditions = this.getConditions();
|
|
172
|
+
}
|
|
173
|
+
get = (name) => {
|
|
174
|
+
return this.values[name];
|
|
175
|
+
};
|
|
176
|
+
build = ({ min, max }) => {
|
|
177
|
+
if (min == null && max == null) return "";
|
|
178
|
+
return [
|
|
179
|
+
"screen",
|
|
180
|
+
min && `(min-width: ${min})`,
|
|
181
|
+
max && `(max-width: ${max})`
|
|
182
|
+
].filter(Boolean).join(" and ");
|
|
183
|
+
};
|
|
184
|
+
only = (name) => {
|
|
185
|
+
const { min, max } = this.get(name);
|
|
186
|
+
return this.build({
|
|
187
|
+
min,
|
|
188
|
+
max
|
|
189
|
+
});
|
|
190
|
+
};
|
|
191
|
+
getRanges = () => {
|
|
192
|
+
const breakpoints = Object.keys(this.values);
|
|
193
|
+
const permuations = getPermutations(breakpoints);
|
|
194
|
+
const values = breakpoints.flatMap((name) => {
|
|
195
|
+
const value = this.get(name);
|
|
196
|
+
const down = [`${name}Down`, this.build({ max: adjust(value.min) })];
|
|
197
|
+
return [
|
|
198
|
+
[name, this.build({ min: value.min })],
|
|
199
|
+
[`${name}Only`, this.only(name)],
|
|
200
|
+
down
|
|
201
|
+
];
|
|
202
|
+
}).filter(([_, value]) => value !== "").concat(permuations.map(([min, max]) => {
|
|
203
|
+
const minValue = this.get(min);
|
|
204
|
+
const maxValue = this.get(max);
|
|
205
|
+
return [`${min}To${(0, _bamboocss_shared.capitalize)(max)}`, this.build({
|
|
206
|
+
min: minValue.min,
|
|
207
|
+
max: adjust(maxValue.min)
|
|
208
|
+
})];
|
|
209
|
+
}));
|
|
210
|
+
return Object.fromEntries(values);
|
|
211
|
+
};
|
|
212
|
+
getConditions = () => {
|
|
213
|
+
const values = Object.entries(this.ranges).map(([key, value]) => {
|
|
214
|
+
return [key, toCondition(key, value)];
|
|
215
|
+
});
|
|
216
|
+
return Object.fromEntries(values);
|
|
217
|
+
};
|
|
218
|
+
getCondition = (key) => {
|
|
219
|
+
return this.conditions[key];
|
|
220
|
+
};
|
|
221
|
+
expandScreenAtRule = (root) => {
|
|
222
|
+
root.walkAtRules("breakpoint", (rule) => {
|
|
223
|
+
const value = this.getCondition(rule.params);
|
|
224
|
+
if (!value) throw rule.error(`No \`${rule.params}\` screen found.`);
|
|
225
|
+
if (value.type !== "at-rule") throw rule.error(`\`${rule.params}\` is not a valid screen.`);
|
|
226
|
+
rule.name = "media";
|
|
227
|
+
rule.params = value.params;
|
|
228
|
+
});
|
|
229
|
+
};
|
|
230
|
+
};
|
|
231
|
+
function adjust(value) {
|
|
232
|
+
return (0, _bamboocss_shared.toRem)(`${parseFloat((0, _bamboocss_shared.toPx)(value) ?? "") - .04}px`);
|
|
233
|
+
}
|
|
234
|
+
function sortBreakpoints(breakpoints) {
|
|
235
|
+
return Object.entries(breakpoints).sort(([, minA], [, minB]) => {
|
|
236
|
+
return parseInt(minA, 10) < parseInt(minB, 10) ? -1 : 1;
|
|
237
|
+
}).map(([name, min], index, entries) => {
|
|
238
|
+
let max = null;
|
|
239
|
+
if (index <= entries.length - 1) max = entries[index + 1]?.[1];
|
|
240
|
+
if (max != null) max = adjust(max);
|
|
241
|
+
return [name, {
|
|
242
|
+
name,
|
|
243
|
+
min: (0, _bamboocss_shared.toRem)(min),
|
|
244
|
+
max
|
|
245
|
+
}];
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
const toCondition = (key, value) => ({
|
|
249
|
+
type: "at-rule",
|
|
250
|
+
name: "breakpoint",
|
|
251
|
+
value: key,
|
|
252
|
+
raw: `@media ${value}`,
|
|
253
|
+
params: value
|
|
254
|
+
});
|
|
255
|
+
function getPermutations(values) {
|
|
256
|
+
const result = [];
|
|
257
|
+
values.forEach((current, index) => {
|
|
258
|
+
let idx = index;
|
|
259
|
+
idx++;
|
|
260
|
+
let next = values[idx];
|
|
261
|
+
while (next) {
|
|
262
|
+
result.push([current, next]);
|
|
263
|
+
idx++;
|
|
264
|
+
next = values[idx];
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
return result;
|
|
268
|
+
}
|
|
269
|
+
//#endregion
|
|
270
|
+
//#region src/safe-parse.ts
|
|
271
|
+
function safeParse(str) {
|
|
272
|
+
try {
|
|
273
|
+
return postcss.default.parse(str);
|
|
274
|
+
} catch {
|
|
275
|
+
return postcss.default.root();
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
//#endregion
|
|
279
|
+
//#region src/parse-condition.ts
|
|
280
|
+
function parseAtRule(value) {
|
|
281
|
+
const rule = safeParse(value).nodes[0];
|
|
282
|
+
return {
|
|
283
|
+
type: "at-rule",
|
|
284
|
+
name: rule.name,
|
|
285
|
+
value: rule.params,
|
|
286
|
+
raw: value,
|
|
287
|
+
params: rule.params
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Parses an object condition with `@slot` markers into condition blocks.
|
|
292
|
+
* Each path from root to `@slot` becomes an independent condition block.
|
|
293
|
+
*
|
|
294
|
+
* @example
|
|
295
|
+
* ```ts
|
|
296
|
+
* parseObjectCondition({
|
|
297
|
+
* "@media (hover: hover)": { "&:is(:hover, [data-hover])": "@slot" },
|
|
298
|
+
* "@media (hover: none)": { "&:is(:active, [data-active])": "@slot" },
|
|
299
|
+
* })
|
|
300
|
+
* ```
|
|
301
|
+
*/
|
|
302
|
+
function parseObjectCondition(obj) {
|
|
303
|
+
const blocks = [];
|
|
304
|
+
function traverse(node, path) {
|
|
305
|
+
for (const [key, value] of Object.entries(node)) if (value === "@slot") {
|
|
306
|
+
const parsed = parseCondition([...path, key]);
|
|
307
|
+
if (parsed && parsed.type === "mixed" && parsed.value.length > 0) blocks.push(parsed);
|
|
308
|
+
} else if (typeof value === "object" && value !== null) traverse(value, [...path, key]);
|
|
309
|
+
}
|
|
310
|
+
traverse(obj, []);
|
|
311
|
+
if (blocks.length === 0) return void 0;
|
|
312
|
+
if (blocks.length === 1) return blocks[0];
|
|
313
|
+
return {
|
|
314
|
+
type: "multi-block",
|
|
315
|
+
value: blocks,
|
|
316
|
+
raw: obj
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
function parseCondition(condition) {
|
|
320
|
+
if (Array.isArray(condition)) return {
|
|
321
|
+
type: "mixed",
|
|
322
|
+
raw: condition,
|
|
323
|
+
value: condition.map(parseCondition).filter(Boolean)
|
|
324
|
+
};
|
|
325
|
+
if (typeof condition === "object" && condition !== null) return parseObjectCondition(condition);
|
|
326
|
+
if (condition.startsWith("@")) return parseAtRule(condition);
|
|
327
|
+
let type;
|
|
328
|
+
if (condition.startsWith("&")) type = "self-nesting";
|
|
329
|
+
else if (condition.endsWith(" &")) type = "parent-nesting";
|
|
330
|
+
else if (condition.includes("&")) type = "combinator-nesting";
|
|
331
|
+
if (type) return {
|
|
332
|
+
type,
|
|
333
|
+
value: condition,
|
|
334
|
+
raw: condition
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
//#endregion
|
|
338
|
+
//#region src/sort-at-rules.ts
|
|
339
|
+
const minMaxWidth = /(!?\(\s*min(-device-)?-width)(.|\n)+\(\s*max(-device)?-width/i;
|
|
340
|
+
const minWidth = /\(\s*min(-device)?-width/i;
|
|
341
|
+
const maxMinWidth = /(!?\(\s*max(-device)?-width)(.|\n)+\(\s*min(-device)?-width/i;
|
|
342
|
+
const maxWidth = /\(\s*max(-device)?-width/i;
|
|
343
|
+
const isMinWidth = _testQuery(minMaxWidth, maxMinWidth, minWidth);
|
|
344
|
+
const isMaxWidth = _testQuery(maxMinWidth, minMaxWidth, maxWidth);
|
|
345
|
+
const minMaxHeight = /(!?\(\s*min(-device)?-height)(.|\n)+\(\s*max(-device)?-height/i;
|
|
346
|
+
const minHeight = /\(\s*min(-device)?-height/i;
|
|
347
|
+
const maxMinHeight = /(!?\(\s*max(-device)?-height)(.|\n)+\(\s*min(-device)?-height/i;
|
|
348
|
+
const maxHeight = /\(\s*max(-device)?-height/i;
|
|
349
|
+
const isMinHeight = _testQuery(minMaxHeight, maxMinHeight, minHeight);
|
|
350
|
+
const isMaxHeight = _testQuery(maxMinHeight, minMaxHeight, maxHeight);
|
|
351
|
+
const isPrint = /print/i;
|
|
352
|
+
const isPrintOnly = /^print$/i;
|
|
353
|
+
const maxValue = Number.MAX_VALUE;
|
|
354
|
+
/**
|
|
355
|
+
* Obtain the length of the media request in pixels.
|
|
356
|
+
* Copy from original source `function inspectLength (length)`
|
|
357
|
+
*/
|
|
358
|
+
function getQueryLength(query) {
|
|
359
|
+
let length = /(-?\d*\.?\d+)(ch|em|ex|px|rem)/.exec(query);
|
|
360
|
+
if (length === null && (isMinWidth(query) || isMinHeight(query))) length = /(\d)/.exec(query);
|
|
361
|
+
if (length === "0") return 0;
|
|
362
|
+
if (length === null) return maxValue;
|
|
363
|
+
let number = length[1];
|
|
364
|
+
switch (length[2]) {
|
|
365
|
+
case "ch":
|
|
366
|
+
number = parseFloat(number) * 8.8984375;
|
|
367
|
+
break;
|
|
368
|
+
case "em":
|
|
369
|
+
case "rem":
|
|
370
|
+
number = parseFloat(number) * 16;
|
|
371
|
+
break;
|
|
372
|
+
case "ex":
|
|
373
|
+
number = parseFloat(number) * 8.296875;
|
|
374
|
+
break;
|
|
375
|
+
case "px":
|
|
376
|
+
number = parseFloat(number);
|
|
377
|
+
break;
|
|
378
|
+
}
|
|
379
|
+
return +number;
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Wrapper for creating test functions
|
|
383
|
+
* @private
|
|
384
|
+
* @param {RegExp} doubleTestTrue
|
|
385
|
+
* @param {RegExp} doubleTestFalse
|
|
386
|
+
* @param {RegExp} singleTest
|
|
387
|
+
* @return {Function}
|
|
388
|
+
*/
|
|
389
|
+
function _testQuery(doubleTestTrue, doubleTestFalse, singleTest) {
|
|
390
|
+
/**
|
|
391
|
+
* @param {string} query
|
|
392
|
+
* @return {boolean}
|
|
393
|
+
*/
|
|
394
|
+
return function(query) {
|
|
395
|
+
if (doubleTestTrue.test(query)) return true;
|
|
396
|
+
else if (doubleTestFalse.test(query)) return false;
|
|
397
|
+
return singleTest.test(query);
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* @private
|
|
402
|
+
* @param {string} a
|
|
403
|
+
* @param {string} b
|
|
404
|
+
* @return {number|null}
|
|
405
|
+
*/
|
|
406
|
+
function _testIsPrint(a, b) {
|
|
407
|
+
const isPrintA = isPrint.test(a);
|
|
408
|
+
const isPrintOnlyA = isPrintOnly.test(a);
|
|
409
|
+
const isPrintB = isPrint.test(b);
|
|
410
|
+
const isPrintOnlyB = isPrintOnly.test(b);
|
|
411
|
+
if (isPrintA && isPrintB) {
|
|
412
|
+
if (!isPrintOnlyA && isPrintOnlyB) return 1;
|
|
413
|
+
if (isPrintOnlyA && !isPrintOnlyB) return -1;
|
|
414
|
+
return a.localeCompare(b);
|
|
415
|
+
}
|
|
416
|
+
if (isPrintA) return 1;
|
|
417
|
+
if (isPrintB) return -1;
|
|
418
|
+
return null;
|
|
419
|
+
}
|
|
420
|
+
function createSort(config = {}) {
|
|
421
|
+
const { unitlessMqAlwaysFirst } = config;
|
|
422
|
+
return function sortCSSmq(a, b) {
|
|
423
|
+
const testIsPrint = _testIsPrint(a, b);
|
|
424
|
+
if (testIsPrint !== null) return testIsPrint;
|
|
425
|
+
const minA = isMinWidth(a) || isMinHeight(a);
|
|
426
|
+
const maxA = isMaxWidth(a) || isMaxHeight(a);
|
|
427
|
+
const minB = isMinWidth(b) || isMinHeight(b);
|
|
428
|
+
const maxB = isMaxWidth(b) || isMaxHeight(b);
|
|
429
|
+
if (unitlessMqAlwaysFirst && (!minA && !maxA || !minB && !maxB)) {
|
|
430
|
+
if (!minA && !maxA && !minB && !maxB) return a.localeCompare(b);
|
|
431
|
+
return !minB && !maxB ? 1 : -1;
|
|
432
|
+
} else {
|
|
433
|
+
if (minA && maxB) return -1;
|
|
434
|
+
if (maxA && minB) return 1;
|
|
435
|
+
const lengthA = getQueryLength(a);
|
|
436
|
+
const lengthB = getQueryLength(b);
|
|
437
|
+
if (lengthA === maxValue && lengthB === maxValue) return a.localeCompare(b);
|
|
438
|
+
else if (lengthA === maxValue) return 1;
|
|
439
|
+
else if (lengthB === maxValue) return -1;
|
|
440
|
+
if (lengthA > lengthB) {
|
|
441
|
+
if (maxA) return -1;
|
|
442
|
+
return 1;
|
|
443
|
+
}
|
|
444
|
+
if (lengthA < lengthB) {
|
|
445
|
+
if (maxA) return 1;
|
|
446
|
+
return -1;
|
|
447
|
+
}
|
|
448
|
+
return a.localeCompare(b);
|
|
449
|
+
}
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
const sortAtRules = createSort();
|
|
453
|
+
//#endregion
|
|
454
|
+
//#region src/sort-style-rules.ts
|
|
455
|
+
const hasAtRule = (conditions) => conditions.some((details) => details.type === "at-rule" || details.type === "mixed" || details.type === "multi-block");
|
|
456
|
+
const styleOrder = [
|
|
457
|
+
":link",
|
|
458
|
+
":visited",
|
|
459
|
+
":focus-within",
|
|
460
|
+
":focus",
|
|
461
|
+
":focus-visible",
|
|
462
|
+
":hover",
|
|
463
|
+
":active"
|
|
464
|
+
];
|
|
465
|
+
const pseudoSelectorScore = (selector) => {
|
|
466
|
+
return styleOrder.findIndex((pseudoClass) => selector.includes(pseudoClass)) + 1;
|
|
467
|
+
};
|
|
468
|
+
const compareSelectors = (a, b) => {
|
|
469
|
+
const aConds = a.conditions;
|
|
470
|
+
const bConds = b.conditions;
|
|
471
|
+
if (aConds.length === bConds.length) {
|
|
472
|
+
const selector1 = aConds[0].value;
|
|
473
|
+
const selector2 = bConds[0].value;
|
|
474
|
+
return pseudoSelectorScore(selector1) - pseudoSelectorScore(selector2);
|
|
475
|
+
}
|
|
476
|
+
return aConds.length - bConds.length;
|
|
477
|
+
};
|
|
478
|
+
/**
|
|
479
|
+
* Flatten mixed conditions to Array<AtRuleCondition | SelectorCondition>
|
|
480
|
+
*/
|
|
481
|
+
const flatten$1 = (conds) => conds.flatMap((cond) => {
|
|
482
|
+
if (cond.type === "mixed") return cond.value;
|
|
483
|
+
if (cond.type === "multi-block") return cond.value.flatMap((block) => block.value);
|
|
484
|
+
return cond;
|
|
485
|
+
});
|
|
486
|
+
/**
|
|
487
|
+
* Compare 2 Array<AtRuleCondition | SelectorCondition>
|
|
488
|
+
* - sort by condition length (shorter first)
|
|
489
|
+
* - sort at-rules by predefined order (sort-mq postcss plugin order)
|
|
490
|
+
* - sort selectors by predefined pseudo selector order
|
|
491
|
+
* - return 0 if equal
|
|
492
|
+
*
|
|
493
|
+
* do this for item in the array against the same index in the other array
|
|
494
|
+
* -> exit early if not equal
|
|
495
|
+
* -> if all comparisons result in a score of 0, return 0
|
|
496
|
+
*/
|
|
497
|
+
const compareAtRuleOrMixed = (a, b) => {
|
|
498
|
+
const aConds = flatten$1(a.conditions);
|
|
499
|
+
const bConds = flatten$1(b.conditions);
|
|
500
|
+
let aCond, bCond;
|
|
501
|
+
const max = Math.max(aConds.length, bConds.length);
|
|
502
|
+
for (let i = 0; i < max; i++) {
|
|
503
|
+
aCond = aConds[i];
|
|
504
|
+
bCond = bConds[i];
|
|
505
|
+
if (!aCond) return -1;
|
|
506
|
+
if (!bCond) return 1;
|
|
507
|
+
if (aCond.type === "at-rule" && bCond.type.includes("nesting")) return 1;
|
|
508
|
+
if (aCond.type.includes("nesting") && bCond.type === "at-rule") return -1;
|
|
509
|
+
if (aCond.type === "at-rule" && bCond.type === "at-rule") {
|
|
510
|
+
const atRule1 = aCond.params ?? aCond.raw;
|
|
511
|
+
const atRule2 = bCond.params ?? bCond.raw;
|
|
512
|
+
if (!atRule1) return -1;
|
|
513
|
+
if (!atRule2) return 1;
|
|
514
|
+
const score = sortAtRules(atRule1, atRule2);
|
|
515
|
+
if (score !== 0) return score;
|
|
516
|
+
continue;
|
|
517
|
+
}
|
|
518
|
+
if (aCond.type.includes("nesting") && bCond.type.includes("nesting")) {
|
|
519
|
+
const nextACond = aConds[i + 1];
|
|
520
|
+
const nextBCond = bConds[i + 1];
|
|
521
|
+
if (Boolean(nextACond) === Boolean(nextBCond)) {
|
|
522
|
+
const score = pseudoSelectorScore(aCond.value) - pseudoSelectorScore(bCond.value);
|
|
523
|
+
if (score !== 0) return score;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
return 0;
|
|
528
|
+
};
|
|
529
|
+
const sortByPropertyPriority = (a, b) => {
|
|
530
|
+
if (a.entry.prop === b.entry.prop) return 0;
|
|
531
|
+
return (0, _bamboocss_shared.getPropertyPriority)(a.entry.prop) - (0, _bamboocss_shared.getPropertyPriority)(b.entry.prop);
|
|
532
|
+
};
|
|
533
|
+
/**
|
|
534
|
+
* Sort style rules by conditions
|
|
535
|
+
* - with no conditions first
|
|
536
|
+
* - with selectors only next
|
|
537
|
+
* - with at-rules last
|
|
538
|
+
*
|
|
539
|
+
* for each of them:
|
|
540
|
+
* - sort by condition length (shorter first, the more you nest the more specific it is)
|
|
541
|
+
* - sort selectors by predefined pseudo selector order
|
|
542
|
+
* - sort at-rules by predefined order (sort-mq postcss plugin order)
|
|
543
|
+
* - sort by property priority (longhands first)
|
|
544
|
+
*/
|
|
545
|
+
const sortStyleRules = (styleRules) => {
|
|
546
|
+
const declarations = [];
|
|
547
|
+
const withSelectorsOnly = [];
|
|
548
|
+
const withAtRules = [];
|
|
549
|
+
for (const styleRule of styleRules) if (!styleRule.conditions?.length) declarations.push(styleRule);
|
|
550
|
+
else if (!hasAtRule(styleRule.conditions)) withSelectorsOnly.push(styleRule);
|
|
551
|
+
else withAtRules.push(styleRule);
|
|
552
|
+
withSelectorsOnly.sort((a, b) => {
|
|
553
|
+
const selectorDiff = compareSelectors(a, b);
|
|
554
|
+
if (selectorDiff !== 0) return selectorDiff;
|
|
555
|
+
return sortByPropertyPriority(a, b);
|
|
556
|
+
});
|
|
557
|
+
withAtRules.sort((a, b) => {
|
|
558
|
+
const conditionDiff = compareAtRuleOrMixed(a, b);
|
|
559
|
+
if (conditionDiff !== 0) return conditionDiff;
|
|
560
|
+
return sortByPropertyPriority(a, b);
|
|
561
|
+
});
|
|
562
|
+
const sorted = declarations.sort(sortByPropertyPriority);
|
|
563
|
+
sorted.push(...withSelectorsOnly, ...withAtRules);
|
|
564
|
+
return sorted;
|
|
565
|
+
};
|
|
566
|
+
//#endregion
|
|
567
|
+
//#region src/conditions.ts
|
|
568
|
+
/**
|
|
569
|
+
* Checks if a condition is an at-rule type
|
|
570
|
+
*/
|
|
571
|
+
const isAtRule = (cond) => cond.type === "at-rule";
|
|
572
|
+
/**
|
|
573
|
+
* Matches pseudo-element selectors (::before, ::after, ::placeholder, etc.)
|
|
574
|
+
* Pseudo-elements must appear at the end of CSS selector chains per the CSS spec.
|
|
575
|
+
*/
|
|
576
|
+
const pseudoElementRegex$1 = /::[\w-]/;
|
|
577
|
+
const isPseudoElement = (cond) => typeof cond.raw === "string" && pseudoElementRegex$1.test(cond.raw);
|
|
578
|
+
/**
|
|
579
|
+
* Flattens a condition, extracting parts from mixed conditions.
|
|
580
|
+
* Returns an array of { condition, originalIndex } to track source order.
|
|
581
|
+
*/
|
|
582
|
+
const flattenCondition = (cond, originalIndex) => {
|
|
583
|
+
if (cond.type === "mixed") return cond.value.map((part) => ({
|
|
584
|
+
cond: part,
|
|
585
|
+
originalIndex
|
|
586
|
+
}));
|
|
587
|
+
return [{
|
|
588
|
+
cond,
|
|
589
|
+
originalIndex
|
|
590
|
+
}];
|
|
591
|
+
};
|
|
592
|
+
const underscoreRegex = /^_/;
|
|
593
|
+
const selectorRegex = /&|@/;
|
|
594
|
+
var Conditions = class {
|
|
595
|
+
options;
|
|
596
|
+
values;
|
|
597
|
+
breakpoints;
|
|
598
|
+
constructor(options) {
|
|
599
|
+
this.options = options;
|
|
600
|
+
const { breakpoints: breakpointValues = {}, conditions = {} } = options;
|
|
601
|
+
const breakpoints = new Breakpoints(breakpointValues);
|
|
602
|
+
this.breakpoints = breakpoints;
|
|
603
|
+
const entries = Object.entries(conditions).map(([key, value]) => [`_${key}`, parseCondition(value)]);
|
|
604
|
+
const containers = this.setupContainers();
|
|
605
|
+
const themes = this.setupThemes();
|
|
606
|
+
this.values = {
|
|
607
|
+
...Object.fromEntries(entries),
|
|
608
|
+
...breakpoints.conditions,
|
|
609
|
+
...containers,
|
|
610
|
+
...themes
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
setupContainers = () => {
|
|
614
|
+
const { containerNames = [], containerSizes = {} } = this.options;
|
|
615
|
+
const containers = {};
|
|
616
|
+
containerNames.unshift("");
|
|
617
|
+
containerNames.forEach((name) => {
|
|
618
|
+
Object.entries(containerSizes).forEach(([size, value]) => {
|
|
619
|
+
const _value = (0, _bamboocss_shared.toRem)(value) ?? value;
|
|
620
|
+
containers[`@${name}/${size}`] = {
|
|
621
|
+
type: "at-rule",
|
|
622
|
+
name: "container",
|
|
623
|
+
value: _value,
|
|
624
|
+
raw: `@container ${name} (min-width: ${_value})`,
|
|
625
|
+
params: `${name} ${value}`
|
|
626
|
+
};
|
|
627
|
+
});
|
|
628
|
+
});
|
|
629
|
+
return containers;
|
|
630
|
+
};
|
|
631
|
+
setupThemes = () => {
|
|
632
|
+
const { themes = {} } = this.options;
|
|
633
|
+
const themeVariants = {};
|
|
634
|
+
Object.entries(themes).forEach(([theme, _themeVariant]) => {
|
|
635
|
+
const condName = this.getThemeName(theme);
|
|
636
|
+
const cond = parseCondition(this.getThemeSelector(theme) + " &");
|
|
637
|
+
if (!cond) return;
|
|
638
|
+
themeVariants[condName] = cond;
|
|
639
|
+
});
|
|
640
|
+
return themeVariants;
|
|
641
|
+
};
|
|
642
|
+
getThemeSelector = (name) => {
|
|
643
|
+
return `[data-bamboo-theme=${name}]`;
|
|
644
|
+
};
|
|
645
|
+
getThemeName = (theme) => {
|
|
646
|
+
return "_theme" + (0, _bamboocss_shared.capitalize)(theme);
|
|
647
|
+
};
|
|
648
|
+
finalize = (paths) => {
|
|
649
|
+
return paths.map((path) => {
|
|
650
|
+
if (this.has(path)) return path.replace(underscoreRegex, "");
|
|
651
|
+
if (selectorRegex.test(path)) return `[${(0, _bamboocss_shared.withoutSpace)(path.trim())}]`;
|
|
652
|
+
return path;
|
|
653
|
+
});
|
|
654
|
+
};
|
|
655
|
+
shift = (paths) => {
|
|
656
|
+
return paths.map((path) => path.trim()).sort((a, b) => {
|
|
657
|
+
const aIsCondition = this.isCondition(a);
|
|
658
|
+
const bIsCondition = this.isCondition(b);
|
|
659
|
+
if (aIsCondition && !bIsCondition) return 1;
|
|
660
|
+
if (!aIsCondition && bIsCondition) return -1;
|
|
661
|
+
if (!aIsCondition && !bIsCondition) return -1;
|
|
662
|
+
return 0;
|
|
663
|
+
});
|
|
664
|
+
};
|
|
665
|
+
segment = (paths) => {
|
|
666
|
+
const condition = [];
|
|
667
|
+
const selector = [];
|
|
668
|
+
for (const path of paths) if (this.isCondition(path)) condition.push(path);
|
|
669
|
+
else selector.push(path);
|
|
670
|
+
return {
|
|
671
|
+
condition,
|
|
672
|
+
selector
|
|
673
|
+
};
|
|
674
|
+
};
|
|
675
|
+
has = (key) => {
|
|
676
|
+
return Object.prototype.hasOwnProperty.call(this.values, key);
|
|
677
|
+
};
|
|
678
|
+
isCondition = (key) => {
|
|
679
|
+
return this.has(key) || !!this.getRaw(key) || (0, _bamboocss_shared.isBaseCondition)(key);
|
|
680
|
+
};
|
|
681
|
+
isEmpty = () => {
|
|
682
|
+
return Object.keys(this.values).length === 0;
|
|
683
|
+
};
|
|
684
|
+
get = (key) => {
|
|
685
|
+
return this.values[key]?.raw;
|
|
686
|
+
};
|
|
687
|
+
getRaw = (condNameOrQuery) => {
|
|
688
|
+
if (typeof condNameOrQuery === "string" && this.values[condNameOrQuery]) return this.values[condNameOrQuery];
|
|
689
|
+
try {
|
|
690
|
+
return parseCondition(condNameOrQuery);
|
|
691
|
+
} catch (error) {
|
|
692
|
+
const query = typeof condNameOrQuery === "string" ? condNameOrQuery : JSON.stringify(condNameOrQuery);
|
|
693
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
694
|
+
_bamboocss_logger.logger.warn("core:condition", `Failed to parse condition "${query}": ${message}`);
|
|
695
|
+
}
|
|
696
|
+
};
|
|
697
|
+
sort = (conditions) => {
|
|
698
|
+
const flattened = conditions.map(this.getRaw).filter(Boolean).flatMap((cond, index) => flattenCondition(cond, index));
|
|
699
|
+
flattened.sort((a, b) => {
|
|
700
|
+
const aIsAtRule = isAtRule(a.cond);
|
|
701
|
+
const bIsAtRule = isAtRule(b.cond);
|
|
702
|
+
if (aIsAtRule && !bIsAtRule) return -1;
|
|
703
|
+
if (!aIsAtRule && bIsAtRule) return 1;
|
|
704
|
+
const aIsPseudo = isPseudoElement(a.cond);
|
|
705
|
+
if (aIsPseudo !== isPseudoElement(b.cond)) return aIsPseudo ? 1 : -1;
|
|
706
|
+
return a.originalIndex - b.originalIndex;
|
|
707
|
+
});
|
|
708
|
+
return flattened.map((item) => item.cond);
|
|
709
|
+
};
|
|
710
|
+
normalize = (condition) => {
|
|
711
|
+
return (0, _bamboocss_shared.isObject)(condition) ? condition : this.getRaw(condition);
|
|
712
|
+
};
|
|
713
|
+
keys = () => {
|
|
714
|
+
return Object.keys(this.values);
|
|
715
|
+
};
|
|
716
|
+
saveOne = (key, value) => {
|
|
717
|
+
const parsed = parseCondition(value);
|
|
718
|
+
if (!parsed) return;
|
|
719
|
+
this.values[`_${key}`] = parsed;
|
|
720
|
+
};
|
|
721
|
+
remove(key) {
|
|
722
|
+
delete this.values[`_${key}`];
|
|
723
|
+
}
|
|
724
|
+
getSortedKeys = () => {
|
|
725
|
+
return Object.keys(this.values).sort((a, b) => {
|
|
726
|
+
const aCondition = this.values[a];
|
|
727
|
+
const bCondition = this.values[b];
|
|
728
|
+
return compareAtRuleOrMixed({
|
|
729
|
+
entry: {},
|
|
730
|
+
conditions: [aCondition]
|
|
731
|
+
}, {
|
|
732
|
+
entry: {},
|
|
733
|
+
conditions: [bCondition]
|
|
734
|
+
});
|
|
735
|
+
});
|
|
736
|
+
};
|
|
737
|
+
};
|
|
738
|
+
//#endregion
|
|
739
|
+
//#region src/file.ts
|
|
740
|
+
var FileEngine = class {
|
|
741
|
+
context;
|
|
742
|
+
constructor(context) {
|
|
743
|
+
this.context = context;
|
|
744
|
+
}
|
|
745
|
+
get forceConsistentTypeExtension() {
|
|
746
|
+
return this.context.config.forceConsistentTypeExtension || false;
|
|
747
|
+
}
|
|
748
|
+
get outExtension() {
|
|
749
|
+
return this.context.config.outExtension;
|
|
750
|
+
}
|
|
751
|
+
ext(file) {
|
|
752
|
+
return `${file}.${this.outExtension}`;
|
|
753
|
+
}
|
|
754
|
+
extDts(file) {
|
|
755
|
+
return `${file}.${this.outExtension === "mjs" && this.forceConsistentTypeExtension ? "d.mts" : "d.ts"}`;
|
|
756
|
+
}
|
|
757
|
+
__extDts(file) {
|
|
758
|
+
return this.forceConsistentTypeExtension ? this.extDts(file) : file;
|
|
759
|
+
}
|
|
760
|
+
import(mod, file) {
|
|
761
|
+
return `import { ${mod} } from '${this.ext(file)}';`;
|
|
762
|
+
}
|
|
763
|
+
importType(mod, file) {
|
|
764
|
+
return `import type { ${mod} } from '${this.__extDts(file)}';`;
|
|
765
|
+
}
|
|
766
|
+
exportType(mod, file) {
|
|
767
|
+
return `export type { ${mod} } from '${this.__extDts(file)}';`;
|
|
768
|
+
}
|
|
769
|
+
exportStar(file) {
|
|
770
|
+
return `export * from '${this.ext(file)}';`;
|
|
771
|
+
}
|
|
772
|
+
exportTypeStar(file) {
|
|
773
|
+
return `export * from '${this.__extDts(file)}';`;
|
|
774
|
+
}
|
|
775
|
+
isTypeFile(file) {
|
|
776
|
+
return file.endsWith(".d.ts") || file.endsWith(".d.mts");
|
|
777
|
+
}
|
|
778
|
+
jsDocComment(comment, options) {
|
|
779
|
+
const { deprecated, default: defaultValue } = options ?? {};
|
|
780
|
+
if (!comment && !deprecated && !defaultValue) return "";
|
|
781
|
+
const comments = ["/**"];
|
|
782
|
+
if (comment) comments.push(` * ${comment}`, "\n");
|
|
783
|
+
if (deprecated) {
|
|
784
|
+
const suffix = (0, _bamboocss_shared.isString)(deprecated) ? ` ${deprecated}` : "";
|
|
785
|
+
comments.push(` * @deprecated${suffix}`);
|
|
786
|
+
}
|
|
787
|
+
if (defaultValue) comments.push(` * @default ${defaultValue}`);
|
|
788
|
+
comments.push(" */");
|
|
789
|
+
return comments.filter((c) => c.trim().length).join("\n");
|
|
790
|
+
}
|
|
791
|
+
/**
|
|
792
|
+
* convert import type { CompositionStyleObject } from './system-types'
|
|
793
|
+
* to import type { CompositionStyleObject } from './system-types.d.ts'
|
|
794
|
+
*/
|
|
795
|
+
rewriteTypeImport(code) {
|
|
796
|
+
return code.replace(/import\s+type\s+\{([^}]+)\}\s+from\s+['"]([^'"]+)['"]/g, this.importType("$1", "$2"));
|
|
797
|
+
}
|
|
798
|
+
};
|
|
799
|
+
//#endregion
|
|
800
|
+
//#region src/unitless.ts
|
|
801
|
+
const keys = {
|
|
802
|
+
animationIterationCount: true,
|
|
803
|
+
aspectRatio: true,
|
|
804
|
+
borderImageOutset: true,
|
|
805
|
+
borderImageSlice: true,
|
|
806
|
+
borderImageWidth: true,
|
|
807
|
+
boxFlex: true,
|
|
808
|
+
boxFlexGroup: true,
|
|
809
|
+
boxOrdinalGroup: true,
|
|
810
|
+
columnCount: true,
|
|
811
|
+
columns: true,
|
|
812
|
+
flex: true,
|
|
813
|
+
flexGrow: true,
|
|
814
|
+
flexPositive: true,
|
|
815
|
+
flexShrink: true,
|
|
816
|
+
flexNegative: true,
|
|
817
|
+
flexOrder: true,
|
|
818
|
+
gridRow: true,
|
|
819
|
+
gridRowEnd: true,
|
|
820
|
+
gridRowSpan: true,
|
|
821
|
+
gridRowStart: true,
|
|
822
|
+
gridColumn: true,
|
|
823
|
+
gridColumnEnd: true,
|
|
824
|
+
gridColumnSpan: true,
|
|
825
|
+
gridColumnStart: true,
|
|
826
|
+
msGridRow: true,
|
|
827
|
+
msGridRowSpan: true,
|
|
828
|
+
msGridColumn: true,
|
|
829
|
+
msGridColumnSpan: true,
|
|
830
|
+
fontWeight: true,
|
|
831
|
+
lineClamp: true,
|
|
832
|
+
lineHeight: true,
|
|
833
|
+
opacity: true,
|
|
834
|
+
order: true,
|
|
835
|
+
orphans: true,
|
|
836
|
+
scale: true,
|
|
837
|
+
tabSize: true,
|
|
838
|
+
widows: true,
|
|
839
|
+
zIndex: true,
|
|
840
|
+
zoom: true,
|
|
841
|
+
WebkitLineClamp: true,
|
|
842
|
+
fillOpacity: true,
|
|
843
|
+
floodOpacity: true,
|
|
844
|
+
stopOpacity: true,
|
|
845
|
+
strokeDasharray: true,
|
|
846
|
+
strokeDashoffset: true,
|
|
847
|
+
strokeMiterlimit: true,
|
|
848
|
+
strokeOpacity: true,
|
|
849
|
+
strokeWidth: true
|
|
850
|
+
};
|
|
851
|
+
const unitlessProperties = /* @__PURE__ */ new Set();
|
|
852
|
+
Object.keys(keys).forEach((key) => {
|
|
853
|
+
unitlessProperties.add(key);
|
|
854
|
+
unitlessProperties.add((0, _bamboocss_shared.hypenateProperty)(key));
|
|
855
|
+
});
|
|
856
|
+
//#endregion
|
|
857
|
+
//#region src/stringify.ts
|
|
858
|
+
const toString = Object.prototype.toString;
|
|
859
|
+
/** Returns a string of CSS from an object of CSS. */
|
|
860
|
+
function stringify(value) {
|
|
861
|
+
/** Set used to manage the opened and closed state of rules. */
|
|
862
|
+
const used = /* @__PURE__ */ new WeakSet();
|
|
863
|
+
const write = (cssText, selectors, conditions, name, data, isAtRuleLike, isVariableLike) => {
|
|
864
|
+
if (data === false) return "";
|
|
865
|
+
for (let i = 0; i < conditions.length; ++i) if (!used.has(conditions[i])) {
|
|
866
|
+
used.add(conditions[i]);
|
|
867
|
+
cssText += `${conditions[i]} {`;
|
|
868
|
+
}
|
|
869
|
+
if (selectors.length && !used.has(selectors)) {
|
|
870
|
+
used.add(selectors);
|
|
871
|
+
cssText += `${selectors.map((s) => s.replace("& ", ""))} {`;
|
|
872
|
+
}
|
|
873
|
+
let value = data;
|
|
874
|
+
if (typeof value === "number") {
|
|
875
|
+
if (!(value === 0 || unitlessProperties.has(name) || isVariableLike)) value = `${value}px`;
|
|
876
|
+
}
|
|
877
|
+
if (isAtRuleLike) name = `${name} `;
|
|
878
|
+
else if (isVariableLike) name = `${name}: `;
|
|
879
|
+
else name = `${(0, _bamboocss_shared.hypenateProperty)(name)}: `;
|
|
880
|
+
cssText += `${name + String(value)};\n`;
|
|
881
|
+
return cssText;
|
|
882
|
+
};
|
|
883
|
+
const parse = (style, selectors, conditions) => {
|
|
884
|
+
let cssText = "";
|
|
885
|
+
for (const name in style) {
|
|
886
|
+
const isAtRuleLike = name[0] === "@";
|
|
887
|
+
const isVariableLike = !isAtRuleLike && name.startsWith("--");
|
|
888
|
+
const rules = isAtRuleLike && Array.isArray(style[name]) ? style[name] : [style[name]];
|
|
889
|
+
for (const data of rules) {
|
|
890
|
+
if (!(typeof data === "object" && data && data.toString === toString)) {
|
|
891
|
+
cssText = write(cssText, selectors, conditions, name, data, isAtRuleLike, isVariableLike);
|
|
892
|
+
continue;
|
|
893
|
+
}
|
|
894
|
+
if (used.has(selectors)) {
|
|
895
|
+
used.delete(selectors);
|
|
896
|
+
cssText += "}";
|
|
897
|
+
}
|
|
898
|
+
let usedName = Object(name);
|
|
899
|
+
let nextSelectors;
|
|
900
|
+
if (isAtRuleLike) {
|
|
901
|
+
if (selectors.length && name.includes("@scope") && name.includes("&")) {
|
|
902
|
+
const resolvedSelectors = getResolvedSelectors(selectors, parseSelectors(name));
|
|
903
|
+
usedName = Object(resolvedSelectors[0]);
|
|
904
|
+
}
|
|
905
|
+
nextSelectors = selectors;
|
|
906
|
+
cssText += parse(data, nextSelectors, conditions.concat(usedName));
|
|
907
|
+
} else {
|
|
908
|
+
const nestedSelectors = parseSelectors(name);
|
|
909
|
+
nextSelectors = selectors.length ? getResolvedSelectors(selectors, nestedSelectors) : nestedSelectors;
|
|
910
|
+
cssText += parse(data, nextSelectors, conditions);
|
|
911
|
+
}
|
|
912
|
+
if (used.has(usedName)) {
|
|
913
|
+
used.delete(usedName);
|
|
914
|
+
cssText += "}\n";
|
|
915
|
+
}
|
|
916
|
+
if (used.has(nextSelectors)) {
|
|
917
|
+
used.delete(nextSelectors);
|
|
918
|
+
cssText += "}\n";
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
return cssText;
|
|
923
|
+
};
|
|
924
|
+
return parse(value, [], []);
|
|
925
|
+
}
|
|
926
|
+
/**
|
|
927
|
+
* Returns a list of separated selectors from a selector string.
|
|
928
|
+
* @example
|
|
929
|
+
* parseSelectors('a, button') // ['a', 'button']
|
|
930
|
+
* parseSelectors('.switch:is(:checked, [data-checked]).dark, .dark .switch:is(:checked, [data-checked])') // ['.switch:is(:checked, [data-checked]).dark', '.dark .switch:is(:checked, [data-checked])']
|
|
931
|
+
* parseSelectors('&:is(:disabled, [disabled], [data-disabled]), .another') // [':is(:disabled, [disabled], [data-disabled])', '.another']
|
|
932
|
+
*/
|
|
933
|
+
function parseSelectors(selector) {
|
|
934
|
+
const result = [];
|
|
935
|
+
let parenCount = 0;
|
|
936
|
+
let currentSelector = "";
|
|
937
|
+
let inEscape = false;
|
|
938
|
+
for (let i = 0; i < selector.length; i++) {
|
|
939
|
+
const char = selector[i];
|
|
940
|
+
if (char === "\\" && !inEscape) {
|
|
941
|
+
inEscape = true;
|
|
942
|
+
currentSelector += char;
|
|
943
|
+
continue;
|
|
944
|
+
}
|
|
945
|
+
if (inEscape) {
|
|
946
|
+
inEscape = false;
|
|
947
|
+
currentSelector += char;
|
|
948
|
+
continue;
|
|
949
|
+
}
|
|
950
|
+
if (char === "(") parenCount++;
|
|
951
|
+
else if (char === ")") parenCount--;
|
|
952
|
+
if (char === "," && parenCount === 0) {
|
|
953
|
+
result.push(currentSelector.trim());
|
|
954
|
+
currentSelector = "";
|
|
955
|
+
} else currentSelector += char;
|
|
956
|
+
}
|
|
957
|
+
if (currentSelector) result.push(currentSelector.trim());
|
|
958
|
+
return result;
|
|
959
|
+
}
|
|
960
|
+
const parentSelectorRegex = /&/g;
|
|
961
|
+
const descendantSelectorRegex = /[ +>|~]/g;
|
|
962
|
+
const surroundedRegex = /&.*&/g;
|
|
963
|
+
/**
|
|
964
|
+
* Returns selectors resolved from parent selectors and nested selectors.
|
|
965
|
+
* @example
|
|
966
|
+
* getResolvedSelectors(['a', 'button'], ['&:hover', '&:focus']) // ['a:hover', 'a:focus', 'button:hover', 'button:focus']
|
|
967
|
+
* getResolvedSelectors(['.switch:is(:checked, [data-checked]).dark, .dark .switch:is(:checked, [data-checked])'], ['&:hover', '&:focus']) // ['.switch:is(:checked, [data-checked]).dark:hover', '.switch:is(:checked, [data-checked]).dark:focus', '.dark .switch:is(:checked, [data-checked]):hover', '.dark .switch:is(:checked, [data-checked]):focus']
|
|
968
|
+
*
|
|
969
|
+
*/
|
|
970
|
+
const getResolvedSelectors = (parentSelectors, nestedSelectors) => {
|
|
971
|
+
const resolved = [];
|
|
972
|
+
parentSelectors.forEach((parentSelector) => {
|
|
973
|
+
resolved.push(...nestedSelectors.map((selector) => {
|
|
974
|
+
if (!selector.includes("&")) return parentSelector + " " + selector;
|
|
975
|
+
return selector.replace(parentSelectorRegex, descendantSelectorRegex.test(parentSelector) && surroundedRegex.test(selector) ? `:is(${parentSelector})` : parentSelector);
|
|
976
|
+
}));
|
|
977
|
+
});
|
|
978
|
+
return resolved;
|
|
979
|
+
};
|
|
980
|
+
//#endregion
|
|
981
|
+
//#region src/global-fontface.ts
|
|
982
|
+
var GlobalFontface = class {
|
|
983
|
+
options;
|
|
984
|
+
names;
|
|
985
|
+
constructor(options) {
|
|
986
|
+
this.options = options;
|
|
987
|
+
const { globalFontface = {} } = options;
|
|
988
|
+
this.names = Object.keys(globalFontface);
|
|
989
|
+
}
|
|
990
|
+
isEmpty() {
|
|
991
|
+
return this.names.length === 0;
|
|
992
|
+
}
|
|
993
|
+
toString() {
|
|
994
|
+
const { globalFontface = {} } = this.options;
|
|
995
|
+
return stringifyGlobalFontface(globalFontface);
|
|
996
|
+
}
|
|
997
|
+
};
|
|
998
|
+
const stringifyGlobalFontface = (globalFontface) => {
|
|
999
|
+
if (!globalFontface) return "";
|
|
1000
|
+
const lines = [];
|
|
1001
|
+
Object.entries(globalFontface).forEach(([key, value]) => {
|
|
1002
|
+
(Array.isArray(value) ? value : [value]).forEach((v) => {
|
|
1003
|
+
lines.push(stringifyFontface(key, v));
|
|
1004
|
+
});
|
|
1005
|
+
});
|
|
1006
|
+
return lines.join("\n\n");
|
|
1007
|
+
};
|
|
1008
|
+
function stringifyFontface(fontFamily, config) {
|
|
1009
|
+
return `@font-face {
|
|
1010
|
+
font-family: ${fontFamily};
|
|
1011
|
+
${stringify(config)}
|
|
1012
|
+
}`;
|
|
1013
|
+
}
|
|
1014
|
+
//#endregion
|
|
1015
|
+
//#region src/global-position-try.ts
|
|
1016
|
+
var GlobalPositionTry = class {
|
|
1017
|
+
opts;
|
|
1018
|
+
names;
|
|
1019
|
+
constructor(opts) {
|
|
1020
|
+
this.opts = opts;
|
|
1021
|
+
this.names = Object.keys(opts.globalPositionTry ?? {});
|
|
1022
|
+
}
|
|
1023
|
+
isEmpty() {
|
|
1024
|
+
return this.names.length === 0;
|
|
1025
|
+
}
|
|
1026
|
+
toString() {
|
|
1027
|
+
return stringifyGlobalPositionTry(this.opts.globalPositionTry ?? {});
|
|
1028
|
+
}
|
|
1029
|
+
};
|
|
1030
|
+
const stringifyGlobalPositionTry = (dfns) => {
|
|
1031
|
+
if (!dfns) return "";
|
|
1032
|
+
const lines = [];
|
|
1033
|
+
Object.entries(dfns).forEach(([key, value]) => {
|
|
1034
|
+
(Array.isArray(value) ? value : [value]).forEach((v) => {
|
|
1035
|
+
lines.push(stringifyPositionTry(key, v));
|
|
1036
|
+
});
|
|
1037
|
+
});
|
|
1038
|
+
return lines.join("\n\n");
|
|
1039
|
+
};
|
|
1040
|
+
const ident = (key) => key.startsWith("--") ? key : `--${key}`;
|
|
1041
|
+
function stringifyPositionTry(key, config) {
|
|
1042
|
+
return `@position-try ${ident(key)} {
|
|
1043
|
+
${stringify(config)}
|
|
1044
|
+
}`;
|
|
1045
|
+
}
|
|
1046
|
+
//#endregion
|
|
1047
|
+
//#region src/global-vars.ts
|
|
1048
|
+
var GlobalVars = class {
|
|
1049
|
+
options;
|
|
1050
|
+
keys;
|
|
1051
|
+
vars;
|
|
1052
|
+
names;
|
|
1053
|
+
constructor(options) {
|
|
1054
|
+
this.options = options;
|
|
1055
|
+
const { globalVars = {} } = options;
|
|
1056
|
+
this.keys = new Set(Object.keys(globalVars));
|
|
1057
|
+
const arr = Array.from(this.keys);
|
|
1058
|
+
this.names = arr.map((v) => `${v.slice(2)}`);
|
|
1059
|
+
this.vars = arr.map((v) => `var(${v})`);
|
|
1060
|
+
}
|
|
1061
|
+
isEmpty() {
|
|
1062
|
+
return this.keys.size === 0;
|
|
1063
|
+
}
|
|
1064
|
+
toString() {
|
|
1065
|
+
const { globalVars = {}, cssVarRoot } = this.options;
|
|
1066
|
+
return stringifyGlobalVars(globalVars, cssVarRoot);
|
|
1067
|
+
}
|
|
1068
|
+
};
|
|
1069
|
+
const stringifyGlobalVars = (globalVars, cssVarRoot) => {
|
|
1070
|
+
if (!globalVars) return "";
|
|
1071
|
+
const decls = [];
|
|
1072
|
+
const vars = { [cssVarRoot]: {} };
|
|
1073
|
+
const base = vars[cssVarRoot];
|
|
1074
|
+
Object.entries(globalVars).forEach(([key, value]) => {
|
|
1075
|
+
if (typeof value === "string") {
|
|
1076
|
+
base[key] = value;
|
|
1077
|
+
return;
|
|
1078
|
+
}
|
|
1079
|
+
const css = stringifyProperty(key, value);
|
|
1080
|
+
decls.push(css);
|
|
1081
|
+
});
|
|
1082
|
+
const lines = [];
|
|
1083
|
+
lines.push(stringify(vars));
|
|
1084
|
+
lines.push(...decls);
|
|
1085
|
+
return lines.join("\n\n");
|
|
1086
|
+
};
|
|
1087
|
+
function stringifyProperty(key, config) {
|
|
1088
|
+
return outdent.outdent`@property ${key} {
|
|
1089
|
+
syntax: '${config.syntax}';
|
|
1090
|
+
inherits: ${config.inherits};
|
|
1091
|
+
initial-value: ${config.initialValue ?? "initial"};
|
|
1092
|
+
}`;
|
|
1093
|
+
}
|
|
1094
|
+
//#endregion
|
|
1095
|
+
//#region src/rule-processor.ts
|
|
1096
|
+
var RuleProcessor = class {
|
|
1097
|
+
context;
|
|
1098
|
+
encoder;
|
|
1099
|
+
decoder;
|
|
1100
|
+
sheet;
|
|
1101
|
+
constructor(context) {
|
|
1102
|
+
this.context = context;
|
|
1103
|
+
this.encoder = context.encoder;
|
|
1104
|
+
this.decoder = context.decoder;
|
|
1105
|
+
this.sheet = context.createSheet();
|
|
1106
|
+
}
|
|
1107
|
+
getParamsOrThrow() {
|
|
1108
|
+
if (!Boolean(this.encoder && this.decoder && this.sheet)) throw new _bamboocss_shared.BambooError("MISSING_PARAMS", "RuleProcessor is missing params, please call `clone` first");
|
|
1109
|
+
return {
|
|
1110
|
+
encoder: this.encoder,
|
|
1111
|
+
decoder: this.decoder,
|
|
1112
|
+
sheet: this.sheet
|
|
1113
|
+
};
|
|
1114
|
+
}
|
|
1115
|
+
clone() {
|
|
1116
|
+
this.encoder = this.context.encoder.clone();
|
|
1117
|
+
this.decoder = this.context.decoder.clone();
|
|
1118
|
+
this.sheet = this.context.createSheet();
|
|
1119
|
+
return this;
|
|
1120
|
+
}
|
|
1121
|
+
toCss(options) {
|
|
1122
|
+
const { decoder, sheet } = this.getParamsOrThrow();
|
|
1123
|
+
sheet.processDecoder(decoder);
|
|
1124
|
+
return sheet.toCss(options);
|
|
1125
|
+
}
|
|
1126
|
+
css(styles) {
|
|
1127
|
+
const { encoder, decoder } = this.getParamsOrThrow();
|
|
1128
|
+
encoder.processAtomic(styles);
|
|
1129
|
+
decoder.collect(encoder);
|
|
1130
|
+
return {
|
|
1131
|
+
styles,
|
|
1132
|
+
getClassNames: () => Array.from(decoder.classNames.keys()),
|
|
1133
|
+
toCss: this.toCss.bind(this)
|
|
1134
|
+
};
|
|
1135
|
+
}
|
|
1136
|
+
grouped(styles) {
|
|
1137
|
+
const { encoder, decoder } = this.getParamsOrThrow();
|
|
1138
|
+
encoder.processGrouped(styles);
|
|
1139
|
+
decoder.collect(encoder);
|
|
1140
|
+
const groupedResults = Array.from(decoder.grouped);
|
|
1141
|
+
return {
|
|
1142
|
+
styles,
|
|
1143
|
+
getClassNames: () => groupedResults.map((r) => r.className),
|
|
1144
|
+
toCss: this.toCss.bind(this)
|
|
1145
|
+
};
|
|
1146
|
+
}
|
|
1147
|
+
cva(recipeConfig) {
|
|
1148
|
+
const { encoder, decoder } = this.getParamsOrThrow();
|
|
1149
|
+
encoder.processAtomicRecipe(recipeConfig);
|
|
1150
|
+
decoder.collect(encoder);
|
|
1151
|
+
return {
|
|
1152
|
+
config: recipeConfig,
|
|
1153
|
+
getClassNames: () => Array.from(decoder.classNames.keys()),
|
|
1154
|
+
toCss: this.toCss.bind(this)
|
|
1155
|
+
};
|
|
1156
|
+
}
|
|
1157
|
+
sva(recipeConfig) {
|
|
1158
|
+
const { encoder, decoder } = this;
|
|
1159
|
+
this.getParamsOrThrow();
|
|
1160
|
+
encoder.processAtomicSlotRecipe(recipeConfig);
|
|
1161
|
+
decoder.collect(encoder);
|
|
1162
|
+
return {
|
|
1163
|
+
config: recipeConfig,
|
|
1164
|
+
getClassNames: () => Array.from(decoder.classNames.keys()),
|
|
1165
|
+
toCss: this.toCss.bind(this)
|
|
1166
|
+
};
|
|
1167
|
+
}
|
|
1168
|
+
recipe(name, variants = {}) {
|
|
1169
|
+
const { encoder, decoder } = this;
|
|
1170
|
+
this.getParamsOrThrow();
|
|
1171
|
+
encoder.processRecipe(name, variants);
|
|
1172
|
+
decoder.collect(encoder);
|
|
1173
|
+
return {
|
|
1174
|
+
variants,
|
|
1175
|
+
getClassNames: () => Array.from(decoder.classNames.keys()),
|
|
1176
|
+
toCss: this.toCss.bind(this)
|
|
1177
|
+
};
|
|
1178
|
+
}
|
|
1179
|
+
};
|
|
1180
|
+
//#endregion
|
|
1181
|
+
//#region src/hooks-api.ts
|
|
1182
|
+
var HooksApi = class {
|
|
1183
|
+
ctx;
|
|
1184
|
+
processor;
|
|
1185
|
+
constructor(ctx) {
|
|
1186
|
+
this.ctx = ctx;
|
|
1187
|
+
this.processor = new RuleProcessor(ctx);
|
|
1188
|
+
}
|
|
1189
|
+
get config() {
|
|
1190
|
+
return this.ctx.conf.config;
|
|
1191
|
+
}
|
|
1192
|
+
get configPath() {
|
|
1193
|
+
return this.ctx.conf.path;
|
|
1194
|
+
}
|
|
1195
|
+
get configDependencies() {
|
|
1196
|
+
return this.ctx.conf.dependencies;
|
|
1197
|
+
}
|
|
1198
|
+
get classNames() {
|
|
1199
|
+
return this.ctx.utility.classNames;
|
|
1200
|
+
}
|
|
1201
|
+
get generatedClassNames() {
|
|
1202
|
+
return this.ctx.decoder.classNames;
|
|
1203
|
+
}
|
|
1204
|
+
};
|
|
1205
|
+
//#endregion
|
|
1206
|
+
//#region src/file-matcher.ts
|
|
1207
|
+
const cssEntrypointFns = new Set([
|
|
1208
|
+
"css",
|
|
1209
|
+
"cva",
|
|
1210
|
+
"sva"
|
|
1211
|
+
]);
|
|
1212
|
+
var FileMatcher = class {
|
|
1213
|
+
context;
|
|
1214
|
+
imports;
|
|
1215
|
+
namespaces = /* @__PURE__ */ new Map();
|
|
1216
|
+
importMap;
|
|
1217
|
+
cssAliases = /* @__PURE__ */ new Set();
|
|
1218
|
+
cvaAliases = /* @__PURE__ */ new Set();
|
|
1219
|
+
svaAliases = /* @__PURE__ */ new Set();
|
|
1220
|
+
tokenAliases = /* @__PURE__ */ new Set();
|
|
1221
|
+
jsxFactoryAliases = /* @__PURE__ */ new Set();
|
|
1222
|
+
recipeAliases = /* @__PURE__ */ new Set();
|
|
1223
|
+
patternAliases = /* @__PURE__ */ new Set();
|
|
1224
|
+
propertiesMap = /* @__PURE__ */ new Map();
|
|
1225
|
+
functions = /* @__PURE__ */ new Map();
|
|
1226
|
+
components = /* @__PURE__ */ new Map();
|
|
1227
|
+
constructor(context, opts) {
|
|
1228
|
+
this.context = context;
|
|
1229
|
+
const { value, importMap } = opts;
|
|
1230
|
+
this.importMap = importMap;
|
|
1231
|
+
this.imports = value;
|
|
1232
|
+
this.imports.forEach((result) => {
|
|
1233
|
+
if (result.kind === "namespace") this.namespaces.set(result.name, result);
|
|
1234
|
+
});
|
|
1235
|
+
this.assignAliases();
|
|
1236
|
+
this.assignProperties();
|
|
1237
|
+
}
|
|
1238
|
+
assignAliases() {
|
|
1239
|
+
const isCssEntrypoint = this.createMatch(this.importMap.css, Array.from(cssEntrypointFns));
|
|
1240
|
+
const isTokensEntrypoint = this.createMatch(this.importMap.tokens, ["token"]);
|
|
1241
|
+
this.imports.forEach((result) => {
|
|
1242
|
+
if (this.isValidRecipe(result.alias)) this.recipeAliases.add(result.alias);
|
|
1243
|
+
if (this.isValidPattern(result.alias)) this.patternAliases.add(result.alias);
|
|
1244
|
+
if (isCssEntrypoint(result.alias)) {
|
|
1245
|
+
if (result.name === "css") this.cssAliases.add(result.alias);
|
|
1246
|
+
if (result.name === "cva") this.cvaAliases.add(result.alias);
|
|
1247
|
+
if (result.name === "sva") this.svaAliases.add(result.alias);
|
|
1248
|
+
}
|
|
1249
|
+
if (isTokensEntrypoint(result.alias)) {
|
|
1250
|
+
if (result.name === "token") this.tokenAliases.add(result.alias);
|
|
1251
|
+
}
|
|
1252
|
+
if (result.name === this.context.jsx.factoryName) this.jsxFactoryAliases.add(result.alias);
|
|
1253
|
+
if (result.kind === "namespace") {
|
|
1254
|
+
if (this.importMap.pattern.some((m) => result.mod.includes(m))) this.context.patterns.keys.forEach((pattern) => {
|
|
1255
|
+
this.patternAliases.add(pattern);
|
|
1256
|
+
});
|
|
1257
|
+
if (this.importMap.recipe.some((m) => result.mod.includes(m))) this.context.recipes.keys.forEach((recipe) => {
|
|
1258
|
+
this.recipeAliases.add(recipe);
|
|
1259
|
+
});
|
|
1260
|
+
}
|
|
1261
|
+
});
|
|
1262
|
+
}
|
|
1263
|
+
assignProperties() {
|
|
1264
|
+
this.context.jsx.nodes.forEach((node) => {
|
|
1265
|
+
this.getAliases(node.jsxName).forEach((alias) => {
|
|
1266
|
+
node.props?.forEach((prop) => this.propertiesMap.set(prop, true));
|
|
1267
|
+
this.functions.set(node.baseName, this.propertiesMap);
|
|
1268
|
+
this.functions.set(alias, this.propertiesMap);
|
|
1269
|
+
this.components.set(alias, this.propertiesMap);
|
|
1270
|
+
});
|
|
1271
|
+
});
|
|
1272
|
+
}
|
|
1273
|
+
isEmpty = () => {
|
|
1274
|
+
return this.imports.length === 0;
|
|
1275
|
+
};
|
|
1276
|
+
toString = () => {
|
|
1277
|
+
return this.imports.map((item) => item.alias).join(", ");
|
|
1278
|
+
};
|
|
1279
|
+
find = (id) => {
|
|
1280
|
+
return this.imports.find((o) => o.alias === id);
|
|
1281
|
+
};
|
|
1282
|
+
createMatch = (mods, keys) => {
|
|
1283
|
+
const matchingImports = this.imports.filter((o) => {
|
|
1284
|
+
const isFromMod = mods.some((m) => o.mod.includes(m) || o.importMapValue?.includes(m));
|
|
1285
|
+
const isOneOfKeys = o.kind === "namespace" ? true : keys.includes(o.name);
|
|
1286
|
+
return isFromMod && isOneOfKeys;
|
|
1287
|
+
});
|
|
1288
|
+
return (0, _bamboocss_shared.memo)((id) => {
|
|
1289
|
+
return !!matchingImports.find((mod) => {
|
|
1290
|
+
if (mod.kind === "namespace") return keys.includes(id.replace(`${mod.alias}.`, ""));
|
|
1291
|
+
return mod.alias === id || mod.name === id;
|
|
1292
|
+
});
|
|
1293
|
+
});
|
|
1294
|
+
};
|
|
1295
|
+
match = (id) => {
|
|
1296
|
+
return !!this.find(id);
|
|
1297
|
+
};
|
|
1298
|
+
getName = (id) => {
|
|
1299
|
+
return this.find(id)?.name || id;
|
|
1300
|
+
};
|
|
1301
|
+
getAliases = (id) => {
|
|
1302
|
+
return this.imports.filter((o) => o.name === id).map((o) => o.alias || id);
|
|
1303
|
+
};
|
|
1304
|
+
_patternsMatcher;
|
|
1305
|
+
isValidPattern = (id) => {
|
|
1306
|
+
this._patternsMatcher ||= this.createMatch(this.importMap.pattern, this.context.patterns.keys);
|
|
1307
|
+
return this._patternsMatcher(id);
|
|
1308
|
+
};
|
|
1309
|
+
_recipesMatcher;
|
|
1310
|
+
isValidRecipe = (id) => {
|
|
1311
|
+
this._recipesMatcher ||= this.createMatch(this.importMap.recipe, this.context.recipes.keys);
|
|
1312
|
+
return this._recipesMatcher(id);
|
|
1313
|
+
};
|
|
1314
|
+
isRawFn = (fnName) => {
|
|
1315
|
+
const name = fnName.split(".raw")[0] ?? "";
|
|
1316
|
+
return name === "css" || this.cssAliases.has(name) || this.cvaAliases.has(name) || this.svaAliases.has(name) || this.isValidPattern(name) || this.isValidRecipe(name);
|
|
1317
|
+
};
|
|
1318
|
+
isNamespaced = (fnName) => {
|
|
1319
|
+
return this.namespaces.has(fnName.split(".")[0]);
|
|
1320
|
+
};
|
|
1321
|
+
normalizeFnName = (fnName) => {
|
|
1322
|
+
let name = fnName;
|
|
1323
|
+
if (this.isNamespaced(fnName)) name = name.split(".").slice(1).join(".");
|
|
1324
|
+
if (this.isRawFn(name)) return name.replace(".raw", "");
|
|
1325
|
+
return name;
|
|
1326
|
+
};
|
|
1327
|
+
isAliasFnName = (0, _bamboocss_shared.memo)((fnName) => {
|
|
1328
|
+
return this.cvaAliases.has(fnName) || this.cssAliases.has(fnName) || this.svaAliases.has(fnName) || this.tokenAliases.has(fnName) || this.isJsxFactory(fnName);
|
|
1329
|
+
});
|
|
1330
|
+
isTokenAlias = (fnName) => {
|
|
1331
|
+
return this.tokenAliases.has(fnName);
|
|
1332
|
+
};
|
|
1333
|
+
matchFn = (0, _bamboocss_shared.memo)((fnName) => {
|
|
1334
|
+
if (this.recipeAliases.has(fnName) || this.patternAliases.has(fnName)) return true;
|
|
1335
|
+
if (this.isAliasFnName(fnName) || this.isRawFn(fnName)) return true;
|
|
1336
|
+
if (this.functions.has(fnName)) return true;
|
|
1337
|
+
const [namespace, identifier] = fnName.split(".");
|
|
1338
|
+
const ns = this.namespaces.get(namespace);
|
|
1339
|
+
if (ns) {
|
|
1340
|
+
if (this.importMap.css.some((m) => ns.mod.includes(m)) && cssEntrypointFns.has(identifier)) return true;
|
|
1341
|
+
if (this.importMap.tokens.some((m) => ns.mod.includes(m)) && identifier === "token") return true;
|
|
1342
|
+
if (this.importMap.recipe.some((m) => ns.mod.includes(m)) && this.recipeAliases.has(identifier)) return true;
|
|
1343
|
+
if (this.importMap.pattern.some((m) => ns.mod.includes(m)) && this.patternAliases.has(identifier)) return true;
|
|
1344
|
+
return this.functions.has(identifier);
|
|
1345
|
+
}
|
|
1346
|
+
return false;
|
|
1347
|
+
});
|
|
1348
|
+
isJsxFactory = (0, _bamboocss_shared.memo)((tagName) => {
|
|
1349
|
+
const { jsx } = this.context;
|
|
1350
|
+
if (!jsx.isEnabled) return false;
|
|
1351
|
+
for (const alias of this.jsxFactoryAliases) if (tagName.startsWith(alias)) return true;
|
|
1352
|
+
const [namespace, identifier] = tagName.split(".");
|
|
1353
|
+
const ns = this.namespaces.get(namespace);
|
|
1354
|
+
if (ns && this.importMap.jsx.some((m) => ns.mod.includes(m)) && identifier === this.context.jsx.factoryName) return true;
|
|
1355
|
+
});
|
|
1356
|
+
isBambooComponent = (0, _bamboocss_shared.memo)((tagName) => {
|
|
1357
|
+
if (!tagName) return false;
|
|
1358
|
+
const { jsx } = this.context;
|
|
1359
|
+
return this.components.has(tagName) || this.isJsxFactory(tagName) || jsx.isJsxTagRecipe(tagName) || jsx.isJsxTagPattern(tagName);
|
|
1360
|
+
});
|
|
1361
|
+
matchTag = (0, _bamboocss_shared.memo)((tagName) => {
|
|
1362
|
+
return this.isBambooComponent(tagName) || isUpperCase(tagName);
|
|
1363
|
+
});
|
|
1364
|
+
matchTagProp = (0, _bamboocss_shared.memo)((tagName, propName) => {
|
|
1365
|
+
const { jsx, isValidProperty } = this.context;
|
|
1366
|
+
switch (jsx.styleProps) {
|
|
1367
|
+
case "all": return Boolean(this.components.get(tagName)?.has(propName)) || isValidProperty(propName) || this.propertiesMap.has(propName) || jsx.isRecipeOrPatternProp(tagName, propName) || propName.endsWith("Css");
|
|
1368
|
+
case "minimal": return propName === "css" || propName.endsWith("Css") || jsx.isRecipeOrPatternProp(tagName, propName);
|
|
1369
|
+
case "none": return jsx.isRecipeOrPatternProp(tagName, propName);
|
|
1370
|
+
default: return false;
|
|
1371
|
+
}
|
|
1372
|
+
});
|
|
1373
|
+
};
|
|
1374
|
+
const isUpperCase = (value) => value[0] === value[0]?.toUpperCase();
|
|
1375
|
+
//#endregion
|
|
1376
|
+
//#region src/import-map.ts
|
|
1377
|
+
var ImportMap = class {
|
|
1378
|
+
context;
|
|
1379
|
+
value;
|
|
1380
|
+
matchers = {};
|
|
1381
|
+
outdir;
|
|
1382
|
+
constructor(context) {
|
|
1383
|
+
this.context = context;
|
|
1384
|
+
const { jsx } = this.context;
|
|
1385
|
+
this.outdir = this.getOutdir();
|
|
1386
|
+
const importMap = this.buildImportMap(context.config.importMap);
|
|
1387
|
+
this.matchers.css = this.createMatcher(importMap.css, [
|
|
1388
|
+
"css",
|
|
1389
|
+
"cva",
|
|
1390
|
+
"sva"
|
|
1391
|
+
]);
|
|
1392
|
+
this.matchers.tokens = this.createMatcher(importMap.tokens, ["token"]);
|
|
1393
|
+
this.matchers.recipe = this.createMatcher(importMap.recipe);
|
|
1394
|
+
this.matchers.pattern = this.createMatcher(importMap.pattern);
|
|
1395
|
+
if (jsx.isEnabled) this.matchers.jsx = this.createMatcher(importMap.jsx, jsx.names);
|
|
1396
|
+
this.value = importMap;
|
|
1397
|
+
}
|
|
1398
|
+
/**
|
|
1399
|
+
* Normalize one/many import map inputs to a single import map output with absolute paths.
|
|
1400
|
+
* @example
|
|
1401
|
+
* ```ts
|
|
1402
|
+
* importMap: '@acme/org'
|
|
1403
|
+
* ```
|
|
1404
|
+
*
|
|
1405
|
+
* will be normalized to
|
|
1406
|
+
* ```ts
|
|
1407
|
+
* {
|
|
1408
|
+
* css: ['@acme/org/css'],
|
|
1409
|
+
* recipe: ['@acme/org/recipes'],
|
|
1410
|
+
* pattern: ['@acme/org/patterns'],
|
|
1411
|
+
* jsx: ['@acme/org/jsx'],
|
|
1412
|
+
* tokens: ['@acme/org/tokens'],
|
|
1413
|
+
* }
|
|
1414
|
+
* ```
|
|
1415
|
+
*
|
|
1416
|
+
* @exammple
|
|
1417
|
+
* importMap: ['@acme/org', '@foo/org', '@bar/org']
|
|
1418
|
+
* ```
|
|
1419
|
+
*
|
|
1420
|
+
* will be normalized to
|
|
1421
|
+
* ```ts
|
|
1422
|
+
* {
|
|
1423
|
+
* css: ['@acme/org/css', '@foo/org/css', '@bar/org/css'],
|
|
1424
|
+
* recipe: ['@acme/org/recipes', '@foo/org/recipes', '@bar/org/recipes'],
|
|
1425
|
+
* pattern: ['@acme/org/patterns', '@foo/org/patterns', '@bar/org/patterns'],
|
|
1426
|
+
* jsx: ['@acme/org/jsx', '@foo/org/jsx', '@bar/org/jsx'],
|
|
1427
|
+
* tokens: ['@acme/org/tokens', '@foo/org/tokens', '@bar/org/tokens'],
|
|
1428
|
+
* }
|
|
1429
|
+
* ```
|
|
1430
|
+
*/
|
|
1431
|
+
buildImportMap = (option) => {
|
|
1432
|
+
const output = {
|
|
1433
|
+
css: [],
|
|
1434
|
+
recipe: [],
|
|
1435
|
+
pattern: [],
|
|
1436
|
+
jsx: [],
|
|
1437
|
+
tokens: []
|
|
1438
|
+
};
|
|
1439
|
+
asArray(option).forEach((input) => {
|
|
1440
|
+
const normalized = this.normalize(input);
|
|
1441
|
+
output.css.push(...normalized.css);
|
|
1442
|
+
output.recipe.push(...normalized.recipe);
|
|
1443
|
+
output.pattern.push(...normalized.pattern);
|
|
1444
|
+
output.tokens.push(...normalized.tokens);
|
|
1445
|
+
if (normalized.jsx) output.jsx.push(...normalized.jsx);
|
|
1446
|
+
});
|
|
1447
|
+
return output;
|
|
1448
|
+
};
|
|
1449
|
+
fromString = (map) => {
|
|
1450
|
+
return {
|
|
1451
|
+
css: [[map, "css"].join("/")],
|
|
1452
|
+
recipe: [[map, "recipes"].join("/")],
|
|
1453
|
+
pattern: [[map, "patterns"].join("/")],
|
|
1454
|
+
jsx: [[map, "jsx"].join("/")],
|
|
1455
|
+
tokens: [[map, "tokens"].join("/")]
|
|
1456
|
+
};
|
|
1457
|
+
};
|
|
1458
|
+
fromInput = (map) => {
|
|
1459
|
+
const { css, recipes, patterns, jsx, tokens } = map ?? {};
|
|
1460
|
+
return {
|
|
1461
|
+
css: css ? asArray(css) : [[this.outdir, "css"].join("/")],
|
|
1462
|
+
recipe: recipes ? asArray(recipes) : [[this.outdir, "recipes"].join("/")],
|
|
1463
|
+
pattern: patterns ? asArray(patterns) : [[this.outdir, "patterns"].join("/")],
|
|
1464
|
+
jsx: jsx ? asArray(jsx) : [[this.outdir, "jsx"].join("/")],
|
|
1465
|
+
tokens: tokens ? asArray(tokens) : [[this.outdir, "tokens"].join("/")]
|
|
1466
|
+
};
|
|
1467
|
+
};
|
|
1468
|
+
getOutdir = () => {
|
|
1469
|
+
const { outdir } = this.context.config;
|
|
1470
|
+
const split = outdir.split("/");
|
|
1471
|
+
return split[split.length - 1];
|
|
1472
|
+
};
|
|
1473
|
+
normalize = (map) => {
|
|
1474
|
+
if ((0, _bamboocss_shared.isString)(map)) return this.fromString(map);
|
|
1475
|
+
return this.fromInput(map);
|
|
1476
|
+
};
|
|
1477
|
+
createMatcher = (mods, values) => {
|
|
1478
|
+
const regex = values ? new RegExp(`^(${values.join("|")})$`) : /.*/;
|
|
1479
|
+
const match = (value) => regex.test(value);
|
|
1480
|
+
return {
|
|
1481
|
+
mods,
|
|
1482
|
+
regex,
|
|
1483
|
+
match
|
|
1484
|
+
};
|
|
1485
|
+
};
|
|
1486
|
+
match = (result, resolveTsPath) => {
|
|
1487
|
+
if (!result) return false;
|
|
1488
|
+
for (const { regex, mods } of Object.values(this.matchers)) {
|
|
1489
|
+
if (result.kind !== "namespace" && !regex.test(result.name)) continue;
|
|
1490
|
+
if (mods.some((m) => result.mod.includes(m))) return true;
|
|
1491
|
+
const resolvedMod = resolveTsPath?.(result.mod);
|
|
1492
|
+
for (const mod of mods) {
|
|
1493
|
+
const absMod = [this.context.config.cwd, mod].join("/").replaceAll("\\", "/");
|
|
1494
|
+
if (resolvedMod?.includes(absMod) || resolvedMod === mod) {
|
|
1495
|
+
result.importMapValue = resolvedMod;
|
|
1496
|
+
return true;
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
return false;
|
|
1501
|
+
};
|
|
1502
|
+
file = (results) => {
|
|
1503
|
+
return new FileMatcher(this.context, {
|
|
1504
|
+
importMap: this.value,
|
|
1505
|
+
value: results
|
|
1506
|
+
});
|
|
1507
|
+
};
|
|
1508
|
+
};
|
|
1509
|
+
const asArray = (value) => Array.isArray(value) ? value : [value];
|
|
1510
|
+
//#endregion
|
|
1511
|
+
//#region src/jsx.ts
|
|
1512
|
+
var JsxEngine = class {
|
|
1513
|
+
context;
|
|
1514
|
+
nodes = [];
|
|
1515
|
+
names = [];
|
|
1516
|
+
recipeMatcher = {
|
|
1517
|
+
string: /* @__PURE__ */ new Set(),
|
|
1518
|
+
regex: []
|
|
1519
|
+
};
|
|
1520
|
+
recipePropertiesByJsxName = /* @__PURE__ */ new Map();
|
|
1521
|
+
patternMatcher = {
|
|
1522
|
+
string: /* @__PURE__ */ new Set(),
|
|
1523
|
+
regex: []
|
|
1524
|
+
};
|
|
1525
|
+
patternPropertiesByJsxName = /* @__PURE__ */ new Map();
|
|
1526
|
+
constructor(context) {
|
|
1527
|
+
this.context = context;
|
|
1528
|
+
this.nodes = [...context.patterns.details, ...context.recipes.details];
|
|
1529
|
+
this.names = [this.factoryName, ...this.nodes.map((node) => node.jsxName)];
|
|
1530
|
+
this.assignRecipeMatcher();
|
|
1531
|
+
this.assignPatternMatcher();
|
|
1532
|
+
}
|
|
1533
|
+
assignRecipeMatcher() {
|
|
1534
|
+
if (!this.isEnabled) return;
|
|
1535
|
+
for (const recipe of this.context.recipes.details) {
|
|
1536
|
+
this.recipePropertiesByJsxName.set(recipe.jsxName, new Set(recipe.props ?? []));
|
|
1537
|
+
recipe.jsx.forEach((jsx) => {
|
|
1538
|
+
if (typeof jsx === "string") this.recipeMatcher.string.add(jsx);
|
|
1539
|
+
else this.recipeMatcher.regex.push(jsx);
|
|
1540
|
+
});
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
assignPatternMatcher() {
|
|
1544
|
+
if (!this.isEnabled) return;
|
|
1545
|
+
for (const pattern of this.context.patterns.details) {
|
|
1546
|
+
this.patternPropertiesByJsxName.set(pattern.jsxName, new Set(pattern.props ?? []));
|
|
1547
|
+
pattern.jsx.forEach((jsx) => {
|
|
1548
|
+
if (typeof jsx === "string") this.patternMatcher.string.add(jsx);
|
|
1549
|
+
else this.patternMatcher.regex.push(jsx);
|
|
1550
|
+
});
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
get jsxFactory() {
|
|
1554
|
+
return this.context.config.jsxFactory ?? "styled";
|
|
1555
|
+
}
|
|
1556
|
+
get styleProps() {
|
|
1557
|
+
return this.context.config.jsxStyleProps ?? "all";
|
|
1558
|
+
}
|
|
1559
|
+
get framework() {
|
|
1560
|
+
return this.context.config.jsxFramework;
|
|
1561
|
+
}
|
|
1562
|
+
get isEnabled() {
|
|
1563
|
+
return this.framework != null;
|
|
1564
|
+
}
|
|
1565
|
+
get factoryName() {
|
|
1566
|
+
return this.jsxFactory;
|
|
1567
|
+
}
|
|
1568
|
+
get upperName() {
|
|
1569
|
+
return (0, _bamboocss_shared.capitalize)(this.jsxFactory);
|
|
1570
|
+
}
|
|
1571
|
+
get typeName() {
|
|
1572
|
+
return `HTML${(0, _bamboocss_shared.capitalize)(this.jsxFactory)}Props`;
|
|
1573
|
+
}
|
|
1574
|
+
get variantName() {
|
|
1575
|
+
return `${(0, _bamboocss_shared.capitalize)(this.jsxFactory)}VariantProps`;
|
|
1576
|
+
}
|
|
1577
|
+
get componentName() {
|
|
1578
|
+
return `${(0, _bamboocss_shared.capitalize)(this.jsxFactory)}Component`;
|
|
1579
|
+
}
|
|
1580
|
+
isJsxFactory = (name) => {
|
|
1581
|
+
if (name === this.factoryName) return true;
|
|
1582
|
+
const [_namespace, identifier] = name.split(".");
|
|
1583
|
+
return identifier === this.factoryName;
|
|
1584
|
+
};
|
|
1585
|
+
isJsxTagRecipe = (0, _bamboocss_shared.memo)((tagName) => {
|
|
1586
|
+
return this.recipeMatcher.string.has(tagName) || this.recipeMatcher.regex.some((regex) => regex.test(tagName));
|
|
1587
|
+
});
|
|
1588
|
+
isJsxTagPattern = (0, _bamboocss_shared.memo)((tagName) => {
|
|
1589
|
+
return this.patternMatcher.string.has(tagName) || this.patternMatcher.regex.some((regex) => regex.test(tagName));
|
|
1590
|
+
});
|
|
1591
|
+
isRecipeOrPatternProp = (0, _bamboocss_shared.memo)((tagName, propName) => {
|
|
1592
|
+
if (this.isJsxTagRecipe(tagName)) return this.context.recipes.filter(tagName).some((recipe) => this.recipePropertiesByJsxName.get(recipe.jsxName)?.has(propName));
|
|
1593
|
+
if (this.isJsxTagPattern(tagName)) return this.context.patterns.filter(tagName).some((pattern) => this.patternPropertiesByJsxName.get(pattern.jsxName)?.has(propName));
|
|
1594
|
+
return false;
|
|
1595
|
+
});
|
|
1596
|
+
};
|
|
1597
|
+
//#endregion
|
|
1598
|
+
//#region src/layers.ts
|
|
1599
|
+
var Layers = class {
|
|
1600
|
+
names;
|
|
1601
|
+
root;
|
|
1602
|
+
reset;
|
|
1603
|
+
base;
|
|
1604
|
+
tokens;
|
|
1605
|
+
recipes;
|
|
1606
|
+
recipes_base;
|
|
1607
|
+
recipes_slots;
|
|
1608
|
+
recipes_slots_base;
|
|
1609
|
+
utilities;
|
|
1610
|
+
compositions;
|
|
1611
|
+
utilityRuleMap = /* @__PURE__ */ new Map();
|
|
1612
|
+
constructor(names) {
|
|
1613
|
+
this.names = names;
|
|
1614
|
+
this.root = postcss.default.root();
|
|
1615
|
+
this.reset = postcss.default.atRule({
|
|
1616
|
+
name: "layer",
|
|
1617
|
+
params: names.reset,
|
|
1618
|
+
nodes: []
|
|
1619
|
+
});
|
|
1620
|
+
this.base = postcss.default.atRule({
|
|
1621
|
+
name: "layer",
|
|
1622
|
+
params: names.base,
|
|
1623
|
+
nodes: []
|
|
1624
|
+
});
|
|
1625
|
+
this.tokens = postcss.default.atRule({
|
|
1626
|
+
name: "layer",
|
|
1627
|
+
params: names.tokens,
|
|
1628
|
+
nodes: []
|
|
1629
|
+
});
|
|
1630
|
+
this.recipes = postcss.default.atRule({
|
|
1631
|
+
name: "layer",
|
|
1632
|
+
params: names.recipes,
|
|
1633
|
+
nodes: []
|
|
1634
|
+
});
|
|
1635
|
+
this.recipes_base = postcss.default.atRule({
|
|
1636
|
+
name: "layer",
|
|
1637
|
+
params: "_base",
|
|
1638
|
+
nodes: []
|
|
1639
|
+
});
|
|
1640
|
+
this.recipes_slots = postcss.default.atRule({
|
|
1641
|
+
name: "layer",
|
|
1642
|
+
params: names.recipes + ".slots",
|
|
1643
|
+
nodes: []
|
|
1644
|
+
});
|
|
1645
|
+
this.recipes_slots_base = postcss.default.atRule({
|
|
1646
|
+
name: "layer",
|
|
1647
|
+
params: "_base",
|
|
1648
|
+
nodes: []
|
|
1649
|
+
});
|
|
1650
|
+
this.utilities = postcss.default.atRule({
|
|
1651
|
+
name: "layer",
|
|
1652
|
+
params: names.utilities,
|
|
1653
|
+
nodes: []
|
|
1654
|
+
});
|
|
1655
|
+
this.compositions = postcss.default.atRule({
|
|
1656
|
+
name: "layer",
|
|
1657
|
+
params: "compositions",
|
|
1658
|
+
nodes: []
|
|
1659
|
+
});
|
|
1660
|
+
}
|
|
1661
|
+
getLayerRoot(layer) {
|
|
1662
|
+
const { reset, base, tokens, recipes, recipes_base, recipes_slots, recipes_slots_base, utilities, compositions } = this;
|
|
1663
|
+
switch (layer) {
|
|
1664
|
+
case "base": return base;
|
|
1665
|
+
case "reset": return reset;
|
|
1666
|
+
case "tokens": return tokens;
|
|
1667
|
+
case "recipes": {
|
|
1668
|
+
const recipeRoot = postcss.default.root();
|
|
1669
|
+
if (recipes_base.nodes?.length) recipes.prepend(recipes_base);
|
|
1670
|
+
if (recipes_slots_base.nodes?.length) recipes_slots.prepend(recipes_slots_base);
|
|
1671
|
+
if (recipes.nodes?.length) recipeRoot.append(recipes);
|
|
1672
|
+
if (recipes_slots.nodes?.length) recipeRoot.append(recipes_slots);
|
|
1673
|
+
return recipeRoot;
|
|
1674
|
+
}
|
|
1675
|
+
case "utilities":
|
|
1676
|
+
if (compositions.nodes?.length) utilities.prepend(compositions);
|
|
1677
|
+
this.utilityRuleMap.forEach((rules) => {
|
|
1678
|
+
if (rules.nodes?.length) utilities.append(rules);
|
|
1679
|
+
});
|
|
1680
|
+
return utilities;
|
|
1681
|
+
default: throw new _bamboocss_shared.BambooError("INVALID_LAYER", `Unknown layer: ${layer}`);
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
insert() {
|
|
1685
|
+
const { root } = this;
|
|
1686
|
+
const reset = this.getLayerRoot("reset");
|
|
1687
|
+
if (reset.nodes?.length) root.append(reset);
|
|
1688
|
+
const base = this.getLayerRoot("base");
|
|
1689
|
+
if (base.nodes?.length) root.append(base);
|
|
1690
|
+
const tokens = this.getLayerRoot("tokens");
|
|
1691
|
+
if (tokens.nodes?.length) root.append(tokens);
|
|
1692
|
+
const recipes = this.getLayerRoot("recipes");
|
|
1693
|
+
if (recipes.nodes?.length) root.append(recipes);
|
|
1694
|
+
const utilities = this.getLayerRoot("utilities");
|
|
1695
|
+
if (utilities.nodes?.length) root.append(utilities);
|
|
1696
|
+
return root;
|
|
1697
|
+
}
|
|
1698
|
+
get layerNames() {
|
|
1699
|
+
return Object.values(this.names);
|
|
1700
|
+
}
|
|
1701
|
+
get params() {
|
|
1702
|
+
return `@layer ${this.layerNames.join(", ")};`;
|
|
1703
|
+
}
|
|
1704
|
+
};
|
|
1705
|
+
//#endregion
|
|
1706
|
+
//#region src/path.ts
|
|
1707
|
+
var PathEngine = class {
|
|
1708
|
+
context;
|
|
1709
|
+
constructor(context) {
|
|
1710
|
+
this.context = context;
|
|
1711
|
+
}
|
|
1712
|
+
get cwd() {
|
|
1713
|
+
return this.context.config.cwd;
|
|
1714
|
+
}
|
|
1715
|
+
get outdir() {
|
|
1716
|
+
return this.context.config.outdir;
|
|
1717
|
+
}
|
|
1718
|
+
getFilePath(file) {
|
|
1719
|
+
return [
|
|
1720
|
+
this.cwd,
|
|
1721
|
+
this.outdir,
|
|
1722
|
+
file
|
|
1723
|
+
].filter(Boolean);
|
|
1724
|
+
}
|
|
1725
|
+
get root() {
|
|
1726
|
+
return this.getFilePath();
|
|
1727
|
+
}
|
|
1728
|
+
get css() {
|
|
1729
|
+
return this.getFilePath("css");
|
|
1730
|
+
}
|
|
1731
|
+
get token() {
|
|
1732
|
+
return this.getFilePath("tokens");
|
|
1733
|
+
}
|
|
1734
|
+
get types() {
|
|
1735
|
+
return this.getFilePath("types");
|
|
1736
|
+
}
|
|
1737
|
+
get recipe() {
|
|
1738
|
+
return this.getFilePath("recipes");
|
|
1739
|
+
}
|
|
1740
|
+
get pattern() {
|
|
1741
|
+
return this.getFilePath("patterns");
|
|
1742
|
+
}
|
|
1743
|
+
get outCss() {
|
|
1744
|
+
return this.getFilePath("styles.css");
|
|
1745
|
+
}
|
|
1746
|
+
get jsx() {
|
|
1747
|
+
return this.getFilePath("jsx");
|
|
1748
|
+
}
|
|
1749
|
+
get themes() {
|
|
1750
|
+
return this.getFilePath("themes");
|
|
1751
|
+
}
|
|
1752
|
+
get specs() {
|
|
1753
|
+
return this.getFilePath("specs");
|
|
1754
|
+
}
|
|
1755
|
+
};
|
|
1756
|
+
//#endregion
|
|
1757
|
+
//#region src/patterns.ts
|
|
1758
|
+
var Patterns = class {
|
|
1759
|
+
options;
|
|
1760
|
+
patterns;
|
|
1761
|
+
details;
|
|
1762
|
+
keys;
|
|
1763
|
+
utility;
|
|
1764
|
+
tokens;
|
|
1765
|
+
deprecated = /* @__PURE__ */ new Set();
|
|
1766
|
+
constructor(options) {
|
|
1767
|
+
this.options = options;
|
|
1768
|
+
this.patterns = options.config.patterns ?? {};
|
|
1769
|
+
this.details = Object.entries(this.patterns).map(([name, pattern]) => this.createDetail(name, pattern));
|
|
1770
|
+
this.keys = Object.keys(this.patterns);
|
|
1771
|
+
this.utility = options.utility;
|
|
1772
|
+
this.tokens = options.tokens;
|
|
1773
|
+
}
|
|
1774
|
+
createDetail(name, pattern) {
|
|
1775
|
+
const names = this.getNames(name);
|
|
1776
|
+
const jsx = (pattern.jsx ?? []).concat([names.jsxName]);
|
|
1777
|
+
if (pattern.deprecated) this.deprecated.add(name);
|
|
1778
|
+
return {
|
|
1779
|
+
...names,
|
|
1780
|
+
props: Object.keys(pattern?.properties ?? {}),
|
|
1781
|
+
blocklistType: pattern?.blocklist ? `| '${pattern.blocklist.join("' | '")}'` : "",
|
|
1782
|
+
config: pattern,
|
|
1783
|
+
type: "pattern",
|
|
1784
|
+
match: (0, _bamboocss_shared.createRegex)(jsx),
|
|
1785
|
+
jsx
|
|
1786
|
+
};
|
|
1787
|
+
}
|
|
1788
|
+
getConfig(name) {
|
|
1789
|
+
return this.patterns[name];
|
|
1790
|
+
}
|
|
1791
|
+
transform(name, styles) {
|
|
1792
|
+
const pattern = this.patterns[name];
|
|
1793
|
+
const _styles = (0, _bamboocss_shared.getPatternStyles)(pattern, styles);
|
|
1794
|
+
return pattern?.transform?.(_styles, this.options.helpers) ?? {};
|
|
1795
|
+
}
|
|
1796
|
+
getNames(name) {
|
|
1797
|
+
const upperName = (0, _bamboocss_shared.capitalize)(name);
|
|
1798
|
+
return {
|
|
1799
|
+
upperName,
|
|
1800
|
+
baseName: name,
|
|
1801
|
+
dashName: (0, _bamboocss_shared.dashCase)(name),
|
|
1802
|
+
styleFnName: `get${upperName}Style`,
|
|
1803
|
+
jsxName: this.patterns[name]?.jsxName ?? upperName
|
|
1804
|
+
};
|
|
1805
|
+
}
|
|
1806
|
+
find = (0, _bamboocss_shared.memo)((jsxName) => {
|
|
1807
|
+
return this.details.find((node) => node.match.test(jsxName))?.baseName ?? (0, _bamboocss_shared.uncapitalize)(jsxName);
|
|
1808
|
+
});
|
|
1809
|
+
filter = (0, _bamboocss_shared.memo)((jsxName) => {
|
|
1810
|
+
return this.details.filter((node) => node.match.test(jsxName));
|
|
1811
|
+
});
|
|
1812
|
+
isEmpty() {
|
|
1813
|
+
return this.keys.length === 0;
|
|
1814
|
+
}
|
|
1815
|
+
isDeprecated(name) {
|
|
1816
|
+
return this.deprecated.has(name);
|
|
1817
|
+
}
|
|
1818
|
+
saveOne(name, pattern) {
|
|
1819
|
+
this.patterns[name] = pattern;
|
|
1820
|
+
const detailIndex = this.details.findIndex((detail) => detail.baseName === name);
|
|
1821
|
+
const updated = this.createDetail(name, pattern);
|
|
1822
|
+
if (detailIndex > -1) this.details[detailIndex] = updated;
|
|
1823
|
+
else this.details.push(updated);
|
|
1824
|
+
}
|
|
1825
|
+
remove(name) {
|
|
1826
|
+
delete this.patterns[name];
|
|
1827
|
+
const detailIndex = this.details.findIndex((detail) => detail.baseName === name);
|
|
1828
|
+
if (detailIndex > -1) this.details.splice(detailIndex, 1);
|
|
1829
|
+
}
|
|
1830
|
+
filterDetails(filters) {
|
|
1831
|
+
const patternDiffs = filters?.affecteds?.patterns;
|
|
1832
|
+
return patternDiffs ? this.details.filter((pattern) => patternDiffs.includes(pattern.dashName)) : this.details;
|
|
1833
|
+
}
|
|
1834
|
+
getPropertyValues = (patternName, property) => {
|
|
1835
|
+
const patternConfig = this.getConfig(patternName);
|
|
1836
|
+
if (!patternConfig) return [];
|
|
1837
|
+
const propType = patternConfig.properties?.[property];
|
|
1838
|
+
if (!propType) return;
|
|
1839
|
+
if (propType.type === "enum") return propType.value;
|
|
1840
|
+
if (propType.type === "boolean") return ["true", "false"];
|
|
1841
|
+
if (propType.type === "property") return this.utility.getPropertyKeys(propType.value || property);
|
|
1842
|
+
if (propType.type === "token") {
|
|
1843
|
+
const values = this.tokens.view.getCategoryValues(propType.value);
|
|
1844
|
+
return Object.keys(values ?? {});
|
|
1845
|
+
}
|
|
1846
|
+
};
|
|
1847
|
+
getPropertyType = (prop) => {
|
|
1848
|
+
switch (prop.type) {
|
|
1849
|
+
case "enum": return `ConditionalValue<${(0, _bamboocss_shared.unionType)(prop.value)}>`;
|
|
1850
|
+
case "token": {
|
|
1851
|
+
const tokenType = `Tokens["${prop.value}"]`;
|
|
1852
|
+
if (prop.property) return `ConditionalValue<${tokenType} | Properties["${prop.property}"]>`;
|
|
1853
|
+
return `ConditionalValue<${tokenType}>`;
|
|
1854
|
+
}
|
|
1855
|
+
case "property": return `SystemProperties["${prop.value}"]`;
|
|
1856
|
+
case "string":
|
|
1857
|
+
case "number":
|
|
1858
|
+
case "boolean": return `ConditionalValue<${prop.type}>`;
|
|
1859
|
+
default: return `ConditionalValue<${prop.type || "unknown"}>`;
|
|
1860
|
+
}
|
|
1861
|
+
};
|
|
1862
|
+
static isValidNode = (node) => {
|
|
1863
|
+
return (0, _bamboocss_shared.isObject)(node) && "type" in node && node.type === "recipe";
|
|
1864
|
+
};
|
|
1865
|
+
};
|
|
1866
|
+
//#endregion
|
|
1867
|
+
//#region src/serialize.ts
|
|
1868
|
+
/**
|
|
1869
|
+
* Transform the style object (with conditions, shorthands, tokens) into a valid CSS (in JS) object
|
|
1870
|
+
*/
|
|
1871
|
+
function transformStyles(context, styleObj, key) {
|
|
1872
|
+
const encoder = context.encoder.clone();
|
|
1873
|
+
const decoder = context.decoder.clone();
|
|
1874
|
+
const hashSet = /* @__PURE__ */ new Set();
|
|
1875
|
+
encoder.hashStyleObject(hashSet, styleObj);
|
|
1876
|
+
return decoder.getGroup(hashSet, key).result;
|
|
1877
|
+
}
|
|
1878
|
+
/**
|
|
1879
|
+
* Serialize the style object (with conditions, shorthands, tokens) into a valid CSS string
|
|
1880
|
+
*/
|
|
1881
|
+
function serializeStyles(context, groupedObject) {
|
|
1882
|
+
const result = {};
|
|
1883
|
+
for (const [scope, styles] of Object.entries(groupedObject)) {
|
|
1884
|
+
result[scope] ||= {};
|
|
1885
|
+
const styleObject = (0, _bamboocss_shared.walkObject)(styles, (value) => value, { getKey: (prop, value) => {
|
|
1886
|
+
if ((0, _bamboocss_shared.isObject)(value) && !context.conditions.isCondition(prop) && !context.isValidProperty(prop)) return parseSelectors(prop).map((s) => "& " + s).join(", ");
|
|
1887
|
+
return prop;
|
|
1888
|
+
} });
|
|
1889
|
+
(0, lodash_merge.default)(result[scope], transformStyles(context, styleObject, scope));
|
|
1890
|
+
}
|
|
1891
|
+
return result;
|
|
1892
|
+
}
|
|
1893
|
+
//#endregion
|
|
1894
|
+
//#region src/recipes.ts
|
|
1895
|
+
const sharedState = {
|
|
1896
|
+
/**
|
|
1897
|
+
* The map of recipe names to their resolved class names
|
|
1898
|
+
*/
|
|
1899
|
+
classNames: /* @__PURE__ */ new Map(),
|
|
1900
|
+
/**
|
|
1901
|
+
* The map of the property to their resolved styles
|
|
1902
|
+
*/
|
|
1903
|
+
styles: /* @__PURE__ */ new Map(),
|
|
1904
|
+
/**
|
|
1905
|
+
* The map of the recipes with their resolved styles
|
|
1906
|
+
*/
|
|
1907
|
+
nodes: /* @__PURE__ */ new Map(),
|
|
1908
|
+
/**
|
|
1909
|
+
* The map of recipe key to slot key + slot recipe
|
|
1910
|
+
*/
|
|
1911
|
+
slots: /* @__PURE__ */ new Map()
|
|
1912
|
+
};
|
|
1913
|
+
var Recipes = class Recipes {
|
|
1914
|
+
recipes;
|
|
1915
|
+
slotSeparator = "__";
|
|
1916
|
+
keys = [];
|
|
1917
|
+
deprecated = /* @__PURE__ */ new Set();
|
|
1918
|
+
context;
|
|
1919
|
+
get config() {
|
|
1920
|
+
return this.recipes;
|
|
1921
|
+
}
|
|
1922
|
+
constructor(recipes = {}) {
|
|
1923
|
+
this.recipes = recipes;
|
|
1924
|
+
this.prune();
|
|
1925
|
+
}
|
|
1926
|
+
getPropKey = (recipe, variant, value) => {
|
|
1927
|
+
return `${recipe} (${variant} = ${value})`;
|
|
1928
|
+
};
|
|
1929
|
+
get separator() {
|
|
1930
|
+
return this.context.utility.separator ?? "_";
|
|
1931
|
+
}
|
|
1932
|
+
getClassName = (className, variant, value) => {
|
|
1933
|
+
return `${className}--${variant}${this.separator}${value}`;
|
|
1934
|
+
};
|
|
1935
|
+
prune = () => {
|
|
1936
|
+
const recipeNames = Object.keys(this.recipes);
|
|
1937
|
+
Array.from(sharedState.nodes.keys()).filter((name) => !recipeNames.includes(name)).forEach((name) => {
|
|
1938
|
+
this.remove(name);
|
|
1939
|
+
});
|
|
1940
|
+
};
|
|
1941
|
+
save = (context) => {
|
|
1942
|
+
this.context = context;
|
|
1943
|
+
for (const [name, recipe] of Object.entries(this.recipes)) this.saveOne(name, recipe);
|
|
1944
|
+
this.keys = Object.keys(this.recipes);
|
|
1945
|
+
};
|
|
1946
|
+
saveOne = (name, recipe) => {
|
|
1947
|
+
if (Recipes.isSlotRecipeConfig(recipe)) {
|
|
1948
|
+
const slots = (0, _bamboocss_shared.getSlotRecipes)(recipe);
|
|
1949
|
+
const slotsMap = /* @__PURE__ */ new Map();
|
|
1950
|
+
Object.entries(slots).forEach(([slot, slotRecipe]) => {
|
|
1951
|
+
const slotName = this.getSlotKey(name, slot);
|
|
1952
|
+
this.normalize(slotName, slotRecipe);
|
|
1953
|
+
slotsMap.set(slotName, slotRecipe);
|
|
1954
|
+
});
|
|
1955
|
+
this.assignRecipe(name, recipe);
|
|
1956
|
+
sharedState.slots.set(name, slotsMap);
|
|
1957
|
+
} else this.assignRecipe(name, this.normalize(name, recipe));
|
|
1958
|
+
};
|
|
1959
|
+
remove(name) {
|
|
1960
|
+
sharedState.nodes.delete(name);
|
|
1961
|
+
sharedState.classNames.delete(name);
|
|
1962
|
+
sharedState.styles.delete(name);
|
|
1963
|
+
}
|
|
1964
|
+
inferJsxSlots = (name, recipe) => {
|
|
1965
|
+
const capitalized = (0, _bamboocss_shared.capitalize)(name);
|
|
1966
|
+
const jsx = Array.from(recipe.jsx ?? [capitalized]);
|
|
1967
|
+
const ROOT_SLOT = "root";
|
|
1968
|
+
if (Recipes.isSlotRecipeConfig(recipe)) {
|
|
1969
|
+
const jsxRootName = (0, _bamboocss_shared.capitalize)(ROOT_SLOT);
|
|
1970
|
+
const rootNames = [`${capitalized}.${jsxRootName}`, `${capitalized}${jsxRootName}`];
|
|
1971
|
+
jsx.push(...rootNames);
|
|
1972
|
+
}
|
|
1973
|
+
return jsx;
|
|
1974
|
+
};
|
|
1975
|
+
assignRecipe = (name, recipe) => {
|
|
1976
|
+
if (recipe.deprecated) this.deprecated.add(name);
|
|
1977
|
+
const variantKeys = Object.keys(recipe.variants ?? {});
|
|
1978
|
+
const jsx = this.inferJsxSlots(name, recipe);
|
|
1979
|
+
sharedState.nodes.set(name, {
|
|
1980
|
+
...this.getNames(name),
|
|
1981
|
+
className: recipe.className ?? name,
|
|
1982
|
+
jsx,
|
|
1983
|
+
type: "recipe",
|
|
1984
|
+
variantKeys,
|
|
1985
|
+
variantKeyMap: Object.fromEntries(Object.entries(recipe.variants ?? {}).map(([key, value]) => {
|
|
1986
|
+
return [key, Object.keys(value)];
|
|
1987
|
+
})),
|
|
1988
|
+
match: (0, _bamboocss_shared.createRegex)(jsx),
|
|
1989
|
+
config: recipe,
|
|
1990
|
+
splitProps: (props) => {
|
|
1991
|
+
return (0, _bamboocss_shared.splitProps)(props, variantKeys);
|
|
1992
|
+
},
|
|
1993
|
+
props: variantKeys
|
|
1994
|
+
});
|
|
1995
|
+
};
|
|
1996
|
+
getSlotKey = (name, slot) => {
|
|
1997
|
+
return `${name}${this.slotSeparator}${slot}`;
|
|
1998
|
+
};
|
|
1999
|
+
isEmpty = () => {
|
|
2000
|
+
return sharedState.nodes.size === 0;
|
|
2001
|
+
};
|
|
2002
|
+
isDeprecated = (name) => {
|
|
2003
|
+
return this.deprecated.has(name);
|
|
2004
|
+
};
|
|
2005
|
+
getNames = (0, _bamboocss_shared.memo)((name) => {
|
|
2006
|
+
return {
|
|
2007
|
+
baseName: name,
|
|
2008
|
+
upperName: (0, _bamboocss_shared.capitalize)(name),
|
|
2009
|
+
dashName: (0, _bamboocss_shared.dashCase)(name),
|
|
2010
|
+
jsxName: (0, _bamboocss_shared.capitalize)(name)
|
|
2011
|
+
};
|
|
2012
|
+
});
|
|
2013
|
+
getRecipe = (0, _bamboocss_shared.memo)((name) => {
|
|
2014
|
+
return sharedState.nodes.get(name);
|
|
2015
|
+
});
|
|
2016
|
+
getConfig = (0, _bamboocss_shared.memo)((name) => {
|
|
2017
|
+
return this.recipes[name];
|
|
2018
|
+
});
|
|
2019
|
+
getConfigOrThrow = (0, _bamboocss_shared.memo)((name) => {
|
|
2020
|
+
const config = this.getConfig(name);
|
|
2021
|
+
if (!config) throw new _bamboocss_shared.BambooError("UNKNOWN_RECIPE", `Recipe "${name}" not found`);
|
|
2022
|
+
return config;
|
|
2023
|
+
});
|
|
2024
|
+
find = (0, _bamboocss_shared.memo)((jsxName) => {
|
|
2025
|
+
return this.details.find((node) => node.match.test(jsxName));
|
|
2026
|
+
});
|
|
2027
|
+
filter = (0, _bamboocss_shared.memo)((jsxName) => {
|
|
2028
|
+
return this.details.filter((node) => node.match.test(jsxName));
|
|
2029
|
+
});
|
|
2030
|
+
get details() {
|
|
2031
|
+
return Array.from(sharedState.nodes.values());
|
|
2032
|
+
}
|
|
2033
|
+
splitProps = (recipeName, props) => {
|
|
2034
|
+
const recipe = this.details.find((node) => node.baseName === recipeName);
|
|
2035
|
+
if (!recipe) return [{}, props];
|
|
2036
|
+
return recipe.splitProps(props);
|
|
2037
|
+
};
|
|
2038
|
+
isSlotRecipe = (name) => {
|
|
2039
|
+
return sharedState.slots.has(name);
|
|
2040
|
+
};
|
|
2041
|
+
static isSlotRecipeConfig = (config) => {
|
|
2042
|
+
return "slots" in config && Array.isArray(config.slots) && config.slots.length > 0;
|
|
2043
|
+
};
|
|
2044
|
+
normalize = (name, config) => {
|
|
2045
|
+
const { jsx = [(0, _bamboocss_shared.capitalize)(name)], base = {}, variants = {}, defaultVariants = {}, description = "", compoundVariants = [], staticCss = [] } = config;
|
|
2046
|
+
const className = config.className ?? name;
|
|
2047
|
+
const recipe = {
|
|
2048
|
+
...config,
|
|
2049
|
+
deprecated: config.deprecated == null ? false : config.deprecated,
|
|
2050
|
+
jsx,
|
|
2051
|
+
className,
|
|
2052
|
+
description,
|
|
2053
|
+
base: {},
|
|
2054
|
+
variants: {},
|
|
2055
|
+
defaultVariants,
|
|
2056
|
+
compoundVariants,
|
|
2057
|
+
staticCss
|
|
2058
|
+
};
|
|
2059
|
+
recipe.base = transformStyles(this.context, base, name);
|
|
2060
|
+
sharedState.styles.set(name, recipe.base);
|
|
2061
|
+
sharedState.classNames.set(name, recipe.className);
|
|
2062
|
+
for (const [key, variant] of Object.entries(variants)) for (const [variantKey, styles] of Object.entries(variant)) {
|
|
2063
|
+
const propKey = this.getPropKey(name, key, variantKey);
|
|
2064
|
+
const className = this.getClassName(recipe.className, key, variantKey);
|
|
2065
|
+
const styleObject = transformStyles(this.context, styles, className);
|
|
2066
|
+
sharedState.styles.set(propKey, styleObject);
|
|
2067
|
+
sharedState.classNames.set(propKey, className);
|
|
2068
|
+
(0, lodash_merge.default)(recipe.variants, { [key]: { [variantKey]: styleObject } });
|
|
2069
|
+
}
|
|
2070
|
+
return recipe;
|
|
2071
|
+
};
|
|
2072
|
+
getTransform = (name, slot) => {
|
|
2073
|
+
return (variant, value) => {
|
|
2074
|
+
if (value === "__ignore__") return {
|
|
2075
|
+
layer: slot ? "recipes_slots_base" : "recipes_base",
|
|
2076
|
+
className: sharedState.classNames.get(name),
|
|
2077
|
+
styles: sharedState.styles.get(name) ?? {}
|
|
2078
|
+
};
|
|
2079
|
+
const propKey = this.getPropKey(name, variant, value);
|
|
2080
|
+
return {
|
|
2081
|
+
className: sharedState.classNames.get(propKey),
|
|
2082
|
+
styles: sharedState.styles.get(propKey) ?? {}
|
|
2083
|
+
};
|
|
2084
|
+
};
|
|
2085
|
+
};
|
|
2086
|
+
filterDetails = (filters) => {
|
|
2087
|
+
const recipeDiffs = filters?.affecteds?.recipes;
|
|
2088
|
+
return recipeDiffs ? this.details.filter((recipe) => recipeDiffs.includes(recipe.dashName)) : this.details;
|
|
2089
|
+
};
|
|
2090
|
+
static inferSlots = (recipe) => {
|
|
2091
|
+
const slots = /* @__PURE__ */ new Set();
|
|
2092
|
+
Object.keys(recipe.base ?? {}).forEach((name) => {
|
|
2093
|
+
slots.add(name);
|
|
2094
|
+
});
|
|
2095
|
+
Object.values(recipe.variants ?? {}).forEach((variants) => {
|
|
2096
|
+
Object.keys(variants).forEach((name) => {
|
|
2097
|
+
slots.add(name);
|
|
2098
|
+
});
|
|
2099
|
+
});
|
|
2100
|
+
recipe.compoundVariants?.forEach((compoundVariant) => {
|
|
2101
|
+
if (!compoundVariant) return;
|
|
2102
|
+
Object.keys(compoundVariant.css ?? {}).forEach((name) => {
|
|
2103
|
+
slots.add(name);
|
|
2104
|
+
});
|
|
2105
|
+
});
|
|
2106
|
+
return Array.from(slots);
|
|
2107
|
+
};
|
|
2108
|
+
static isValidNode = (node) => {
|
|
2109
|
+
return (0, _bamboocss_shared.isObject)(node) && "type" in node && node.type === "recipe";
|
|
2110
|
+
};
|
|
2111
|
+
};
|
|
2112
|
+
//#endregion
|
|
2113
|
+
//#region package.json
|
|
2114
|
+
var version = "1.11.3";
|
|
2115
|
+
//#endregion
|
|
2116
|
+
//#region src/style-encoder.ts
|
|
2117
|
+
const urlRegex = /^https?:\/\//;
|
|
2118
|
+
var StyleEncoder = class StyleEncoder {
|
|
2119
|
+
context;
|
|
2120
|
+
static separator = "]___[";
|
|
2121
|
+
static conditionSeparator = "<___>";
|
|
2122
|
+
atomic = /* @__PURE__ */ new Set();
|
|
2123
|
+
compound_variants = /* @__PURE__ */ new Set();
|
|
2124
|
+
recipes = /* @__PURE__ */ new Map();
|
|
2125
|
+
recipes_base = /* @__PURE__ */ new Map();
|
|
2126
|
+
grouped = /* @__PURE__ */ new Map();
|
|
2127
|
+
constructor(context) {
|
|
2128
|
+
this.context = context;
|
|
2129
|
+
}
|
|
2130
|
+
filterStyleProps = (props) => {
|
|
2131
|
+
if (this.context.isTemplateLiteralSyntax) return props;
|
|
2132
|
+
return filterProps(this.context.isValidProperty, props);
|
|
2133
|
+
};
|
|
2134
|
+
clone = () => {
|
|
2135
|
+
return new StyleEncoder(this.context);
|
|
2136
|
+
};
|
|
2137
|
+
isEmpty = () => {
|
|
2138
|
+
return !this.atomic.size && !this.recipes.size && !this.compound_variants.size && !this.recipes_base.size && !this.grouped.size;
|
|
2139
|
+
};
|
|
2140
|
+
get results() {
|
|
2141
|
+
return {
|
|
2142
|
+
atomic: this.atomic,
|
|
2143
|
+
recipes: this.recipes,
|
|
2144
|
+
recipes_base: this.recipes_base,
|
|
2145
|
+
grouped: this.grouped
|
|
2146
|
+
};
|
|
2147
|
+
}
|
|
2148
|
+
/**
|
|
2149
|
+
* Hashes a style object and adds the resulting hashes to a set.
|
|
2150
|
+
* @param set - The set to add the resulting hashes to.
|
|
2151
|
+
* @param obj - The style object to hash.
|
|
2152
|
+
* @param baseEntry - An optional base style entry to use when hashing the style object.
|
|
2153
|
+
*/
|
|
2154
|
+
hashStyleObject = (set, obj, baseEntry) => {
|
|
2155
|
+
const isCondition = this.context.conditions.isCondition;
|
|
2156
|
+
const traverseOptions = { separator: StyleEncoder.conditionSeparator };
|
|
2157
|
+
let prop = "";
|
|
2158
|
+
let prevProp = "";
|
|
2159
|
+
const isRecipe = !!baseEntry?.variants;
|
|
2160
|
+
(0, _bamboocss_shared.traverse)((0, _bamboocss_shared.normalizeStyleObject)(obj, this.context, !isRecipe), ({ key, value: rawValue, path }) => {
|
|
2161
|
+
if (rawValue === void 0) return;
|
|
2162
|
+
if (urlRegex.test(rawValue)) return;
|
|
2163
|
+
const value = Array.isArray(rawValue) ? (0, _bamboocss_shared.toResponsiveObject)(rawValue, this.context.conditions.breakpoints.keys) : rawValue;
|
|
2164
|
+
prop = key;
|
|
2165
|
+
if (isCondition(key)) {
|
|
2166
|
+
if ((0, _bamboocss_shared.isObjectOrArray)(value)) return;
|
|
2167
|
+
prop = prevProp;
|
|
2168
|
+
} else if ((0, _bamboocss_shared.isObjectOrArray)(value)) {
|
|
2169
|
+
prevProp = prop;
|
|
2170
|
+
return;
|
|
2171
|
+
}
|
|
2172
|
+
const resolvedCondition = getResolvedCondition(path, isCondition);
|
|
2173
|
+
const hashed = hashStyleEntry(Object.assign(baseEntry ?? {}, {
|
|
2174
|
+
prop,
|
|
2175
|
+
value,
|
|
2176
|
+
cond: resolvedCondition
|
|
2177
|
+
}));
|
|
2178
|
+
set.add(hashed);
|
|
2179
|
+
prevProp = prop;
|
|
2180
|
+
}, traverseOptions);
|
|
2181
|
+
};
|
|
2182
|
+
processAtomic = (styles) => {
|
|
2183
|
+
this.hashStyleObject(this.atomic, styles);
|
|
2184
|
+
};
|
|
2185
|
+
processGrouped = (styles) => {
|
|
2186
|
+
const groupSet = /* @__PURE__ */ new Set();
|
|
2187
|
+
this.hashStyleObject(groupSet, styles);
|
|
2188
|
+
if (groupSet.size === 0) return;
|
|
2189
|
+
const groupId = Array.from(groupSet).sort().join("|");
|
|
2190
|
+
if (this.grouped.get(groupId)) return;
|
|
2191
|
+
this.grouped.set(groupId, groupSet);
|
|
2192
|
+
};
|
|
2193
|
+
processStyleProps = (styleProps, grouped = false) => {
|
|
2194
|
+
const processFn = grouped ? this.processGrouped : this.processAtomic;
|
|
2195
|
+
const styles = this.filterStyleProps(styleProps);
|
|
2196
|
+
const rest = {};
|
|
2197
|
+
for (const [key, value] of Object.entries(styles)) if (key === "css" || key.endsWith("Css")) {
|
|
2198
|
+
if (Array.isArray(value)) value.forEach((style) => processFn(style));
|
|
2199
|
+
else if (value) processFn(value);
|
|
2200
|
+
} else rest[key] = value;
|
|
2201
|
+
processFn(rest);
|
|
2202
|
+
};
|
|
2203
|
+
processConfigSlotRecipeBase = (recipeName, config) => {
|
|
2204
|
+
config.slots.forEach((slot) => {
|
|
2205
|
+
const recipeKey = this.context.recipes.getSlotKey(recipeName, slot);
|
|
2206
|
+
const slotBase = config.base?.[slot];
|
|
2207
|
+
if (!slotBase || this.recipes_base.has(recipeKey)) return;
|
|
2208
|
+
const base_set = (0, _bamboocss_shared.getOrCreateSet)(this.recipes_base, recipeKey);
|
|
2209
|
+
this.hashStyleObject(base_set, slotBase, {
|
|
2210
|
+
recipe: recipeName,
|
|
2211
|
+
slot
|
|
2212
|
+
});
|
|
2213
|
+
});
|
|
2214
|
+
};
|
|
2215
|
+
processConfigSlotRecipe = (recipeName, variants) => {
|
|
2216
|
+
const config = this.context.recipes.getConfig(recipeName);
|
|
2217
|
+
if (!Recipes.isSlotRecipeConfig(config)) return;
|
|
2218
|
+
this.processConfigSlotRecipeBase(recipeName, config);
|
|
2219
|
+
const set = (0, _bamboocss_shared.getOrCreateSet)(this.recipes, recipeName);
|
|
2220
|
+
const computedVariants = Object.assign({}, config.defaultVariants, variants);
|
|
2221
|
+
this.hashStyleObject(set, computedVariants, {
|
|
2222
|
+
recipe: recipeName,
|
|
2223
|
+
variants: true
|
|
2224
|
+
});
|
|
2225
|
+
if (!config.compoundVariants || this.compound_variants.has(recipeName)) return;
|
|
2226
|
+
this.compound_variants.add(recipeName);
|
|
2227
|
+
config.compoundVariants.forEach((compoundVariant) => {
|
|
2228
|
+
if (!compoundVariant) return;
|
|
2229
|
+
Object.values(compoundVariant.css).forEach((values) => {
|
|
2230
|
+
if (!values) return;
|
|
2231
|
+
this.processAtomic(values);
|
|
2232
|
+
});
|
|
2233
|
+
});
|
|
2234
|
+
};
|
|
2235
|
+
processConfigRecipeBase = (recipeName, config) => {
|
|
2236
|
+
if (!config.base || this.recipes_base.has(recipeName)) return;
|
|
2237
|
+
const base_set = (0, _bamboocss_shared.getOrCreateSet)(this.recipes_base, recipeName);
|
|
2238
|
+
this.hashStyleObject(base_set, config.base, { recipe: recipeName });
|
|
2239
|
+
};
|
|
2240
|
+
processConfigRecipe = (recipeName, variants) => {
|
|
2241
|
+
const config = this.context.recipes.getConfig(recipeName);
|
|
2242
|
+
if (!config) return;
|
|
2243
|
+
this.processConfigRecipeBase(recipeName, config);
|
|
2244
|
+
const set = (0, _bamboocss_shared.getOrCreateSet)(this.recipes, recipeName);
|
|
2245
|
+
const computedVariants = Object.assign({}, config.defaultVariants, variants);
|
|
2246
|
+
this.hashStyleObject(set, computedVariants, {
|
|
2247
|
+
recipe: recipeName,
|
|
2248
|
+
variants: true
|
|
2249
|
+
});
|
|
2250
|
+
if (!config.compoundVariants || this.compound_variants.has(recipeName)) return;
|
|
2251
|
+
this.compound_variants.add(recipeName);
|
|
2252
|
+
config.compoundVariants.forEach((compoundVariant) => {
|
|
2253
|
+
if (!compoundVariant) return;
|
|
2254
|
+
this.processAtomic(compoundVariant.css);
|
|
2255
|
+
});
|
|
2256
|
+
};
|
|
2257
|
+
processRecipe = (recipeName, variants) => {
|
|
2258
|
+
if (this.context.recipes.isSlotRecipe(recipeName)) this.processConfigSlotRecipe(recipeName, variants);
|
|
2259
|
+
else this.processConfigRecipe(recipeName, variants);
|
|
2260
|
+
};
|
|
2261
|
+
processRecipeBase(recipeName) {
|
|
2262
|
+
const config = this.context.recipes.getConfig(recipeName);
|
|
2263
|
+
if (!config) return;
|
|
2264
|
+
if (this.context.recipes.isSlotRecipe(recipeName)) this.processConfigSlotRecipeBase(recipeName, config);
|
|
2265
|
+
else this.processConfigRecipeBase(recipeName, config);
|
|
2266
|
+
}
|
|
2267
|
+
processPattern = (name, patternProps, type, jsxName) => {
|
|
2268
|
+
let fnName = name;
|
|
2269
|
+
if (type === "jsx-pattern" && jsxName) fnName = this.context.patterns.find(jsxName);
|
|
2270
|
+
const styleProps = this.context.patterns.transform(fnName, patternProps);
|
|
2271
|
+
this.processStyleProps(styleProps);
|
|
2272
|
+
};
|
|
2273
|
+
processAtomicRecipe = (recipe) => {
|
|
2274
|
+
const { base = {}, variants = {}, compoundVariants = [] } = recipe;
|
|
2275
|
+
this.processAtomic(base);
|
|
2276
|
+
for (const variant of Object.values(variants)) for (const styles of Object.values(variant)) this.processAtomic(styles);
|
|
2277
|
+
compoundVariants.forEach((compoundVariant) => {
|
|
2278
|
+
if (!compoundVariant) return;
|
|
2279
|
+
this.processAtomic(compoundVariant.css);
|
|
2280
|
+
});
|
|
2281
|
+
};
|
|
2282
|
+
processAtomicSlotRecipe = (recipe) => {
|
|
2283
|
+
const inferredSlots = Recipes.inferSlots(recipe);
|
|
2284
|
+
recipe.slots = (0, _bamboocss_shared.uniq)([...recipe.slots ?? [], ...inferredSlots].filter(Boolean));
|
|
2285
|
+
const slots = (0, _bamboocss_shared.getSlotRecipes)(recipe);
|
|
2286
|
+
for (const slotRecipe of Object.values(slots)) this.processAtomicRecipe(slotRecipe);
|
|
2287
|
+
};
|
|
2288
|
+
getConfigRecipeHash = (recipeName) => {
|
|
2289
|
+
return {
|
|
2290
|
+
atomic: this.atomic,
|
|
2291
|
+
base: this.recipes_base.get(recipeName),
|
|
2292
|
+
variants: this.recipes.get(recipeName)
|
|
2293
|
+
};
|
|
2294
|
+
};
|
|
2295
|
+
getConfigSlotRecipeHash = (recipeName) => {
|
|
2296
|
+
const recipeConfig = this.context.recipes.getConfigOrThrow(recipeName);
|
|
2297
|
+
if (!Recipes.isSlotRecipeConfig(recipeConfig)) throw new _bamboocss_shared.BambooError("INVALID_RECIPE", `Recipe "${recipeName}" is not a slot recipe`);
|
|
2298
|
+
const base = {};
|
|
2299
|
+
recipeConfig.slots.map((slot) => {
|
|
2300
|
+
const recipeKey = this.context.recipes.getSlotKey(recipeName, slot);
|
|
2301
|
+
base[slot] = this.recipes_base.get(recipeKey);
|
|
2302
|
+
});
|
|
2303
|
+
return {
|
|
2304
|
+
atomic: this.atomic,
|
|
2305
|
+
base,
|
|
2306
|
+
variants: this.recipes.get(recipeName)
|
|
2307
|
+
};
|
|
2308
|
+
};
|
|
2309
|
+
getRecipeHash = (recipeName) => {
|
|
2310
|
+
if (this.context.recipes.isSlotRecipe(recipeName)) return this.getConfigSlotRecipeHash(recipeName);
|
|
2311
|
+
return this.getConfigRecipeHash(recipeName);
|
|
2312
|
+
};
|
|
2313
|
+
toJSON = () => {
|
|
2314
|
+
const styles = {
|
|
2315
|
+
atomic: Array.from(this.atomic),
|
|
2316
|
+
recipes: Object.fromEntries(Array.from(this.recipes.entries()).map(([name, set]) => [name, Array.from(set)]))
|
|
2317
|
+
};
|
|
2318
|
+
if (this.grouped.size) styles.grouped = Object.fromEntries(Array.from(this.grouped.entries()).map(([id, set]) => [id, Array.from(set)]));
|
|
2319
|
+
return {
|
|
2320
|
+
schemaVersion: version,
|
|
2321
|
+
styles
|
|
2322
|
+
};
|
|
2323
|
+
};
|
|
2324
|
+
fromJSON = (json) => {
|
|
2325
|
+
const { styles } = json;
|
|
2326
|
+
styles.atomic?.forEach((hash) => this.atomic.add(hash));
|
|
2327
|
+
Object.entries(styles.recipes ?? {}).forEach(([recipeName, hashes]) => {
|
|
2328
|
+
this.processRecipeBase(recipeName);
|
|
2329
|
+
const set = (0, _bamboocss_shared.getOrCreateSet)(this.recipes, recipeName);
|
|
2330
|
+
hashes.forEach((hash) => set.add(hash));
|
|
2331
|
+
});
|
|
2332
|
+
Object.entries(styles.grouped ?? {}).forEach(([groupId, hashes]) => {
|
|
2333
|
+
const set = (0, _bamboocss_shared.getOrCreateSet)(this.grouped, groupId);
|
|
2334
|
+
hashes.forEach((hash) => set.add(hash));
|
|
2335
|
+
});
|
|
2336
|
+
return this;
|
|
2337
|
+
};
|
|
2338
|
+
};
|
|
2339
|
+
const filterProps = (isValidProperty, props) => {
|
|
2340
|
+
const clone = {};
|
|
2341
|
+
for (const [key, value] of Object.entries(props)) if ((isValidProperty(key) || key === "css" || key.endsWith("Css")) && value !== void 0) clone[key] = value;
|
|
2342
|
+
return clone;
|
|
2343
|
+
};
|
|
2344
|
+
const hashStyleEntry = (entry) => {
|
|
2345
|
+
const parts = [`${entry.prop}${StyleEncoder.separator}value:${entry.value}`];
|
|
2346
|
+
if (entry.cond) parts.push(`cond:${entry.cond}`);
|
|
2347
|
+
if (entry.recipe) parts.push(`recipe:${entry.recipe}`);
|
|
2348
|
+
if (entry.layer) parts.push(`layer:${entry.layer}`);
|
|
2349
|
+
if (entry.slot) parts.push(`slot:${entry.slot}`);
|
|
2350
|
+
return parts.join(StyleEncoder.separator);
|
|
2351
|
+
};
|
|
2352
|
+
/**
|
|
2353
|
+
* Returns the final condition string after filtering out irrelevant parts. ('base' and props)
|
|
2354
|
+
* @example
|
|
2355
|
+
* 'marginTop<___>md' => 'md'
|
|
2356
|
+
* 'marginTop<___>md<___>lg' => 'md<___>lg'
|
|
2357
|
+
* '_hover' => '_hover'
|
|
2358
|
+
* '& > p<___>base', => '& > p'
|
|
2359
|
+
* '@media base' => '@media base'
|
|
2360
|
+
* '_hover<___>base<___>_dark' => '_hover<___>_dark'
|
|
2361
|
+
*
|
|
2362
|
+
*/
|
|
2363
|
+
const getResolvedCondition = (cond, isCondition) => {
|
|
2364
|
+
if (!cond) return "";
|
|
2365
|
+
const parts = cond.split(StyleEncoder.conditionSeparator);
|
|
2366
|
+
const relevantParts = parts.filter((part) => part !== "base" && isCondition(part));
|
|
2367
|
+
if (parts.length !== relevantParts.length) return relevantParts.join(StyleEncoder.conditionSeparator);
|
|
2368
|
+
return cond;
|
|
2369
|
+
};
|
|
2370
|
+
//#endregion
|
|
2371
|
+
//#region src/style-decoder.ts
|
|
2372
|
+
var StyleDecoder = class StyleDecoder {
|
|
2373
|
+
context;
|
|
2374
|
+
constructor(context) {
|
|
2375
|
+
this.context = context;
|
|
2376
|
+
}
|
|
2377
|
+
classNames = /* @__PURE__ */ new Map();
|
|
2378
|
+
atomic_cache = /* @__PURE__ */ new Map();
|
|
2379
|
+
group_cache = /* @__PURE__ */ new Map();
|
|
2380
|
+
recipe_base_cache = /* @__PURE__ */ new Map();
|
|
2381
|
+
atomic = /* @__PURE__ */ new Set();
|
|
2382
|
+
grouped = /* @__PURE__ */ new Set();
|
|
2383
|
+
recipes = /* @__PURE__ */ new Map();
|
|
2384
|
+
recipes_base = /* @__PURE__ */ new Map();
|
|
2385
|
+
clone = () => {
|
|
2386
|
+
return new StyleDecoder(this.context);
|
|
2387
|
+
};
|
|
2388
|
+
isEmpty = () => {
|
|
2389
|
+
return !this.atomic.size && !this.grouped.size && !this.recipes.size && !this.recipes_base.size;
|
|
2390
|
+
};
|
|
2391
|
+
get results() {
|
|
2392
|
+
return {
|
|
2393
|
+
atomic: this.atomic,
|
|
2394
|
+
grouped: this.grouped,
|
|
2395
|
+
recipes: this.recipes,
|
|
2396
|
+
recipes_base: this.recipes_base
|
|
2397
|
+
};
|
|
2398
|
+
}
|
|
2399
|
+
formatSelector = (conditions, className) => {
|
|
2400
|
+
const { conditions: cond, hash, utility } = this.context;
|
|
2401
|
+
const conds = cond.finalize(conditions);
|
|
2402
|
+
let result;
|
|
2403
|
+
if (hash.className) {
|
|
2404
|
+
conds.push(className);
|
|
2405
|
+
result = utility.formatClassName(utility.toHash(conds, utility.defaultHashFn));
|
|
2406
|
+
} else {
|
|
2407
|
+
conds.push(utility.formatClassName(className));
|
|
2408
|
+
result = conds.join(":");
|
|
2409
|
+
}
|
|
2410
|
+
return (0, _bamboocss_shared.esc)(result);
|
|
2411
|
+
};
|
|
2412
|
+
getRecipeName = (hash) => {
|
|
2413
|
+
const entry = getEntryFromHash(hash);
|
|
2414
|
+
if (!entry.recipe) return;
|
|
2415
|
+
return entry.slot ? this.context.recipes.getSlotKey(entry.recipe, entry.slot) : entry.recipe;
|
|
2416
|
+
};
|
|
2417
|
+
getTransformResult = (hash) => {
|
|
2418
|
+
const entry = getEntryFromHash(hash);
|
|
2419
|
+
const recipeName = this.getRecipeName(hash);
|
|
2420
|
+
const transformed = (recipeName ? this.context.recipes.getTransform(recipeName) : this.context.utility.transform)(entry.prop, (0, _bamboocss_shared.withoutImportant)(entry.value));
|
|
2421
|
+
if (!transformed.className) return;
|
|
2422
|
+
const important = (0, _bamboocss_shared.isImportant)(entry.value);
|
|
2423
|
+
const styles = important ? (0, _bamboocss_shared.markImportant)(transformed.styles) : transformed.styles;
|
|
2424
|
+
const parts = entry.cond ? entry.cond.split(StyleEncoder.conditionSeparator) : [];
|
|
2425
|
+
const className = this.formatSelector(parts, transformed.className);
|
|
2426
|
+
return {
|
|
2427
|
+
className,
|
|
2428
|
+
classSelector: important ? `.${className}\\!` : `.${className}`,
|
|
2429
|
+
styles,
|
|
2430
|
+
transformed,
|
|
2431
|
+
parts
|
|
2432
|
+
};
|
|
2433
|
+
};
|
|
2434
|
+
resolveCondition = (condition) => {
|
|
2435
|
+
if (condition.type === "multi-block") return [];
|
|
2436
|
+
if (Array.isArray(condition.raw)) return condition.raw.map((c) => this.context.utility.tokens.resolveReference(c));
|
|
2437
|
+
return this.context.utility.tokens.resolveReference(condition.raw);
|
|
2438
|
+
};
|
|
2439
|
+
/**
|
|
2440
|
+
* Expands multi-block conditions into separate sets of conditions.
|
|
2441
|
+
* Each block becomes an independent condition set that produces its own CSS block.
|
|
2442
|
+
* When multiple multi-block conditions are stacked (e.g. two custom multi-block
|
|
2443
|
+
* conditions used together), the cartesian product of all blocks is produced.
|
|
2444
|
+
* Returns null if no multi-block condition is found.
|
|
2445
|
+
*/
|
|
2446
|
+
expandMultiBlock(conditions) {
|
|
2447
|
+
if (!conditions.some((c) => c.type === "multi-block")) return null;
|
|
2448
|
+
const alternatives = conditions.map((c) => {
|
|
2449
|
+
if (c.type === "multi-block") return c.value.map((block) => block.value.filter(Boolean));
|
|
2450
|
+
return [[c]];
|
|
2451
|
+
});
|
|
2452
|
+
let combos = [[]];
|
|
2453
|
+
for (const slot of alternatives) {
|
|
2454
|
+
const next = [];
|
|
2455
|
+
for (const partial of combos) for (const choice of slot) next.push([...partial, ...choice]);
|
|
2456
|
+
combos = next;
|
|
2457
|
+
}
|
|
2458
|
+
return combos.map((combo) => sortConditionDetails(combo));
|
|
2459
|
+
}
|
|
2460
|
+
getAtomic = (hash) => {
|
|
2461
|
+
const cached = this.atomic_cache.get(hash);
|
|
2462
|
+
if (cached) return cached;
|
|
2463
|
+
const entry = getEntryFromHash(hash);
|
|
2464
|
+
const transformResult = this.getTransformResult(hash);
|
|
2465
|
+
if (!transformResult) return;
|
|
2466
|
+
const { className, classSelector, styles, transformed, parts } = transformResult;
|
|
2467
|
+
const basePath = [classSelector];
|
|
2468
|
+
const obj = {};
|
|
2469
|
+
let conditions;
|
|
2470
|
+
if (entry.cond) {
|
|
2471
|
+
conditions = this.context.conditions.sort(parts);
|
|
2472
|
+
const expanded = this.expandMultiBlock(conditions);
|
|
2473
|
+
if (expanded) for (const blockConditions of expanded) (0, _bamboocss_shared.deepSet)(obj, basePath.concat(blockConditions.flatMap((c) => this.resolveCondition(c))), styles);
|
|
2474
|
+
else (0, _bamboocss_shared.deepSet)(obj, basePath.concat(conditions.flatMap((c) => this.resolveCondition(c))), styles);
|
|
2475
|
+
} else (0, _bamboocss_shared.deepSet)(obj, basePath, styles);
|
|
2476
|
+
const styleResult = {
|
|
2477
|
+
result: obj,
|
|
2478
|
+
entry,
|
|
2479
|
+
hash,
|
|
2480
|
+
conditions,
|
|
2481
|
+
className,
|
|
2482
|
+
layer: transformed.layer
|
|
2483
|
+
};
|
|
2484
|
+
this.atomic_cache.set(hash, styleResult);
|
|
2485
|
+
return styleResult;
|
|
2486
|
+
};
|
|
2487
|
+
getGroup = (hashSet, key) => {
|
|
2488
|
+
const cached = this.group_cache.get(key);
|
|
2489
|
+
if (cached) return cached;
|
|
2490
|
+
let obj = {};
|
|
2491
|
+
const basePath = [];
|
|
2492
|
+
const details = [];
|
|
2493
|
+
const transform = this.context.utility.transform.bind(this.context.utility);
|
|
2494
|
+
hashSet.forEach((hash) => {
|
|
2495
|
+
const entry = getEntryFromHash(hash);
|
|
2496
|
+
const transformed = transform(entry.prop, (0, _bamboocss_shared.withoutImportant)(entry.value));
|
|
2497
|
+
if (!transformed.className) return;
|
|
2498
|
+
const result = (0, _bamboocss_shared.isImportant)(entry.value) ? (0, _bamboocss_shared.markImportant)(transformed.styles) : transformed.styles;
|
|
2499
|
+
const parts = entry.cond ? entry.cond.split(StyleEncoder.conditionSeparator) : [];
|
|
2500
|
+
let conditions;
|
|
2501
|
+
if (entry.cond) conditions = this.context.conditions.sort(parts);
|
|
2502
|
+
details.push({
|
|
2503
|
+
hash,
|
|
2504
|
+
entry,
|
|
2505
|
+
conditions,
|
|
2506
|
+
result
|
|
2507
|
+
});
|
|
2508
|
+
});
|
|
2509
|
+
sortStyleRules(details).forEach((value) => {
|
|
2510
|
+
if (value.conditions) {
|
|
2511
|
+
const expanded = this.expandMultiBlock(value.conditions);
|
|
2512
|
+
if (expanded) for (const blockConditions of expanded) {
|
|
2513
|
+
const path = basePath.concat(blockConditions.flatMap((c) => this.resolveCondition(c)));
|
|
2514
|
+
obj = (0, _bamboocss_shared.deepSet)(obj, path, value.result);
|
|
2515
|
+
}
|
|
2516
|
+
else {
|
|
2517
|
+
const path = basePath.concat(value.conditions.flatMap((c) => this.resolveCondition(c)));
|
|
2518
|
+
obj = (0, _bamboocss_shared.deepSet)(obj, path, value.result);
|
|
2519
|
+
}
|
|
2520
|
+
} else obj = (0, _bamboocss_shared.deepSet)(obj, basePath, value.result);
|
|
2521
|
+
});
|
|
2522
|
+
const result = {
|
|
2523
|
+
result: obj,
|
|
2524
|
+
hashSet,
|
|
2525
|
+
details,
|
|
2526
|
+
className: key
|
|
2527
|
+
};
|
|
2528
|
+
this.group_cache.set(key, result);
|
|
2529
|
+
return result;
|
|
2530
|
+
};
|
|
2531
|
+
getRecipeBase = (hashSet, recipeName, slot) => {
|
|
2532
|
+
const recipeConfig = this.context.recipes.getConfig(recipeName);
|
|
2533
|
+
if (!recipeConfig) return;
|
|
2534
|
+
const recipeNode = this.context.recipes.getRecipe(recipeName);
|
|
2535
|
+
if (!recipeNode) return;
|
|
2536
|
+
const className = "slots" in recipeConfig && slot ? this.context.recipes.getSlotKey(recipeNode.className, slot) : recipeNode.className;
|
|
2537
|
+
const cached = this.recipe_base_cache.get(className);
|
|
2538
|
+
if (cached) return cached;
|
|
2539
|
+
const selector = this.formatSelector([], className);
|
|
2540
|
+
const style = this.getGroup(hashSet, className);
|
|
2541
|
+
const result = Object.assign({}, style, {
|
|
2542
|
+
result: { ["." + selector]: style.result },
|
|
2543
|
+
recipe: recipeName,
|
|
2544
|
+
className,
|
|
2545
|
+
slot
|
|
2546
|
+
});
|
|
2547
|
+
this.recipe_base_cache.set(className, result);
|
|
2548
|
+
return result;
|
|
2549
|
+
};
|
|
2550
|
+
collectAtomic = (encoder) => {
|
|
2551
|
+
const atomic = [];
|
|
2552
|
+
encoder.atomic.forEach((item) => {
|
|
2553
|
+
const result = this.getAtomic(item);
|
|
2554
|
+
if (!result) return;
|
|
2555
|
+
atomic.push(result);
|
|
2556
|
+
});
|
|
2557
|
+
sortStyleRules(atomic).forEach((styleResult) => {
|
|
2558
|
+
this.atomic.add(styleResult);
|
|
2559
|
+
this.classNames.set(styleResult.className, styleResult);
|
|
2560
|
+
});
|
|
2561
|
+
return this;
|
|
2562
|
+
};
|
|
2563
|
+
processClassName = (recipeName, hash) => {
|
|
2564
|
+
const result = this.getAtomic(hash);
|
|
2565
|
+
if (!result) return;
|
|
2566
|
+
(0, _bamboocss_shared.getOrCreateSet)(this.recipes, recipeName).add(result);
|
|
2567
|
+
this.classNames.set(result.className, result);
|
|
2568
|
+
};
|
|
2569
|
+
collectRecipe = (encoder) => {
|
|
2570
|
+
encoder.recipes.forEach((hashSet, recipeName) => {
|
|
2571
|
+
const recipeConfig = this.context.recipes.getConfig(recipeName);
|
|
2572
|
+
if (!recipeConfig) return;
|
|
2573
|
+
hashSet.forEach((hash) => {
|
|
2574
|
+
if ("slots" in recipeConfig) recipeConfig.slots.forEach((slot) => {
|
|
2575
|
+
const slotHash = hash + StyleEncoder.separator + "slot:" + slot;
|
|
2576
|
+
this.processClassName(recipeName, slotHash);
|
|
2577
|
+
});
|
|
2578
|
+
else this.processClassName(recipeName, hash);
|
|
2579
|
+
});
|
|
2580
|
+
});
|
|
2581
|
+
};
|
|
2582
|
+
collectRecipeBase = (encoder) => {
|
|
2583
|
+
encoder.recipes_base.forEach((hashSet, recipeKey) => {
|
|
2584
|
+
const [recipeName, slot] = recipeKey.split(this.context.recipes.slotSeparator);
|
|
2585
|
+
if (!this.context.recipes.getConfig(recipeName)) return;
|
|
2586
|
+
const result = this.getRecipeBase(hashSet, recipeName, slot);
|
|
2587
|
+
if (!result) return;
|
|
2588
|
+
(0, _bamboocss_shared.getOrCreateSet)(this.recipes_base, recipeKey).add(result);
|
|
2589
|
+
this.classNames.set(result.className, result);
|
|
2590
|
+
});
|
|
2591
|
+
};
|
|
2592
|
+
collectGrouped = (encoder) => {
|
|
2593
|
+
encoder.grouped.forEach((hashSet, groupId) => {
|
|
2594
|
+
const groupKey = "grouped:" + groupId;
|
|
2595
|
+
const style = this.getGroup(hashSet, groupKey);
|
|
2596
|
+
const shortHash = this.context.utility.toHash(["grouped", groupId], this.context.utility.defaultHashFn);
|
|
2597
|
+
const className = this.formatSelector([], shortHash);
|
|
2598
|
+
const result = {
|
|
2599
|
+
...style,
|
|
2600
|
+
className,
|
|
2601
|
+
result: { ["." + className]: style.result }
|
|
2602
|
+
};
|
|
2603
|
+
this.grouped.add(result);
|
|
2604
|
+
this.classNames.set(className, result);
|
|
2605
|
+
});
|
|
2606
|
+
};
|
|
2607
|
+
/**
|
|
2608
|
+
* Collect and re-create all styles and recipes objects from the style encoder
|
|
2609
|
+
* So that we can just iterate over them and transform resulting CSS objects into CSS strings
|
|
2610
|
+
*/
|
|
2611
|
+
collect = (encoder) => {
|
|
2612
|
+
this.collectAtomic(encoder);
|
|
2613
|
+
this.collectGrouped(encoder);
|
|
2614
|
+
this.collectRecipe(encoder);
|
|
2615
|
+
this.collectRecipeBase(encoder);
|
|
2616
|
+
return this;
|
|
2617
|
+
};
|
|
2618
|
+
getConfigRecipeResult = (recipeName) => {
|
|
2619
|
+
return {
|
|
2620
|
+
atomic: this.atomic,
|
|
2621
|
+
base: this.recipes_base.get(recipeName),
|
|
2622
|
+
variants: this.recipes.get(recipeName)
|
|
2623
|
+
};
|
|
2624
|
+
};
|
|
2625
|
+
getConfigSlotRecipeResult = (recipeName) => {
|
|
2626
|
+
const recipeConfig = this.context.recipes.getConfigOrThrow(recipeName);
|
|
2627
|
+
if (!Recipes.isSlotRecipeConfig(recipeConfig)) throw new _bamboocss_shared.BambooError("UNKNOWN_RECIPE", `Recipe "${recipeName}" is not a slot recipe`);
|
|
2628
|
+
const base = {};
|
|
2629
|
+
recipeConfig.slots.map((slot) => {
|
|
2630
|
+
const recipeKey = this.context.recipes.getSlotKey(recipeName, slot);
|
|
2631
|
+
base[slot] = this.recipes_base.get(recipeKey);
|
|
2632
|
+
});
|
|
2633
|
+
return {
|
|
2634
|
+
atomic: this.atomic,
|
|
2635
|
+
base,
|
|
2636
|
+
variants: this.recipes.get(recipeName)
|
|
2637
|
+
};
|
|
2638
|
+
};
|
|
2639
|
+
getRecipeResult = (recipeName) => {
|
|
2640
|
+
if (this.context.recipes.isSlotRecipe(recipeName)) return this.getConfigSlotRecipeResult(recipeName);
|
|
2641
|
+
return this.getConfigRecipeResult(recipeName);
|
|
2642
|
+
};
|
|
2643
|
+
};
|
|
2644
|
+
const entryKeys = [
|
|
2645
|
+
"cond",
|
|
2646
|
+
"recipe",
|
|
2647
|
+
"layer",
|
|
2648
|
+
"slot"
|
|
2649
|
+
];
|
|
2650
|
+
const getEntryFromHash = (hash) => {
|
|
2651
|
+
const parts = hash.split(StyleEncoder.separator);
|
|
2652
|
+
const entry = {
|
|
2653
|
+
prop: parts[0],
|
|
2654
|
+
value: parseValue(parts[1].replace("value:", ""))
|
|
2655
|
+
};
|
|
2656
|
+
parts.forEach((part) => {
|
|
2657
|
+
const key = entryKeys.find((k) => part.startsWith(k));
|
|
2658
|
+
if (key) entry[key] = part.slice(key.length + 1);
|
|
2659
|
+
});
|
|
2660
|
+
return entry;
|
|
2661
|
+
};
|
|
2662
|
+
const startsWithZero = /^0\d+$/;
|
|
2663
|
+
const parseValue = (value) => {
|
|
2664
|
+
if (startsWithZero.test(value)) return value;
|
|
2665
|
+
const asNumber = Number(value);
|
|
2666
|
+
if (!Number.isNaN(asNumber)) return asNumber;
|
|
2667
|
+
return castBoolean(value);
|
|
2668
|
+
};
|
|
2669
|
+
const castBoolean = (value) => {
|
|
2670
|
+
if (value === "true") return true;
|
|
2671
|
+
if (value === "false") return false;
|
|
2672
|
+
return value;
|
|
2673
|
+
};
|
|
2674
|
+
const pseudoElementRegex = /::[\w-]/;
|
|
2675
|
+
/**
|
|
2676
|
+
* Sort flattened condition details (at-rules and selectors only):
|
|
2677
|
+
* at-rules first, pseudo-elements last, preserve relative order.
|
|
2678
|
+
*
|
|
2679
|
+
* Note: This only operates on individual at-rule and selector conditions
|
|
2680
|
+
* (not mixed or multi-block), so checking `raw` as string is sufficient
|
|
2681
|
+
* for pseudo-element detection.
|
|
2682
|
+
*/
|
|
2683
|
+
const sortConditionDetails = (conditions) => {
|
|
2684
|
+
const indexed = conditions.map((cond, i) => ({
|
|
2685
|
+
cond,
|
|
2686
|
+
i
|
|
2687
|
+
}));
|
|
2688
|
+
indexed.sort((a, b) => {
|
|
2689
|
+
const aIsAtRule = a.cond.type === "at-rule";
|
|
2690
|
+
const bIsAtRule = b.cond.type === "at-rule";
|
|
2691
|
+
if (aIsAtRule && !bIsAtRule) return -1;
|
|
2692
|
+
if (!aIsAtRule && bIsAtRule) return 1;
|
|
2693
|
+
const aIsPseudo = typeof a.cond.raw === "string" && pseudoElementRegex.test(a.cond.raw);
|
|
2694
|
+
if (aIsPseudo !== (typeof b.cond.raw === "string" && pseudoElementRegex.test(b.cond.raw))) return aIsPseudo ? 1 : -1;
|
|
2695
|
+
return a.i - b.i;
|
|
2696
|
+
});
|
|
2697
|
+
return indexed.map((item) => item.cond);
|
|
2698
|
+
};
|
|
2699
|
+
//#endregion
|
|
2700
|
+
//#region src/static-css.ts
|
|
2701
|
+
var StaticCss = class {
|
|
2702
|
+
context;
|
|
2703
|
+
encoder;
|
|
2704
|
+
decoder;
|
|
2705
|
+
breakpointKeys;
|
|
2706
|
+
conditionKeys;
|
|
2707
|
+
wildcardCache = /* @__PURE__ */ new Map();
|
|
2708
|
+
constructor(context) {
|
|
2709
|
+
this.context = context;
|
|
2710
|
+
this.encoder = context.encoder;
|
|
2711
|
+
this.decoder = context.decoder;
|
|
2712
|
+
this.breakpointKeys = Object.keys(context.config.theme?.breakpoints ?? {});
|
|
2713
|
+
this.conditionKeys = Object.keys(context.config.conditions ?? {});
|
|
2714
|
+
}
|
|
2715
|
+
clone() {
|
|
2716
|
+
this.encoder = this.encoder.clone();
|
|
2717
|
+
this.decoder = this.decoder.clone();
|
|
2718
|
+
return this;
|
|
2719
|
+
}
|
|
2720
|
+
formatCondition = (condition) => {
|
|
2721
|
+
return this.conditionKeys.includes(condition) ? `_${condition}` : condition;
|
|
2722
|
+
};
|
|
2723
|
+
getConditionalValues = (conditions, value) => {
|
|
2724
|
+
return conditions.reduce((acc, key) => {
|
|
2725
|
+
const cond = this.formatCondition(key);
|
|
2726
|
+
return {
|
|
2727
|
+
...acc,
|
|
2728
|
+
[cond]: value
|
|
2729
|
+
};
|
|
2730
|
+
}, { base: value });
|
|
2731
|
+
};
|
|
2732
|
+
createRegex = () => {
|
|
2733
|
+
const pattern = `(${Array.from(this.decoder.classNames.keys()).map((name) => (0, _bamboocss_shared.esc)(name)).join("|")})`;
|
|
2734
|
+
return new RegExp(`\\b${pattern}\\b`, "g");
|
|
2735
|
+
};
|
|
2736
|
+
parse = (text) => {
|
|
2737
|
+
const regex = this.createRegex();
|
|
2738
|
+
const matches = text.match(regex);
|
|
2739
|
+
if (!matches) return [];
|
|
2740
|
+
return matches.map((match) => match.replace(".", ""));
|
|
2741
|
+
};
|
|
2742
|
+
/**
|
|
2743
|
+
* Get property keys with memoization for wildcard expansion
|
|
2744
|
+
* This is the main performance optimization - avoids redundant token lookups
|
|
2745
|
+
*/
|
|
2746
|
+
getCachedPropertyKeys = (property) => {
|
|
2747
|
+
if (!this.wildcardCache.has(property)) {
|
|
2748
|
+
const keys = this.context.utility.getPropertyKeys(property);
|
|
2749
|
+
this.wildcardCache.set(property, keys);
|
|
2750
|
+
_bamboocss_logger.logger.debug("static_css:wildcard", `${property} -> ${keys.length} values (memoized)`);
|
|
2751
|
+
} else _bamboocss_logger.logger.debug("static_css:wildcard", `${property} (cache hit)`);
|
|
2752
|
+
return this.wildcardCache.get(property);
|
|
2753
|
+
};
|
|
2754
|
+
/**
|
|
2755
|
+
* Get pattern property values with memoization
|
|
2756
|
+
*/
|
|
2757
|
+
getCachedPatternPropertyValues = (patternName, property) => {
|
|
2758
|
+
const cacheKey = `${patternName}:${property}`;
|
|
2759
|
+
if (!this.wildcardCache.has(cacheKey)) {
|
|
2760
|
+
const values = this.context.patterns.getPropertyValues(patternName, property) ?? [];
|
|
2761
|
+
this.wildcardCache.set(cacheKey, values);
|
|
2762
|
+
_bamboocss_logger.logger.debug("static_css:wildcard", `Pattern ${patternName}.${property} -> ${values.length} values (memoized)`);
|
|
2763
|
+
} else _bamboocss_logger.logger.debug("static_css:wildcard", `Pattern ${patternName}.${property} (cache hit)`);
|
|
2764
|
+
return this.wildcardCache.get(cacheKey);
|
|
2765
|
+
};
|
|
2766
|
+
getCssObjects = (entry, conditions) => {
|
|
2767
|
+
const [property, values] = entry;
|
|
2768
|
+
const propKeys = this.getCachedPropertyKeys(property);
|
|
2769
|
+
return values.flatMap((value) => value === "*" ? propKeys : value).map((value) => ({ [property]: conditions.length ? this.getConditionalValues(conditions, value) : value }));
|
|
2770
|
+
};
|
|
2771
|
+
getCssRuleObjects = (rule) => {
|
|
2772
|
+
const conditions = rule.conditions || [];
|
|
2773
|
+
if (rule.responsive) conditions.push(...this.breakpointKeys);
|
|
2774
|
+
return Object.entries(rule.properties).flatMap((entry) => this.getCssObjects(entry, conditions));
|
|
2775
|
+
};
|
|
2776
|
+
getPatternObjects = (name, entry, conditions) => {
|
|
2777
|
+
const [property, values] = entry;
|
|
2778
|
+
const propValues = this.getCachedPatternPropertyValues(name, property);
|
|
2779
|
+
return values.flatMap((value) => value === "*" ? propValues : value).map((patternValue) => {
|
|
2780
|
+
const value = this.context.patterns.transform(name, { [property]: patternValue });
|
|
2781
|
+
const conditionalValues = this.getConditionalValues(conditions, value);
|
|
2782
|
+
return conditions.length ? conditionalValues : value;
|
|
2783
|
+
});
|
|
2784
|
+
};
|
|
2785
|
+
getPatternRuleObjects = (name, pattern) => {
|
|
2786
|
+
const details = this.context.patterns.details.find((d) => d.baseName === name);
|
|
2787
|
+
if (!details) return [];
|
|
2788
|
+
const useAllKeys = pattern === "*";
|
|
2789
|
+
let props = {};
|
|
2790
|
+
if (useAllKeys) props = Object.fromEntries((details.props ?? []).map((key) => [key, ["*"]]));
|
|
2791
|
+
const { conditions = [], responsive = false, properties = props } = useAllKeys ? {} : pattern;
|
|
2792
|
+
if (responsive) conditions.push(...this.breakpointKeys);
|
|
2793
|
+
return Object.entries(properties).flatMap((entry) => this.getPatternObjects(name, entry, conditions));
|
|
2794
|
+
};
|
|
2795
|
+
getRecipeNode = (name) => {
|
|
2796
|
+
return this.context.recipes.details.find((detail) => detail.baseName === name);
|
|
2797
|
+
};
|
|
2798
|
+
getRecipeRuleObjects = (name, recipe, recipeNode) => {
|
|
2799
|
+
const recipeKeys = recipeNode.variantKeyMap;
|
|
2800
|
+
if (!recipeKeys) return [];
|
|
2801
|
+
const { conditions = [], responsive, ...variants } = recipe === "*" ? recipeKeys : recipe;
|
|
2802
|
+
if (responsive) conditions.push(...this.breakpointKeys);
|
|
2803
|
+
return Object.entries(variants).flatMap(([variant, values]) => {
|
|
2804
|
+
if (!Array.isArray(values)) return [];
|
|
2805
|
+
return values.flatMap((value) => value === "*" ? recipeKeys[variant] : value).map((value) => {
|
|
2806
|
+
const conditionalValues = this.getConditionalValues(conditions, value);
|
|
2807
|
+
return { [name]: { [variant]: conditions.length ? conditionalValues : value } };
|
|
2808
|
+
});
|
|
2809
|
+
});
|
|
2810
|
+
};
|
|
2811
|
+
getRecipeCompoundVariantCssObjects = (recipeNode) => {
|
|
2812
|
+
const cssRules = [];
|
|
2813
|
+
const { compoundVariants } = recipeNode.config;
|
|
2814
|
+
if (!compoundVariants) return cssRules;
|
|
2815
|
+
compoundVariants.forEach((compoundVariant) => {
|
|
2816
|
+
const css = compoundVariant.css;
|
|
2817
|
+
if ("slots" in recipeNode.config && recipeNode.config.slots.length) Object.values(css).forEach((styles) => {
|
|
2818
|
+
Object.entries(styles).forEach(([prop, value]) => {
|
|
2819
|
+
cssRules.push({ [prop]: value });
|
|
2820
|
+
});
|
|
2821
|
+
});
|
|
2822
|
+
else Object.entries(css).forEach(([prop, value]) => {
|
|
2823
|
+
cssRules.push({ [prop]: value });
|
|
2824
|
+
});
|
|
2825
|
+
});
|
|
2826
|
+
return cssRules;
|
|
2827
|
+
};
|
|
2828
|
+
/**
|
|
2829
|
+
* This transforms a static css config into the same format as in the ParserResult,
|
|
2830
|
+
* so that it can be processed by the same logic as styles found in app code.
|
|
2831
|
+
*
|
|
2832
|
+
* e.g.
|
|
2833
|
+
* @example { css: [{ color: ['red', 'blue'] }] } => { css: [{ color: 'red }, { color: 'blue }] }
|
|
2834
|
+
* @example { css: [{ color: ['red'], conditions: ['md'] }] } => { css: [{ color: { base: 'red', md: 'red' } }] }
|
|
2835
|
+
*
|
|
2836
|
+
*/
|
|
2837
|
+
getStyleObjects(options) {
|
|
2838
|
+
const { css = [], patterns = {} } = options;
|
|
2839
|
+
const results = {
|
|
2840
|
+
css: [],
|
|
2841
|
+
recipes: [],
|
|
2842
|
+
patterns: []
|
|
2843
|
+
};
|
|
2844
|
+
css.forEach((rule) => {
|
|
2845
|
+
const cssObjects = this.getCssRuleObjects(rule);
|
|
2846
|
+
results.css.push(...cssObjects);
|
|
2847
|
+
});
|
|
2848
|
+
const recipes = options.recipes ?? {};
|
|
2849
|
+
Object.entries(recipes).forEach(([recipe, rules]) => {
|
|
2850
|
+
const recipeNode = this.getRecipeNode(recipe);
|
|
2851
|
+
if (!recipeNode) return;
|
|
2852
|
+
results.recipes.push({ [recipe]: {} });
|
|
2853
|
+
if (recipeNode.config.compoundVariants) results.css.push(...this.getRecipeCompoundVariantCssObjects(recipeNode));
|
|
2854
|
+
rules.forEach((rule) => {
|
|
2855
|
+
results.recipes.push(...this.getRecipeRuleObjects(recipe, rule, recipeNode));
|
|
2856
|
+
});
|
|
2857
|
+
});
|
|
2858
|
+
Object.entries(patterns).forEach(([pattern, rules]) => {
|
|
2859
|
+
rules.forEach((rule) => {
|
|
2860
|
+
results.patterns.push(...this.getPatternRuleObjects(pattern, rule));
|
|
2861
|
+
});
|
|
2862
|
+
});
|
|
2863
|
+
return results;
|
|
2864
|
+
}
|
|
2865
|
+
process = (options, stylesheet) => {
|
|
2866
|
+
const { context } = this;
|
|
2867
|
+
const sheet = stylesheet ?? context.createSheet();
|
|
2868
|
+
const isClonedInstance = this.encoder !== context.encoder;
|
|
2869
|
+
const encoder = isClonedInstance ? context.encoder.clone() : this.encoder;
|
|
2870
|
+
const decoder = isClonedInstance ? context.decoder.clone() : this.decoder;
|
|
2871
|
+
const staticCss = {
|
|
2872
|
+
...options,
|
|
2873
|
+
recipes: { ...typeof options.recipes === "string" ? {} : options.recipes }
|
|
2874
|
+
};
|
|
2875
|
+
const { theme = {} } = context.config;
|
|
2876
|
+
const recipeConfigs = Object.assign({}, theme.recipes, theme.slotRecipes);
|
|
2877
|
+
const useAllRecipes = options.recipes === "*";
|
|
2878
|
+
Object.entries(recipeConfigs).forEach(([name, recipe]) => {
|
|
2879
|
+
if (useAllRecipes) staticCss.recipes[name] = ["*"];
|
|
2880
|
+
else if (recipe.staticCss) staticCss.recipes[name] = recipe.staticCss;
|
|
2881
|
+
});
|
|
2882
|
+
_bamboocss_logger.logger.debug("static_css:process", `Processing staticCss`);
|
|
2883
|
+
const results = this.getStyleObjects(staticCss);
|
|
2884
|
+
_bamboocss_logger.logger.debug("static_css:process", `Generated style objects: ${results.css.length} css, ${results.recipes.length} recipes, ${results.patterns.length} patterns`);
|
|
2885
|
+
results.css.forEach((css) => {
|
|
2886
|
+
encoder.hashStyleObject(encoder.atomic, css);
|
|
2887
|
+
});
|
|
2888
|
+
results.recipes.forEach((result) => {
|
|
2889
|
+
Object.entries(result).forEach(([name, value]) => {
|
|
2890
|
+
encoder.processRecipe(name, value);
|
|
2891
|
+
});
|
|
2892
|
+
});
|
|
2893
|
+
results.patterns.forEach((result) => {
|
|
2894
|
+
encoder.hashStyleObject(encoder.atomic, result);
|
|
2895
|
+
});
|
|
2896
|
+
sheet.processDecoder(decoder.collect(encoder));
|
|
2897
|
+
return {
|
|
2898
|
+
results,
|
|
2899
|
+
sheet
|
|
2900
|
+
};
|
|
2901
|
+
};
|
|
2902
|
+
};
|
|
2903
|
+
//#endregion
|
|
2904
|
+
//#region src/plugins/merge-rules.ts
|
|
2905
|
+
const vendorPrefix = /-(ah|apple|atsc|epub|hp|khtml|moz|ms|o|rim|ro|tc|wap|webkit|xv)-/;
|
|
2906
|
+
const findMsInputPlaceholder = (selector) => ~selector.search(/-ms-input-placeholder/i);
|
|
2907
|
+
function filterPrefixes(selector) {
|
|
2908
|
+
return selector.match(vendorPrefix);
|
|
2909
|
+
}
|
|
2910
|
+
function sameVendor(selectorsA, selectorsB) {
|
|
2911
|
+
const same = (selectors) => selectors.map((s) => filterPrefixes(s)?.join() ?? "").join(",");
|
|
2912
|
+
const findMsVendor = (selectors) => selectors.find((s) => findMsInputPlaceholder(s));
|
|
2913
|
+
return same(selectorsA) === same(selectorsB) && !(findMsVendor(selectorsA) && findMsVendor(selectorsB));
|
|
2914
|
+
}
|
|
2915
|
+
function noVendor(selector) {
|
|
2916
|
+
return !vendorPrefix.test(selector);
|
|
2917
|
+
}
|
|
2918
|
+
function checkMatch(nodeA, nodeB) {
|
|
2919
|
+
if (nodeA.type === "atrule" && nodeB.type === "atrule") return nodeA.params === nodeB.params && nodeA.name?.toLowerCase() === nodeB.name?.toLowerCase();
|
|
2920
|
+
return nodeA.type === nodeB.type;
|
|
2921
|
+
}
|
|
2922
|
+
function sameParent(nodeA, nodeB) {
|
|
2923
|
+
if (!nodeA.parent) return !nodeB.parent;
|
|
2924
|
+
if (!nodeB.parent) return false;
|
|
2925
|
+
if (!checkMatch(nodeA.parent, nodeB.parent)) return false;
|
|
2926
|
+
return sameParent(nodeA.parent, nodeB.parent);
|
|
2927
|
+
}
|
|
2928
|
+
function declarationIsEqual(a, b) {
|
|
2929
|
+
return a.important === b.important && a.prop === b.prop && a.value === b.value;
|
|
2930
|
+
}
|
|
2931
|
+
function indexOfDeclaration(array, decl) {
|
|
2932
|
+
return array.findIndex((d) => declarationIsEqual(d, decl));
|
|
2933
|
+
}
|
|
2934
|
+
function intersect(a, b, not = false) {
|
|
2935
|
+
return a.filter((c) => {
|
|
2936
|
+
const index = indexOfDeclaration(b, c) !== -1;
|
|
2937
|
+
return not ? !index : index;
|
|
2938
|
+
});
|
|
2939
|
+
}
|
|
2940
|
+
function sameDeclarationsAndOrder(a, b) {
|
|
2941
|
+
if (a.length !== b.length) return false;
|
|
2942
|
+
return a.every((d, index) => declarationIsEqual(d, b[index]));
|
|
2943
|
+
}
|
|
2944
|
+
function isRuleOrAtRule(node) {
|
|
2945
|
+
return node.type === "rule" || node.type === "atrule";
|
|
2946
|
+
}
|
|
2947
|
+
function isDeclaration(node) {
|
|
2948
|
+
return node.type === "decl";
|
|
2949
|
+
}
|
|
2950
|
+
function getDecls(rule) {
|
|
2951
|
+
return rule.nodes.filter(isDeclaration);
|
|
2952
|
+
}
|
|
2953
|
+
const joinSelectors = (...rules) => rules.map((s) => s.selector).join(",");
|
|
2954
|
+
function ruleLength(...rules) {
|
|
2955
|
+
return rules.map((r) => r.nodes.length ? String(r) : "").join("").length;
|
|
2956
|
+
}
|
|
2957
|
+
function splitProp(prop) {
|
|
2958
|
+
const parts = prop.split("-");
|
|
2959
|
+
if (prop[0] !== "-") return {
|
|
2960
|
+
prefix: "",
|
|
2961
|
+
base: parts[0],
|
|
2962
|
+
rest: parts.slice(1)
|
|
2963
|
+
};
|
|
2964
|
+
if (prop[1] === "-") return {
|
|
2965
|
+
prefix: null,
|
|
2966
|
+
base: null,
|
|
2967
|
+
rest: [prop]
|
|
2968
|
+
};
|
|
2969
|
+
return {
|
|
2970
|
+
prefix: parts[1],
|
|
2971
|
+
base: parts[2],
|
|
2972
|
+
rest: parts.slice(3)
|
|
2973
|
+
};
|
|
2974
|
+
}
|
|
2975
|
+
function isConflictingProp(propA, propB) {
|
|
2976
|
+
if (propA === propB) return true;
|
|
2977
|
+
const a = splitProp(propA);
|
|
2978
|
+
const b = splitProp(propB);
|
|
2979
|
+
if (!a.base && !b.base) return true;
|
|
2980
|
+
if (a.base !== b.base && a.base !== "place" && b.base !== "place") return false;
|
|
2981
|
+
if (a.rest.length !== b.rest.length) return true;
|
|
2982
|
+
if (a.base === "border") {
|
|
2983
|
+
const allRestProps = new Set([...a.rest, ...b.rest]);
|
|
2984
|
+
if (allRestProps.has("image") || allRestProps.has("width") || allRestProps.has("color") || allRestProps.has("style")) return true;
|
|
2985
|
+
}
|
|
2986
|
+
return a.rest.every((s, index) => b.rest[index] === s);
|
|
2987
|
+
}
|
|
2988
|
+
function mergeParents(first, second) {
|
|
2989
|
+
if (!first.parent || !second.parent) return false;
|
|
2990
|
+
if (first.parent === second.parent) return false;
|
|
2991
|
+
second.remove();
|
|
2992
|
+
first.parent.append(second);
|
|
2993
|
+
return true;
|
|
2994
|
+
}
|
|
2995
|
+
function canMerge(ruleA, ruleB) {
|
|
2996
|
+
const a = ruleA.selectors;
|
|
2997
|
+
const b = ruleB.selectors;
|
|
2998
|
+
const selectors = a.concat(b);
|
|
2999
|
+
const parent = sameParent(ruleA, ruleB);
|
|
3000
|
+
if (parent && ruleA.parent && ruleA.parent.type === "atrule" && ruleA.parent.name?.includes("keyframes")) return false;
|
|
3001
|
+
if (ruleA.some(isRuleOrAtRule) || ruleB.some(isRuleOrAtRule)) return false;
|
|
3002
|
+
return parent && (selectors.every(noVendor) || sameVendor(a, b));
|
|
3003
|
+
}
|
|
3004
|
+
function partialMerge(first, second) {
|
|
3005
|
+
let intersection = intersect(getDecls(first), getDecls(second));
|
|
3006
|
+
if (intersection.length === 0) return second;
|
|
3007
|
+
let nextRule = second.next();
|
|
3008
|
+
if (!nextRule) nextRule = (second.parent?.next())?.nodes?.[0];
|
|
3009
|
+
if (nextRule && nextRule.type === "rule" && canMerge(second, nextRule)) {
|
|
3010
|
+
const nextIntersection = intersect(getDecls(second), getDecls(nextRule));
|
|
3011
|
+
if (nextIntersection.length > intersection.length) {
|
|
3012
|
+
mergeParents(second, nextRule);
|
|
3013
|
+
first = second;
|
|
3014
|
+
second = nextRule;
|
|
3015
|
+
intersection = nextIntersection;
|
|
3016
|
+
}
|
|
3017
|
+
}
|
|
3018
|
+
const firstDecls = getDecls(first);
|
|
3019
|
+
intersection = intersection.filter((decl, intersectIndex) => {
|
|
3020
|
+
const indexOfDecl = indexOfDeclaration(firstDecls, decl);
|
|
3021
|
+
const nextConflictInFirst = firstDecls.slice(indexOfDecl + 1).filter((d) => isConflictingProp(d.prop, decl.prop));
|
|
3022
|
+
if (nextConflictInFirst.length === 0) return true;
|
|
3023
|
+
const nextConflictInIntersection = intersection.slice(intersectIndex + 1).filter((d) => isConflictingProp(d.prop, decl.prop));
|
|
3024
|
+
if (nextConflictInFirst.length !== nextConflictInIntersection.length) return false;
|
|
3025
|
+
return nextConflictInFirst.every((d, index) => declarationIsEqual(d, nextConflictInIntersection[index]));
|
|
3026
|
+
});
|
|
3027
|
+
const secondDecls = getDecls(second);
|
|
3028
|
+
intersection = intersection.filter((decl) => {
|
|
3029
|
+
const nextConflictIndex = secondDecls.findIndex((d) => isConflictingProp(d.prop, decl.prop));
|
|
3030
|
+
if (nextConflictIndex === -1) return false;
|
|
3031
|
+
if (!declarationIsEqual(secondDecls[nextConflictIndex], decl)) return false;
|
|
3032
|
+
if (decl.prop.toLowerCase() !== "direction" && decl.prop.toLowerCase() !== "unicode-bidi" && secondDecls.some((d) => d.prop.toLowerCase() === "all")) return false;
|
|
3033
|
+
secondDecls.splice(nextConflictIndex, 1);
|
|
3034
|
+
return true;
|
|
3035
|
+
});
|
|
3036
|
+
if (intersection.length === 0) return second;
|
|
3037
|
+
const receivingBlock = second.clone();
|
|
3038
|
+
receivingBlock.selector = joinSelectors(first, second);
|
|
3039
|
+
receivingBlock.nodes = [];
|
|
3040
|
+
second.parent.insertBefore(second, receivingBlock);
|
|
3041
|
+
const firstClone = first.clone();
|
|
3042
|
+
const secondClone = second.clone();
|
|
3043
|
+
function moveDecl(callback) {
|
|
3044
|
+
return (decl) => {
|
|
3045
|
+
if (indexOfDeclaration(intersection, decl) !== -1) callback(decl);
|
|
3046
|
+
};
|
|
3047
|
+
}
|
|
3048
|
+
firstClone.walkDecls(moveDecl((decl) => {
|
|
3049
|
+
decl.remove();
|
|
3050
|
+
receivingBlock.append(decl);
|
|
3051
|
+
}));
|
|
3052
|
+
secondClone.walkDecls(moveDecl((decl) => decl.remove()));
|
|
3053
|
+
if (ruleLength(firstClone, receivingBlock, secondClone) < ruleLength(first, second)) {
|
|
3054
|
+
first.replaceWith(firstClone);
|
|
3055
|
+
second.replaceWith(secondClone);
|
|
3056
|
+
[
|
|
3057
|
+
firstClone,
|
|
3058
|
+
receivingBlock,
|
|
3059
|
+
secondClone
|
|
3060
|
+
].forEach((r) => {
|
|
3061
|
+
if (r.nodes.length === 0) r.remove();
|
|
3062
|
+
});
|
|
3063
|
+
if (!secondClone.parent) return receivingBlock;
|
|
3064
|
+
return secondClone;
|
|
3065
|
+
} else {
|
|
3066
|
+
receivingBlock.remove();
|
|
3067
|
+
return second;
|
|
3068
|
+
}
|
|
3069
|
+
}
|
|
3070
|
+
function selectorMerger() {
|
|
3071
|
+
let cache = null;
|
|
3072
|
+
return function(rule) {
|
|
3073
|
+
if (!cache || !canMerge(rule, cache)) {
|
|
3074
|
+
cache = rule;
|
|
3075
|
+
return;
|
|
3076
|
+
}
|
|
3077
|
+
if (cache === rule) {
|
|
3078
|
+
cache = rule;
|
|
3079
|
+
return;
|
|
3080
|
+
}
|
|
3081
|
+
mergeParents(cache, rule);
|
|
3082
|
+
if (sameDeclarationsAndOrder(getDecls(rule), getDecls(cache))) {
|
|
3083
|
+
rule.selector = joinSelectors(cache, rule);
|
|
3084
|
+
cache.remove();
|
|
3085
|
+
cache = rule;
|
|
3086
|
+
return;
|
|
3087
|
+
}
|
|
3088
|
+
if (cache.selector === rule.selector) {
|
|
3089
|
+
const cached = getDecls(cache);
|
|
3090
|
+
rule.walk((node) => {
|
|
3091
|
+
if (node.type === "decl" && indexOfDeclaration(cached, node) !== -1) {
|
|
3092
|
+
node.remove();
|
|
3093
|
+
return;
|
|
3094
|
+
}
|
|
3095
|
+
cache.append(node);
|
|
3096
|
+
});
|
|
3097
|
+
rule.remove();
|
|
3098
|
+
return;
|
|
3099
|
+
}
|
|
3100
|
+
cache = partialMerge(cache, rule);
|
|
3101
|
+
};
|
|
3102
|
+
}
|
|
3103
|
+
function mergeRules() {
|
|
3104
|
+
return {
|
|
3105
|
+
postcssPlugin: "postcss-merge-rules",
|
|
3106
|
+
OnceExit(css) {
|
|
3107
|
+
css.walkRules(selectorMerger());
|
|
3108
|
+
}
|
|
3109
|
+
};
|
|
3110
|
+
}
|
|
3111
|
+
mergeRules.postcss = true;
|
|
3112
|
+
//#endregion
|
|
3113
|
+
//#region src/plugins/prettify.ts
|
|
3114
|
+
function prettifyNode(node, indent = 0) {
|
|
3115
|
+
node.each && node.each((child, i) => {
|
|
3116
|
+
if (!child.raws.before || !child.raws.before.trim() || child.raws.before.includes("\n")) child.raws.before = `\n${node.type !== "rule" && i > 0 ? "\n" : ""}${" ".repeat(indent)}`;
|
|
3117
|
+
prettifyNode(child, indent + 1);
|
|
3118
|
+
});
|
|
3119
|
+
}
|
|
3120
|
+
function prettify() {
|
|
3121
|
+
return (root) => {
|
|
3122
|
+
prettifyNode(root);
|
|
3123
|
+
if (root.first) root.first.raws.before = "";
|
|
3124
|
+
};
|
|
3125
|
+
}
|
|
3126
|
+
prettify.postcssPlugin = "bamboo-prettify";
|
|
3127
|
+
//#endregion
|
|
3128
|
+
//#region src/plugins/optimize-postcss.ts
|
|
3129
|
+
function optimizePostCss(code, options = {}) {
|
|
3130
|
+
const { minify = false } = options;
|
|
3131
|
+
const plugins = [
|
|
3132
|
+
(0, postcss_nested.default)(),
|
|
3133
|
+
(0, postcss_discard_duplicates.default)(),
|
|
3134
|
+
mergeRules(),
|
|
3135
|
+
(0, postcss_discard_empty.default)()
|
|
3136
|
+
];
|
|
3137
|
+
if (minify) plugins.push((0, postcss_normalize_whitespace.default)(), (0, postcss_minify_selectors.default)());
|
|
3138
|
+
else plugins.push(prettify());
|
|
3139
|
+
const { css } = (0, postcss.default)(plugins).process(code);
|
|
3140
|
+
return css;
|
|
3141
|
+
}
|
|
3142
|
+
//#endregion
|
|
3143
|
+
//#region src/optimize.ts
|
|
3144
|
+
function optimizeCss(code, options = {}) {
|
|
3145
|
+
const { hooks } = options;
|
|
3146
|
+
const css = typeof code === "string" ? code : code.toString();
|
|
3147
|
+
if (hooks?.["css:optimize"]) {
|
|
3148
|
+
const result = hooks["css:optimize"]({
|
|
3149
|
+
css,
|
|
3150
|
+
minify: options.minify,
|
|
3151
|
+
browserslist: options.browserslist
|
|
3152
|
+
});
|
|
3153
|
+
if (result !== void 0) return result;
|
|
3154
|
+
}
|
|
3155
|
+
return optimizePostCss(code, options);
|
|
3156
|
+
}
|
|
3157
|
+
function expandNestedCss(code) {
|
|
3158
|
+
const { css } = (0, postcss.default)([(0, postcss_nested.default)(), prettify()]).process(code);
|
|
3159
|
+
return css;
|
|
3160
|
+
}
|
|
3161
|
+
//#endregion
|
|
3162
|
+
//#region src/plugins/sort-mq.ts
|
|
3163
|
+
const atRuleName = ts_pattern.P.union("media", "container");
|
|
3164
|
+
function sortMediaQueries() {
|
|
3165
|
+
const inner = (root) => {
|
|
3166
|
+
root.nodes?.sort((a, b) => {
|
|
3167
|
+
return (0, ts_pattern.match)({
|
|
3168
|
+
a,
|
|
3169
|
+
b
|
|
3170
|
+
}).with({
|
|
3171
|
+
a: {
|
|
3172
|
+
type: "atrule",
|
|
3173
|
+
name: atRuleName
|
|
3174
|
+
},
|
|
3175
|
+
b: {
|
|
3176
|
+
type: "atrule",
|
|
3177
|
+
name: atRuleName
|
|
3178
|
+
}
|
|
3179
|
+
}, ({ a, b }) => {
|
|
3180
|
+
return sortAtRules(a.params, b.params);
|
|
3181
|
+
}).with({
|
|
3182
|
+
a: {
|
|
3183
|
+
type: "atrule",
|
|
3184
|
+
name: atRuleName
|
|
3185
|
+
},
|
|
3186
|
+
b: ts_pattern.P.any
|
|
3187
|
+
}, () => {
|
|
3188
|
+
return 1;
|
|
3189
|
+
}).with({
|
|
3190
|
+
a: ts_pattern.P.any,
|
|
3191
|
+
b: {
|
|
3192
|
+
type: "atrule",
|
|
3193
|
+
name: atRuleName
|
|
3194
|
+
}
|
|
3195
|
+
}, () => {
|
|
3196
|
+
return -1;
|
|
3197
|
+
}).otherwise(() => {
|
|
3198
|
+
return 0;
|
|
3199
|
+
});
|
|
3200
|
+
});
|
|
3201
|
+
root.nodes?.forEach((node) => {
|
|
3202
|
+
if ("nodes" in node) inner(node);
|
|
3203
|
+
});
|
|
3204
|
+
};
|
|
3205
|
+
return inner;
|
|
3206
|
+
}
|
|
3207
|
+
sortMediaQueries.postcssPlugin = "bamboo-sort-mq";
|
|
3208
|
+
//#endregion
|
|
3209
|
+
//#region src/stylesheet.ts
|
|
3210
|
+
var Stylesheet = class {
|
|
3211
|
+
context;
|
|
3212
|
+
constructor(context) {
|
|
3213
|
+
this.context = context;
|
|
3214
|
+
}
|
|
3215
|
+
get layers() {
|
|
3216
|
+
return this.context.layers;
|
|
3217
|
+
}
|
|
3218
|
+
getLayer(layer) {
|
|
3219
|
+
return this.context.layers[layer];
|
|
3220
|
+
}
|
|
3221
|
+
process(options) {
|
|
3222
|
+
const layer = this.getLayer(options.layer);
|
|
3223
|
+
if (!layer) return;
|
|
3224
|
+
const { styles } = options;
|
|
3225
|
+
if (typeof styles !== "object") return;
|
|
3226
|
+
try {
|
|
3227
|
+
layer.append(stringify(styles));
|
|
3228
|
+
} catch (error) {
|
|
3229
|
+
if (error instanceof postcss.CssSyntaxError) _bamboocss_logger.logger.error("sheet:process", error.showSourceCode(true));
|
|
3230
|
+
else _bamboocss_logger.logger.caughtError("sheet:process", "Failed to process styles", error);
|
|
3231
|
+
}
|
|
3232
|
+
}
|
|
3233
|
+
serialize = (styles) => {
|
|
3234
|
+
return serializeStyles(this.context, styles);
|
|
3235
|
+
};
|
|
3236
|
+
processResetCss = (styles) => {
|
|
3237
|
+
let css = stringify(this.serialize(styles));
|
|
3238
|
+
if (this.context.hooks["cssgen:done"]) css = this.context.hooks["cssgen:done"]({
|
|
3239
|
+
artifact: "reset",
|
|
3240
|
+
content: css
|
|
3241
|
+
}) ?? css;
|
|
3242
|
+
this.context.layers.reset.append(css);
|
|
3243
|
+
};
|
|
3244
|
+
processGlobalCss = (styles) => {
|
|
3245
|
+
let css = stringify(this.serialize(styles));
|
|
3246
|
+
css += this.context.globalVars.toString();
|
|
3247
|
+
css += this.context.globalFontface.toString();
|
|
3248
|
+
css += this.context.globalPositionTry.toString();
|
|
3249
|
+
if (this.context.hooks["cssgen:done"]) css = this.context.hooks["cssgen:done"]({
|
|
3250
|
+
artifact: "global",
|
|
3251
|
+
content: css
|
|
3252
|
+
}) ?? css;
|
|
3253
|
+
this.context.layers.base.append(css);
|
|
3254
|
+
};
|
|
3255
|
+
processCss = (styles, layer) => {
|
|
3256
|
+
if (!styles) return;
|
|
3257
|
+
this.process({
|
|
3258
|
+
styles,
|
|
3259
|
+
layer
|
|
3260
|
+
});
|
|
3261
|
+
};
|
|
3262
|
+
processDecoder = (decoder) => {
|
|
3263
|
+
sortStyleRules([...decoder.atomic]).forEach((css) => {
|
|
3264
|
+
this.processCss(css.result, css.layer ?? "utilities");
|
|
3265
|
+
});
|
|
3266
|
+
decoder.grouped.forEach((grouped) => {
|
|
3267
|
+
this.processCss(grouped.result, "utilities");
|
|
3268
|
+
});
|
|
3269
|
+
decoder.recipes.forEach((recipeSet) => {
|
|
3270
|
+
recipeSet.forEach((recipe) => {
|
|
3271
|
+
this.processCss(recipe.result, recipe.entry.slot ? "recipes_slots" : "recipes");
|
|
3272
|
+
});
|
|
3273
|
+
});
|
|
3274
|
+
decoder.recipes_base.forEach((recipeSet) => {
|
|
3275
|
+
recipeSet.forEach((recipe) => {
|
|
3276
|
+
this.processCss(recipe.result, recipe.slot ? "recipes_slots_base" : "recipes_base");
|
|
3277
|
+
});
|
|
3278
|
+
});
|
|
3279
|
+
};
|
|
3280
|
+
/**
|
|
3281
|
+
* Process only the styles for a specific recipe from the decoder
|
|
3282
|
+
*/
|
|
3283
|
+
processDecoderForRecipe = (decoder, recipeName) => {
|
|
3284
|
+
const recipeSet = decoder.recipes.get(recipeName);
|
|
3285
|
+
if (recipeSet) recipeSet.forEach((recipe) => {
|
|
3286
|
+
this.processCss(recipe.result, recipe.entry.slot ? "recipes_slots" : "recipes");
|
|
3287
|
+
});
|
|
3288
|
+
decoder.recipes_base.forEach((baseSet, recipeKey) => {
|
|
3289
|
+
const [baseRecipeName] = recipeKey.split("__");
|
|
3290
|
+
if (baseRecipeName === recipeName) baseSet.forEach((recipe) => {
|
|
3291
|
+
this.processCss(recipe.result, recipe.slot ? "recipes_slots_base" : "recipes_base");
|
|
3292
|
+
});
|
|
3293
|
+
});
|
|
3294
|
+
};
|
|
3295
|
+
getLayerCss = (...layers) => {
|
|
3296
|
+
const breakpoints = this.context.conditions.breakpoints;
|
|
3297
|
+
return optimizeCss(layers.map((layer) => {
|
|
3298
|
+
const root = this.context.layers.getLayerRoot(layer);
|
|
3299
|
+
breakpoints.expandScreenAtRule(root);
|
|
3300
|
+
return root.toString();
|
|
3301
|
+
}).join("\n"), {
|
|
3302
|
+
minify: false,
|
|
3303
|
+
browserslist: this.context.browserslist,
|
|
3304
|
+
hooks: this.context.hooks
|
|
3305
|
+
});
|
|
3306
|
+
};
|
|
3307
|
+
toCss = ({ minify } = {}) => {
|
|
3308
|
+
try {
|
|
3309
|
+
const breakpoints = this.context.conditions.breakpoints;
|
|
3310
|
+
const root = this.context.layers.insert();
|
|
3311
|
+
breakpoints.expandScreenAtRule(root);
|
|
3312
|
+
const plugins = [sortMediaQueries()];
|
|
3313
|
+
if (this.context.polyfill) plugins.push((0, _csstools_postcss_cascade_layers.default)());
|
|
3314
|
+
return optimizeCss((0, postcss.default)(plugins).process(root).toString(), {
|
|
3315
|
+
minify,
|
|
3316
|
+
browserslist: this.context.browserslist,
|
|
3317
|
+
hooks: this.context.hooks
|
|
3318
|
+
});
|
|
3319
|
+
} catch (error) {
|
|
3320
|
+
if (error instanceof postcss.CssSyntaxError) _bamboocss_logger.logger.error("sheet:toCss", error.showSourceCode(true));
|
|
3321
|
+
throw error;
|
|
3322
|
+
}
|
|
3323
|
+
};
|
|
3324
|
+
};
|
|
3325
|
+
//#endregion
|
|
3326
|
+
//#region src/color-mix.ts
|
|
3327
|
+
const colorMix = (value, token) => {
|
|
3328
|
+
if (!value || typeof value !== "string") return {
|
|
3329
|
+
invalid: true,
|
|
3330
|
+
value
|
|
3331
|
+
};
|
|
3332
|
+
const [rawColor, rawOpacity] = value.split("/");
|
|
3333
|
+
if (!rawColor || !rawOpacity) return {
|
|
3334
|
+
invalid: true,
|
|
3335
|
+
value: rawColor
|
|
3336
|
+
};
|
|
3337
|
+
const colorToken = token(`colors.${rawColor}`);
|
|
3338
|
+
const opacityToken = token.raw(`opacity.${rawOpacity}`)?.value;
|
|
3339
|
+
if (!opacityToken && isNaN(Number(rawOpacity))) return {
|
|
3340
|
+
invalid: true,
|
|
3341
|
+
value: rawColor
|
|
3342
|
+
};
|
|
3343
|
+
const percent = opacityToken ? Number(opacityToken) * 100 + "%" : `${rawOpacity}%`;
|
|
3344
|
+
const color = colorToken ?? rawColor;
|
|
3345
|
+
return {
|
|
3346
|
+
invalid: false,
|
|
3347
|
+
color,
|
|
3348
|
+
value: `color-mix(in srgb, ${color} ${percent}, transparent)`
|
|
3349
|
+
};
|
|
3350
|
+
};
|
|
3351
|
+
//#endregion
|
|
3352
|
+
//#region src/utility.ts
|
|
3353
|
+
var Utility = class {
|
|
3354
|
+
options;
|
|
3355
|
+
/**
|
|
3356
|
+
* The token map or dictionary of tokens
|
|
3357
|
+
*/
|
|
3358
|
+
tokens;
|
|
3359
|
+
/**
|
|
3360
|
+
* [cache] The map of property names to their resolved class names
|
|
3361
|
+
*/
|
|
3362
|
+
classNames = /* @__PURE__ */ new Map();
|
|
3363
|
+
/**
|
|
3364
|
+
* [cache] The map of the property to their resolved styless
|
|
3365
|
+
*/
|
|
3366
|
+
styles = /* @__PURE__ */ new Map();
|
|
3367
|
+
/**
|
|
3368
|
+
* Map of shorthand properties to their longhand properties
|
|
3369
|
+
*/
|
|
3370
|
+
shorthands = /* @__PURE__ */ new Map();
|
|
3371
|
+
/**
|
|
3372
|
+
* The map of possible values for each property
|
|
3373
|
+
*/
|
|
3374
|
+
types = /* @__PURE__ */ new Map();
|
|
3375
|
+
/**
|
|
3376
|
+
* The map of the property keys
|
|
3377
|
+
*/
|
|
3378
|
+
propertyTypeKeys = /* @__PURE__ */ new Map();
|
|
3379
|
+
/**
|
|
3380
|
+
* The utility config
|
|
3381
|
+
*/
|
|
3382
|
+
config = {};
|
|
3383
|
+
/**
|
|
3384
|
+
* The map of property names to their transform functions
|
|
3385
|
+
*/
|
|
3386
|
+
transforms = /* @__PURE__ */ new Map();
|
|
3387
|
+
/**
|
|
3388
|
+
* The map of property names to their config
|
|
3389
|
+
*/
|
|
3390
|
+
configs = /* @__PURE__ */ new Map();
|
|
3391
|
+
/**
|
|
3392
|
+
* The map of deprecated properties
|
|
3393
|
+
*/
|
|
3394
|
+
deprecated = /* @__PURE__ */ new Set();
|
|
3395
|
+
separator = "_";
|
|
3396
|
+
prefix = "";
|
|
3397
|
+
strictTokens = false;
|
|
3398
|
+
constructor(options) {
|
|
3399
|
+
this.options = options;
|
|
3400
|
+
const { tokens, config = {}, separator, prefix, shorthands, strictTokens } = options;
|
|
3401
|
+
this.tokens = tokens;
|
|
3402
|
+
this.config = this.normalizeConfig(config);
|
|
3403
|
+
if (separator) this.separator = separator;
|
|
3404
|
+
if (prefix) this.prefix = prefix;
|
|
3405
|
+
if (strictTokens) this.strictTokens = strictTokens;
|
|
3406
|
+
if (shorthands) this.assignShorthands();
|
|
3407
|
+
this.assignColorPaletteProperty();
|
|
3408
|
+
this.assignProperties();
|
|
3409
|
+
this.assignPropertyTypes();
|
|
3410
|
+
}
|
|
3411
|
+
defaultHashFn = _bamboocss_shared.toHash;
|
|
3412
|
+
toHash = (path, hashFn) => hashFn(path.join(":"));
|
|
3413
|
+
normalizeConfig(config) {
|
|
3414
|
+
return Object.fromEntries(Object.entries(config).map(([property, propertyConfig]) => {
|
|
3415
|
+
return [property, this.normalize(propertyConfig)];
|
|
3416
|
+
}));
|
|
3417
|
+
}
|
|
3418
|
+
assignDeprecated = (property, config) => {
|
|
3419
|
+
if (!config.deprecated) return;
|
|
3420
|
+
this.deprecated.add(property);
|
|
3421
|
+
if ((0, _bamboocss_shared.isString)(config.shorthand)) this.deprecated.add(config.shorthand);
|
|
3422
|
+
if (Array.isArray(config.shorthand)) config.shorthand.forEach((shorthand) => this.deprecated.add(shorthand));
|
|
3423
|
+
};
|
|
3424
|
+
register = (property, config) => {
|
|
3425
|
+
this.config[property] = this.normalize(config);
|
|
3426
|
+
this.assignProperty(property, config);
|
|
3427
|
+
this.assignPropertyType(property, config);
|
|
3428
|
+
};
|
|
3429
|
+
assignShorthands = () => {
|
|
3430
|
+
for (const [property, config] of Object.entries(this.config)) {
|
|
3431
|
+
const { shorthand } = config ?? {};
|
|
3432
|
+
if (!shorthand) continue;
|
|
3433
|
+
(Array.isArray(shorthand) ? shorthand : [shorthand]).forEach((shorthandName) => {
|
|
3434
|
+
this.shorthands.set(shorthandName, property);
|
|
3435
|
+
});
|
|
3436
|
+
}
|
|
3437
|
+
};
|
|
3438
|
+
assignColorPaletteProperty = () => {
|
|
3439
|
+
if (!this.tokens.view.colorPalettes.size) return;
|
|
3440
|
+
const values = (0, _bamboocss_shared.mapToJson)(this.tokens.view.colorPalettes);
|
|
3441
|
+
this.config.colorPalette = {
|
|
3442
|
+
values: Object.keys(values),
|
|
3443
|
+
transform(value) {
|
|
3444
|
+
return values[value];
|
|
3445
|
+
}
|
|
3446
|
+
};
|
|
3447
|
+
};
|
|
3448
|
+
resolveShorthand = (prop) => {
|
|
3449
|
+
return this.shorthands.get(prop) ?? prop;
|
|
3450
|
+
};
|
|
3451
|
+
get hasShorthand() {
|
|
3452
|
+
return this.shorthands.size > 0;
|
|
3453
|
+
}
|
|
3454
|
+
get isEmpty() {
|
|
3455
|
+
return Object.keys(this.config).length === 0;
|
|
3456
|
+
}
|
|
3457
|
+
entries = () => {
|
|
3458
|
+
return Object.entries(this.config).filter(([, value]) => !!value?.className).map(([key, value]) => [key, value.className]);
|
|
3459
|
+
};
|
|
3460
|
+
getPropKey = (prop, value) => {
|
|
3461
|
+
return `(${prop} = ${value})`;
|
|
3462
|
+
};
|
|
3463
|
+
hash = (prop, value) => {
|
|
3464
|
+
return `${prop}${this.separator}${value}`;
|
|
3465
|
+
};
|
|
3466
|
+
/**
|
|
3467
|
+
* Get all the possible values for the defined property
|
|
3468
|
+
*/
|
|
3469
|
+
getPropertyValues = (config, resolveFn) => {
|
|
3470
|
+
const { values } = config;
|
|
3471
|
+
const fn = (key) => {
|
|
3472
|
+
const categoryValues = this.getTokenCategoryValues(key);
|
|
3473
|
+
if (!categoryValues) return;
|
|
3474
|
+
const prop = resolveFn?.(key);
|
|
3475
|
+
if (!prop) return;
|
|
3476
|
+
return { [prop]: categoryValues };
|
|
3477
|
+
};
|
|
3478
|
+
if ((0, _bamboocss_shared.isString)(values)) return fn?.(values) ?? this.tokens.view.getCategoryValues(values) ?? {};
|
|
3479
|
+
if (Array.isArray(values)) return values.reduce((result, value) => {
|
|
3480
|
+
result[value] = value;
|
|
3481
|
+
return result;
|
|
3482
|
+
}, {});
|
|
3483
|
+
if ((0, _bamboocss_shared.isFunction)(values)) return values(resolveFn ? fn : this.getTokenCategoryValues.bind(this));
|
|
3484
|
+
return values;
|
|
3485
|
+
};
|
|
3486
|
+
getPropertyRawValue(config, value) {
|
|
3487
|
+
const { values } = config;
|
|
3488
|
+
if (!values) return value;
|
|
3489
|
+
if ((0, _bamboocss_shared.isString)(values)) return this.tokens.view.valuesByCategory.get(values)?.get(String(value)) || value;
|
|
3490
|
+
if (Array.isArray(values)) return value;
|
|
3491
|
+
if ((0, _bamboocss_shared.isFunction)(values)) return values(this.getTokenCategoryValues.bind(this))[value] || value;
|
|
3492
|
+
if (values.type) return value;
|
|
3493
|
+
return values[value] || value;
|
|
3494
|
+
}
|
|
3495
|
+
getToken = (path) => {
|
|
3496
|
+
return this.tokens.view.getVar(path);
|
|
3497
|
+
};
|
|
3498
|
+
getTokenCategoryValues = (category) => {
|
|
3499
|
+
return this.tokens.view.getCategoryValues(category);
|
|
3500
|
+
};
|
|
3501
|
+
/**
|
|
3502
|
+
* Normalize the property config
|
|
3503
|
+
*/
|
|
3504
|
+
normalize = (propertyConfig) => {
|
|
3505
|
+
const config = { ...propertyConfig };
|
|
3506
|
+
if (config.values === "keyframes") config.values = Object.keys(this.options.keyframes ?? {});
|
|
3507
|
+
if (config.shorthand && !config.className) config.className = Array.isArray(config.shorthand) ? config.shorthand[0] : config.shorthand;
|
|
3508
|
+
return config;
|
|
3509
|
+
};
|
|
3510
|
+
assignProperty = (property, config) => {
|
|
3511
|
+
this.setTransform(property, config?.transform);
|
|
3512
|
+
this.assignDeprecated(property, config);
|
|
3513
|
+
if (!config) return;
|
|
3514
|
+
this.configs.set(property, config);
|
|
3515
|
+
};
|
|
3516
|
+
assignProperties = () => {
|
|
3517
|
+
for (const [property, propertyConfig] of Object.entries(this.config)) {
|
|
3518
|
+
if (!propertyConfig) continue;
|
|
3519
|
+
this.assignProperty(property, propertyConfig);
|
|
3520
|
+
}
|
|
3521
|
+
};
|
|
3522
|
+
assignPropertiesValues = () => {
|
|
3523
|
+
for (const [property, propertyConfig] of Object.entries(this.config)) {
|
|
3524
|
+
if (!propertyConfig) continue;
|
|
3525
|
+
this.assignPropertyValues(property, propertyConfig);
|
|
3526
|
+
}
|
|
3527
|
+
return this;
|
|
3528
|
+
};
|
|
3529
|
+
assignPropertyValues = (property, config) => {
|
|
3530
|
+
const values = this.getPropertyValues(config);
|
|
3531
|
+
if (!values) return;
|
|
3532
|
+
for (const [alias, raw] of Object.entries(values)) {
|
|
3533
|
+
const propKey = this.getPropKey(property, alias);
|
|
3534
|
+
this.setStyles(property, raw, alias, propKey);
|
|
3535
|
+
this.getOrCreateClassName(property, alias);
|
|
3536
|
+
}
|
|
3537
|
+
};
|
|
3538
|
+
getPropertyKeys = (prop) => {
|
|
3539
|
+
const propConfig = this.config[prop];
|
|
3540
|
+
if (!propConfig) return [];
|
|
3541
|
+
const values = this.getPropertyValues(propConfig);
|
|
3542
|
+
if (!values) return [];
|
|
3543
|
+
return Object.keys(values);
|
|
3544
|
+
};
|
|
3545
|
+
getPropertyTypeKeys = (property) => {
|
|
3546
|
+
const keys = this.propertyTypeKeys.get(property);
|
|
3547
|
+
return keys ? Array.from(keys) : [];
|
|
3548
|
+
};
|
|
3549
|
+
assignPropertyType = (property, config) => {
|
|
3550
|
+
if (!config) return;
|
|
3551
|
+
const values = this.getPropertyValues(config, (key) => `type:Tokens["${key}"]`);
|
|
3552
|
+
if (typeof values === "object" && values.type) {
|
|
3553
|
+
this.types.set(property, new Set([`type:${values.type}`]));
|
|
3554
|
+
return;
|
|
3555
|
+
}
|
|
3556
|
+
if (values) {
|
|
3557
|
+
const keys = new Set(Object.keys(values));
|
|
3558
|
+
this.types.set(property, keys);
|
|
3559
|
+
this.propertyTypeKeys.set(property, keys);
|
|
3560
|
+
}
|
|
3561
|
+
const set = this.types.get(property) ?? /* @__PURE__ */ new Set();
|
|
3562
|
+
if (!this.strictTokens && config.property) this.types.set(property, set.add(`CssProperties["${config.property}"]`));
|
|
3563
|
+
};
|
|
3564
|
+
assignPropertyTypes = () => {
|
|
3565
|
+
for (const [property, propertyConfig] of Object.entries(this.config)) {
|
|
3566
|
+
if (!propertyConfig) continue;
|
|
3567
|
+
this.assignPropertyType(property, propertyConfig);
|
|
3568
|
+
}
|
|
3569
|
+
};
|
|
3570
|
+
addPropertyType = (property, type) => {
|
|
3571
|
+
const set = this.types.get(property) ?? /* @__PURE__ */ new Set();
|
|
3572
|
+
this.types.set(property, new Set([...set, ...type]));
|
|
3573
|
+
};
|
|
3574
|
+
/**
|
|
3575
|
+
* Returns the Typescript type for the define properties
|
|
3576
|
+
*/
|
|
3577
|
+
getTypes = () => {
|
|
3578
|
+
const map = /* @__PURE__ */ new Map();
|
|
3579
|
+
for (const [prop, tokens] of this.types.entries()) {
|
|
3580
|
+
if (tokens.size === 0) continue;
|
|
3581
|
+
const typeValues = Array.from(tokens).map((key) => {
|
|
3582
|
+
if (key.startsWith("CssProperties")) return key;
|
|
3583
|
+
if (key.startsWith("type:")) return key.replace("type:", "");
|
|
3584
|
+
return JSON.stringify(key);
|
|
3585
|
+
});
|
|
3586
|
+
map.set(prop, typeValues);
|
|
3587
|
+
}
|
|
3588
|
+
return map;
|
|
3589
|
+
};
|
|
3590
|
+
defaultTransform = (0, _bamboocss_shared.memo)((value, prop) => {
|
|
3591
|
+
if (prop.startsWith("--")) {
|
|
3592
|
+
const tokenValue = this.tokens.view.getVar(value);
|
|
3593
|
+
value = typeof tokenValue === "string" ? tokenValue : value;
|
|
3594
|
+
}
|
|
3595
|
+
return { [prop]: value };
|
|
3596
|
+
});
|
|
3597
|
+
setTransform = (property, transform) => {
|
|
3598
|
+
const defaultTransform = (value) => this.defaultTransform(value, property);
|
|
3599
|
+
const transformFn = transform ?? defaultTransform;
|
|
3600
|
+
this.transforms.set(property, transformFn);
|
|
3601
|
+
return this;
|
|
3602
|
+
};
|
|
3603
|
+
getTokenFn = () => {
|
|
3604
|
+
return Object.assign(this.getToken.bind(this), { raw: (path) => this.tokens.getByName(path) });
|
|
3605
|
+
};
|
|
3606
|
+
resolveColorMix = (value) => {
|
|
3607
|
+
return colorMix(value, this.getTokenFn());
|
|
3608
|
+
};
|
|
3609
|
+
getTransformArgs = (raw) => {
|
|
3610
|
+
return {
|
|
3611
|
+
token: this.getTokenFn(),
|
|
3612
|
+
raw,
|
|
3613
|
+
utils: { colorMix: this.resolveColorMix.bind(this) }
|
|
3614
|
+
};
|
|
3615
|
+
};
|
|
3616
|
+
setStyles = (property, raw, alias, propKey) => {
|
|
3617
|
+
propKey = propKey ?? this.getPropKey(property, raw);
|
|
3618
|
+
const defaultTransform = (value) => this.defaultTransform(value, property);
|
|
3619
|
+
const styles = (this.transforms.get(property) ?? defaultTransform)(raw, this.getTransformArgs(alias));
|
|
3620
|
+
this.styles.set(propKey, styles ?? {});
|
|
3621
|
+
return this;
|
|
3622
|
+
};
|
|
3623
|
+
formatClassName = (className) => {
|
|
3624
|
+
return [this.prefix, className].filter(Boolean).join("-");
|
|
3625
|
+
};
|
|
3626
|
+
/**
|
|
3627
|
+
* Returns the resolved className for a given property and value
|
|
3628
|
+
*/
|
|
3629
|
+
getClassName = (property, raw) => {
|
|
3630
|
+
const config = this.configs.get(property);
|
|
3631
|
+
if (!config || !config.className) return this.hash((0, _bamboocss_shared.hypenateProperty)(property), raw);
|
|
3632
|
+
return this.hash(config.className, raw);
|
|
3633
|
+
};
|
|
3634
|
+
getOrCreateClassName = (property, raw) => {
|
|
3635
|
+
const propKey = this.getPropKey(property, raw);
|
|
3636
|
+
let className = this.classNames.get(propKey);
|
|
3637
|
+
if (!className) {
|
|
3638
|
+
className = this.getClassName(property, raw);
|
|
3639
|
+
this.classNames.set(propKey, className);
|
|
3640
|
+
}
|
|
3641
|
+
return className;
|
|
3642
|
+
};
|
|
3643
|
+
/**
|
|
3644
|
+
* Whether a given property exists in the config
|
|
3645
|
+
*/
|
|
3646
|
+
has = (prop) => {
|
|
3647
|
+
return this.configs.has(prop);
|
|
3648
|
+
};
|
|
3649
|
+
/**
|
|
3650
|
+
* Get or create the resolved styles for a given property and value
|
|
3651
|
+
*/
|
|
3652
|
+
getOrCreateStyle = (prop, value) => {
|
|
3653
|
+
const propKey = this.getPropKey(prop, value);
|
|
3654
|
+
const styles = this.styles.get(propKey);
|
|
3655
|
+
if (styles) return styles;
|
|
3656
|
+
const config = this.configs.get(prop);
|
|
3657
|
+
const raw = config ? this.getPropertyRawValue(config, value) : value;
|
|
3658
|
+
this.setStyles(prop, raw, value, propKey);
|
|
3659
|
+
return this.styles.get(propKey);
|
|
3660
|
+
};
|
|
3661
|
+
/**
|
|
3662
|
+
* Returns the resolved className and styles for a given property and value
|
|
3663
|
+
*/
|
|
3664
|
+
transform = (prop, value) => {
|
|
3665
|
+
if (value == null) return {
|
|
3666
|
+
className: "",
|
|
3667
|
+
styles: {}
|
|
3668
|
+
};
|
|
3669
|
+
const key = this.resolveShorthand(prop);
|
|
3670
|
+
let styleValue = (0, _bamboocss_shared.getArbitraryValue)(value);
|
|
3671
|
+
if ((0, _bamboocss_shared.isString)(styleValue)) styleValue = this.tokens.expandReferenceInValue(styleValue);
|
|
3672
|
+
return (0, _bamboocss_shared.compact)({
|
|
3673
|
+
layer: this.configs.get(key)?.layer,
|
|
3674
|
+
className: this.getOrCreateClassName(key, (0, _bamboocss_shared.withoutSpace)(value)),
|
|
3675
|
+
styles: this.getOrCreateStyle(key, styleValue)
|
|
3676
|
+
});
|
|
3677
|
+
};
|
|
3678
|
+
/**
|
|
3679
|
+
* All keys including shorthand keys
|
|
3680
|
+
*/
|
|
3681
|
+
keys = () => {
|
|
3682
|
+
const shorthands = Array.from(this.shorthands.keys());
|
|
3683
|
+
const properties = Object.keys(this.config);
|
|
3684
|
+
return [...shorthands, ...properties];
|
|
3685
|
+
};
|
|
3686
|
+
/**
|
|
3687
|
+
* Returns a map of the property keys and their shorthands
|
|
3688
|
+
*/
|
|
3689
|
+
getPropShorthandsMap = () => {
|
|
3690
|
+
const shorthandsByProp = /* @__PURE__ */ new Map();
|
|
3691
|
+
this.shorthands.forEach((prop, shorthand) => {
|
|
3692
|
+
const list = shorthandsByProp.get(prop) ?? [];
|
|
3693
|
+
list.push(shorthand);
|
|
3694
|
+
shorthandsByProp.set(prop, list);
|
|
3695
|
+
});
|
|
3696
|
+
return shorthandsByProp;
|
|
3697
|
+
};
|
|
3698
|
+
/**
|
|
3699
|
+
* Returns the shorthands for a given property
|
|
3700
|
+
*/
|
|
3701
|
+
getPropShorthands = (prop) => {
|
|
3702
|
+
return this.getPropShorthandsMap().get(prop) ?? [];
|
|
3703
|
+
};
|
|
3704
|
+
/**
|
|
3705
|
+
* Whether a given property is deprecated
|
|
3706
|
+
*/
|
|
3707
|
+
isDeprecated = (prop) => {
|
|
3708
|
+
return this.deprecated.has(prop);
|
|
3709
|
+
};
|
|
3710
|
+
/**
|
|
3711
|
+
* Returns the token type for a given property
|
|
3712
|
+
*/
|
|
3713
|
+
getTokenType = (prop) => {
|
|
3714
|
+
const set = this.types.get(prop);
|
|
3715
|
+
if (!set) return;
|
|
3716
|
+
for (const type of set) {
|
|
3717
|
+
const match = type.match(TOKEN_TYPE_PATTERN);
|
|
3718
|
+
if (match) return match[1];
|
|
3719
|
+
}
|
|
3720
|
+
};
|
|
3721
|
+
};
|
|
3722
|
+
const TOKEN_TYPE_PATTERN = /type:Tokens\["([^"]+)"\]/;
|
|
3723
|
+
//#endregion
|
|
3724
|
+
//#region src/context.ts
|
|
3725
|
+
const defaults = (config) => ({
|
|
3726
|
+
cssVarRoot: ":where(:root, :host)",
|
|
3727
|
+
jsxFactory: "styled",
|
|
3728
|
+
jsxStyleProps: "all",
|
|
3729
|
+
outExtension: "mjs",
|
|
3730
|
+
shorthands: true,
|
|
3731
|
+
syntax: "object-literal",
|
|
3732
|
+
...config,
|
|
3733
|
+
layers: {
|
|
3734
|
+
reset: "reset",
|
|
3735
|
+
base: "base",
|
|
3736
|
+
tokens: "tokens",
|
|
3737
|
+
recipes: "recipes",
|
|
3738
|
+
utilities: "utilities",
|
|
3739
|
+
...config.layers
|
|
3740
|
+
}
|
|
3741
|
+
});
|
|
3742
|
+
var Context = class {
|
|
3743
|
+
conf;
|
|
3744
|
+
studio;
|
|
3745
|
+
tokens;
|
|
3746
|
+
utility;
|
|
3747
|
+
recipes;
|
|
3748
|
+
conditions;
|
|
3749
|
+
patterns;
|
|
3750
|
+
staticCss;
|
|
3751
|
+
jsx;
|
|
3752
|
+
imports;
|
|
3753
|
+
paths;
|
|
3754
|
+
file;
|
|
3755
|
+
globalVars;
|
|
3756
|
+
globalFontface;
|
|
3757
|
+
globalPositionTry;
|
|
3758
|
+
encoder;
|
|
3759
|
+
decoder;
|
|
3760
|
+
hooksApi;
|
|
3761
|
+
properties;
|
|
3762
|
+
isValidProperty;
|
|
3763
|
+
messages;
|
|
3764
|
+
parserOptions;
|
|
3765
|
+
constructor(conf) {
|
|
3766
|
+
this.conf = conf;
|
|
3767
|
+
const config = defaults(conf.config);
|
|
3768
|
+
const theme = config.theme ?? {};
|
|
3769
|
+
conf.config = config;
|
|
3770
|
+
this.tokens = this.createTokenDictionary(theme, config.themes);
|
|
3771
|
+
this.hooks["tokens:created"]?.({ configure: (opts) => {
|
|
3772
|
+
if (opts.formatTokenName) this.tokens.formatTokenName = opts.formatTokenName;
|
|
3773
|
+
if (opts.formatCssVar) this.tokens.formatCssVar = opts.formatCssVar;
|
|
3774
|
+
} });
|
|
3775
|
+
this.tokens.init();
|
|
3776
|
+
this.utility = this.createUtility(config);
|
|
3777
|
+
this.hooks["utility:created"]?.({ configure: (opts) => {
|
|
3778
|
+
if (opts.toHash) this.utility.toHash = opts.toHash;
|
|
3779
|
+
} });
|
|
3780
|
+
this.conditions = this.createConditions(config);
|
|
3781
|
+
this.patterns = new Patterns({
|
|
3782
|
+
config,
|
|
3783
|
+
tokens: this.tokens,
|
|
3784
|
+
utility: this.utility,
|
|
3785
|
+
helpers: _bamboocss_shared.patternFns
|
|
3786
|
+
});
|
|
3787
|
+
this.studio = {
|
|
3788
|
+
outdir: `${config.outdir}-studio`,
|
|
3789
|
+
...conf.config.studio
|
|
3790
|
+
};
|
|
3791
|
+
this.setupProperties();
|
|
3792
|
+
this.recipes = this.createRecipes(theme);
|
|
3793
|
+
this.encoder = new StyleEncoder({
|
|
3794
|
+
utility: this.utility,
|
|
3795
|
+
recipes: this.recipes,
|
|
3796
|
+
conditions: this.conditions,
|
|
3797
|
+
patterns: this.patterns,
|
|
3798
|
+
isTemplateLiteralSyntax: this.isTemplateLiteralSyntax,
|
|
3799
|
+
isValidProperty: this.isValidProperty
|
|
3800
|
+
});
|
|
3801
|
+
this.decoder = new StyleDecoder({
|
|
3802
|
+
conditions: this.conditions,
|
|
3803
|
+
utility: this.utility,
|
|
3804
|
+
recipes: this.recipes,
|
|
3805
|
+
hash: this.hash
|
|
3806
|
+
});
|
|
3807
|
+
this.setupCompositions(theme);
|
|
3808
|
+
this.registerAnimationName(theme);
|
|
3809
|
+
this.registerFontFamily(config.globalFontface);
|
|
3810
|
+
this.recipes.save(this.baseSheetContext);
|
|
3811
|
+
this.staticCss = new StaticCss({
|
|
3812
|
+
config,
|
|
3813
|
+
utility: this.utility,
|
|
3814
|
+
patterns: this.patterns,
|
|
3815
|
+
recipes: this.recipes,
|
|
3816
|
+
createSheet: this.createSheet,
|
|
3817
|
+
encoder: this.encoder,
|
|
3818
|
+
decoder: this.decoder
|
|
3819
|
+
});
|
|
3820
|
+
this.jsx = new JsxEngine({
|
|
3821
|
+
patterns: this.patterns,
|
|
3822
|
+
recipes: this.recipes,
|
|
3823
|
+
config
|
|
3824
|
+
});
|
|
3825
|
+
this.imports = new ImportMap({
|
|
3826
|
+
jsx: this.jsx,
|
|
3827
|
+
conf: this.conf,
|
|
3828
|
+
config: this.config,
|
|
3829
|
+
patterns: this.patterns,
|
|
3830
|
+
recipes: this.recipes,
|
|
3831
|
+
isValidProperty: this.isValidProperty
|
|
3832
|
+
});
|
|
3833
|
+
this.paths = new PathEngine({ config: this.config });
|
|
3834
|
+
this.file = new FileEngine({ config: this.config });
|
|
3835
|
+
this.globalVars = new GlobalVars({
|
|
3836
|
+
globalVars: this.config.globalVars,
|
|
3837
|
+
cssVarRoot: this.config.cssVarRoot
|
|
3838
|
+
});
|
|
3839
|
+
this.globalFontface = new GlobalFontface({ globalFontface: this.config.globalFontface });
|
|
3840
|
+
this.globalPositionTry = new GlobalPositionTry({ globalPositionTry: this.config.globalPositionTry });
|
|
3841
|
+
this.messages = getMessages({
|
|
3842
|
+
jsx: this.jsx,
|
|
3843
|
+
config: this.config,
|
|
3844
|
+
tokens: this.tokens,
|
|
3845
|
+
recipes: this.recipes,
|
|
3846
|
+
patterns: this.patterns,
|
|
3847
|
+
isTemplateLiteralSyntax: this.isTemplateLiteralSyntax
|
|
3848
|
+
});
|
|
3849
|
+
this.parserOptions = {
|
|
3850
|
+
hash: this.hash,
|
|
3851
|
+
compilerOptions: this.conf.tsconfig?.compilerOptions ?? {},
|
|
3852
|
+
recipes: this.recipes,
|
|
3853
|
+
patterns: this.patterns,
|
|
3854
|
+
jsx: this.jsx,
|
|
3855
|
+
config: this.config,
|
|
3856
|
+
tokens: this.tokens,
|
|
3857
|
+
conditions: this.conditions,
|
|
3858
|
+
utility: this.utility,
|
|
3859
|
+
encoder: this.encoder,
|
|
3860
|
+
tsOptions: this.conf.tsOptions,
|
|
3861
|
+
join: (...paths) => paths.join("/"),
|
|
3862
|
+
imports: this.imports
|
|
3863
|
+
};
|
|
3864
|
+
this.hooksApi = new HooksApi(this);
|
|
3865
|
+
this.hooks["context:created"]?.({
|
|
3866
|
+
ctx: this.hooksApi,
|
|
3867
|
+
logger: _bamboocss_logger.logger
|
|
3868
|
+
});
|
|
3869
|
+
}
|
|
3870
|
+
get config() {
|
|
3871
|
+
return this.conf.config;
|
|
3872
|
+
}
|
|
3873
|
+
get hooks() {
|
|
3874
|
+
return this.conf.hooks ?? {};
|
|
3875
|
+
}
|
|
3876
|
+
get isTemplateLiteralSyntax() {
|
|
3877
|
+
return this.config.syntax === "template-literal";
|
|
3878
|
+
}
|
|
3879
|
+
get hash() {
|
|
3880
|
+
return {
|
|
3881
|
+
tokens: (0, _bamboocss_shared.isBoolean)(this.config.hash) ? this.config.hash : this.config.hash?.cssVar,
|
|
3882
|
+
className: (0, _bamboocss_shared.isBoolean)(this.config.hash) ? this.config.hash : this.config.hash?.className
|
|
3883
|
+
};
|
|
3884
|
+
}
|
|
3885
|
+
get prefix() {
|
|
3886
|
+
return {
|
|
3887
|
+
tokens: (0, _bamboocss_shared.isString)(this.config.prefix) ? this.config.prefix : this.config.prefix?.cssVar,
|
|
3888
|
+
className: (0, _bamboocss_shared.isString)(this.config.prefix) ? this.config.prefix : this.config.prefix?.className
|
|
3889
|
+
};
|
|
3890
|
+
}
|
|
3891
|
+
createTokenDictionary = (theme, themeVariants) => {
|
|
3892
|
+
return new _bamboocss_token_dictionary.TokenDictionary({
|
|
3893
|
+
breakpoints: theme.breakpoints,
|
|
3894
|
+
tokens: theme.tokens,
|
|
3895
|
+
semanticTokens: theme.semanticTokens,
|
|
3896
|
+
themes: themeVariants,
|
|
3897
|
+
prefix: this.prefix.tokens,
|
|
3898
|
+
hash: this.hash.tokens,
|
|
3899
|
+
colorPalette: theme.colorPalette
|
|
3900
|
+
});
|
|
3901
|
+
};
|
|
3902
|
+
createUtility = (config) => {
|
|
3903
|
+
return new Utility({
|
|
3904
|
+
prefix: this.prefix.className,
|
|
3905
|
+
tokens: this.tokens,
|
|
3906
|
+
config: this.isTemplateLiteralSyntax ? {} : Object.assign({}, config.utilities),
|
|
3907
|
+
separator: config.separator,
|
|
3908
|
+
shorthands: config.shorthands,
|
|
3909
|
+
strictTokens: config.strictTokens,
|
|
3910
|
+
keyframes: config.theme?.keyframes
|
|
3911
|
+
});
|
|
3912
|
+
};
|
|
3913
|
+
createConditions = (config) => {
|
|
3914
|
+
return new Conditions({
|
|
3915
|
+
conditions: config.conditions,
|
|
3916
|
+
containerNames: config.theme?.containerNames,
|
|
3917
|
+
containerSizes: config.theme?.containerSizes,
|
|
3918
|
+
breakpoints: config.theme?.breakpoints,
|
|
3919
|
+
themes: config.themes
|
|
3920
|
+
});
|
|
3921
|
+
};
|
|
3922
|
+
createLayers = (layers) => {
|
|
3923
|
+
return new Layers(layers);
|
|
3924
|
+
};
|
|
3925
|
+
setupCompositions = (theme) => {
|
|
3926
|
+
const { textStyles, layerStyles, animationStyles } = theme;
|
|
3927
|
+
const compositions = (0, _bamboocss_shared.compact)({
|
|
3928
|
+
textStyle: textStyles,
|
|
3929
|
+
layerStyle: layerStyles,
|
|
3930
|
+
animationStyle: animationStyles
|
|
3931
|
+
});
|
|
3932
|
+
const stylesheetCtx = {
|
|
3933
|
+
...this.baseSheetContext,
|
|
3934
|
+
layers: this.createLayers(this.config.layers)
|
|
3935
|
+
};
|
|
3936
|
+
for (const [key, values] of Object.entries(compositions)) {
|
|
3937
|
+
this.properties.add(key);
|
|
3938
|
+
const flatValues = (0, _bamboocss_shared.flatten)(values ?? {});
|
|
3939
|
+
const config = {
|
|
3940
|
+
layer: "compositions",
|
|
3941
|
+
className: key,
|
|
3942
|
+
values: Object.keys(flatValues),
|
|
3943
|
+
transform: (value) => {
|
|
3944
|
+
return transformStyles(stylesheetCtx, flatValues[value], key + "." + value);
|
|
3945
|
+
}
|
|
3946
|
+
};
|
|
3947
|
+
this.utility.register(key, config);
|
|
3948
|
+
}
|
|
3949
|
+
};
|
|
3950
|
+
registerAnimationName = (theme) => {
|
|
3951
|
+
this.utility.addPropertyType("animationName", Object.keys(theme.keyframes ?? {}));
|
|
3952
|
+
};
|
|
3953
|
+
registerFontFamily = (fontFaces) => {
|
|
3954
|
+
this.utility.addPropertyType("fontFamily", Object.keys(fontFaces ?? {}));
|
|
3955
|
+
};
|
|
3956
|
+
setupProperties = () => {
|
|
3957
|
+
this.properties = new Set([
|
|
3958
|
+
"css",
|
|
3959
|
+
...this.utility.keys(),
|
|
3960
|
+
...this.conditions.keys()
|
|
3961
|
+
]);
|
|
3962
|
+
this.isValidProperty = (0, _bamboocss_shared.memo)((key) => this.properties.has(key) || (0, _bamboocss_is_valid_prop.isCssProperty)(key));
|
|
3963
|
+
};
|
|
3964
|
+
get baseSheetContext() {
|
|
3965
|
+
return {
|
|
3966
|
+
conditions: this.conditions,
|
|
3967
|
+
utility: this.utility,
|
|
3968
|
+
hash: this.hash.className,
|
|
3969
|
+
encoder: this.encoder,
|
|
3970
|
+
decoder: this.decoder,
|
|
3971
|
+
hooks: this.hooks,
|
|
3972
|
+
isValidProperty: this.isValidProperty,
|
|
3973
|
+
browserslist: this.config.browserslist,
|
|
3974
|
+
polyfill: this.config.polyfill,
|
|
3975
|
+
cssVarRoot: this.config.cssVarRoot,
|
|
3976
|
+
helpers: _bamboocss_shared.patternFns,
|
|
3977
|
+
globalVars: this.globalVars,
|
|
3978
|
+
globalFontface: this.globalFontface,
|
|
3979
|
+
globalPositionTry: this.globalPositionTry
|
|
3980
|
+
};
|
|
3981
|
+
}
|
|
3982
|
+
createSheet = () => {
|
|
3983
|
+
return new Stylesheet({
|
|
3984
|
+
...this.baseSheetContext,
|
|
3985
|
+
layers: this.createLayers(this.config.layers)
|
|
3986
|
+
});
|
|
3987
|
+
};
|
|
3988
|
+
createRecipes = (theme) => {
|
|
3989
|
+
return new Recipes(Object.assign({}, theme.recipes ?? {}, theme.slotRecipes ?? {}));
|
|
3990
|
+
};
|
|
3991
|
+
isValidLayerParams = (params) => {
|
|
3992
|
+
const names = new Set(params.split(",").map((name) => name.trim()));
|
|
3993
|
+
return names.size >= 5 && Object.values(this.config.layers).every((name) => names.has(name));
|
|
3994
|
+
};
|
|
3995
|
+
};
|
|
3996
|
+
//#endregion
|
|
3997
|
+
//#region src/selector.ts
|
|
3998
|
+
const parentNestingRegex = /\s&/g;
|
|
3999
|
+
function extractParentSelectors(selector) {
|
|
4000
|
+
const result = /* @__PURE__ */ new Set();
|
|
4001
|
+
(0, postcss_selector_parser.default)((selectors) => {
|
|
4002
|
+
selectors.each((selector) => {
|
|
4003
|
+
(0, ts_pattern.match)(parseCondition(selector.toString())).with({ type: "parent-nesting" }, () => {
|
|
4004
|
+
result.add(selector.toString().replace(parentNestingRegex, "").trim());
|
|
4005
|
+
}).otherwise(() => {});
|
|
4006
|
+
});
|
|
4007
|
+
}).processSync(selector);
|
|
4008
|
+
const finalized = Array.from(result).join(", ").trim();
|
|
4009
|
+
return result.size > 1 ? `:where(${finalized})` : finalized;
|
|
4010
|
+
}
|
|
4011
|
+
function extractTrailingPseudos(selector) {
|
|
4012
|
+
const ast = (0, postcss_selector_parser.default)((selectors) => selectors).astSync(selector);
|
|
4013
|
+
const matrix = [];
|
|
4014
|
+
for (const [i, sel] of ast.nodes.entries()) for (const [j, child] of [...sel.nodes].reverse().entries()) {
|
|
4015
|
+
if (child.type !== "pseudo" || !child.value.startsWith("::")) break;
|
|
4016
|
+
matrix[j] = matrix[j] || [];
|
|
4017
|
+
matrix[j][i] = child;
|
|
4018
|
+
}
|
|
4019
|
+
const trailingPseudos = postcss_selector_parser.default.selector({ value: "" });
|
|
4020
|
+
for (const pseudos of matrix) {
|
|
4021
|
+
if (!pseudos) continue;
|
|
4022
|
+
if (new Set(pseudos.map((p) => p.value)).size > 1) break;
|
|
4023
|
+
pseudos.forEach((pseudo) => pseudo.remove());
|
|
4024
|
+
trailingPseudos.prepend(pseudos[0]);
|
|
4025
|
+
}
|
|
4026
|
+
if (trailingPseudos.nodes.length) return [trailingPseudos.toString(), ast.toString()];
|
|
4027
|
+
return [null, selector];
|
|
4028
|
+
}
|
|
4029
|
+
//#endregion
|
|
4030
|
+
exports.Breakpoints = Breakpoints;
|
|
4031
|
+
exports.Conditions = Conditions;
|
|
4032
|
+
exports.Context = Context;
|
|
4033
|
+
exports.FileMatcher = FileMatcher;
|
|
4034
|
+
exports.ImportMap = ImportMap;
|
|
4035
|
+
exports.JsxEngine = JsxEngine;
|
|
4036
|
+
exports.Layers = Layers;
|
|
4037
|
+
exports.Patterns = Patterns;
|
|
4038
|
+
exports.Recipes = Recipes;
|
|
4039
|
+
exports.RuleProcessor = RuleProcessor;
|
|
4040
|
+
exports.StaticCss = StaticCss;
|
|
4041
|
+
exports.StyleDecoder = StyleDecoder;
|
|
4042
|
+
exports.StyleEncoder = StyleEncoder;
|
|
4043
|
+
exports.Stylesheet = Stylesheet;
|
|
4044
|
+
exports.Utility = Utility;
|
|
4045
|
+
exports.expandNestedCss = expandNestedCss;
|
|
4046
|
+
exports.extractParentSelectors = extractParentSelectors;
|
|
4047
|
+
exports.extractTrailingPseudos = extractTrailingPseudos;
|
|
4048
|
+
Object.defineProperty(exports, "messages", {
|
|
4049
|
+
enumerable: true,
|
|
4050
|
+
get: function() {
|
|
4051
|
+
return messages_exports;
|
|
4052
|
+
}
|
|
4053
|
+
});
|
|
4054
|
+
exports.optimizeCss = optimizeCss;
|
|
4055
|
+
exports.stringify = stringify;
|