@barocss/browser 0.0.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -27,16 +27,158 @@ function property(name, initialValue, syntax, source) {
27
27
  }
28
28
  return atRule("property", name, nodes, source);
29
29
  }
30
+ class AstCache {
31
+ constructor() {
32
+ this.cache = /* @__PURE__ */ new Map();
33
+ this.maxSize = 1e3;
34
+ }
35
+ // Prevent memory leaks
36
+ set(key, ast) {
37
+ if (this.cache.size >= this.maxSize) {
38
+ const firstKey = this.cache.keys().next().value;
39
+ if (firstKey) {
40
+ this.cache.delete(firstKey);
41
+ }
42
+ }
43
+ this.cache.set(key, ast);
44
+ }
45
+ get(key) {
46
+ return this.cache.get(key);
47
+ }
48
+ has(key) {
49
+ return this.cache.has(key);
50
+ }
51
+ clear() {
52
+ this.cache.clear();
53
+ }
54
+ getStats() {
55
+ return {
56
+ size: this.cache.size,
57
+ maxSize: this.maxSize,
58
+ hitRate: this.cache.size / this.maxSize
59
+ };
60
+ }
61
+ }
62
+ const astCache = new AstCache();
63
+ class ParseResultCache {
64
+ constructor() {
65
+ this.cache = /* @__PURE__ */ new Map();
66
+ this.maxSize = 2e3;
67
+ }
68
+ // Prevent memory leaks
69
+ set(key, result) {
70
+ if (this.cache.size >= this.maxSize) {
71
+ const firstKey = this.cache.keys().next().value;
72
+ if (firstKey) {
73
+ this.cache.delete(firstKey);
74
+ }
75
+ }
76
+ this.cache.set(key, result);
77
+ }
78
+ get(key) {
79
+ return this.cache.get(key);
80
+ }
81
+ has(key) {
82
+ return this.cache.has(key);
83
+ }
84
+ clear() {
85
+ this.cache.clear();
86
+ }
87
+ getStats() {
88
+ return {
89
+ size: this.cache.size,
90
+ maxSize: this.maxSize,
91
+ hitRate: this.cache.size / this.maxSize
92
+ };
93
+ }
94
+ }
95
+ const parseResultCache = new ParseResultCache();
96
+ class UtilityCache {
97
+ constructor() {
98
+ this.cache = /* @__PURE__ */ new Map();
99
+ this.maxSize = 1e3;
100
+ }
101
+ // Prevent memory leaks
102
+ set(key, value) {
103
+ if (this.cache.size >= this.maxSize) {
104
+ const firstKey = this.cache.keys().next().value;
105
+ if (firstKey) {
106
+ this.cache.delete(firstKey);
107
+ }
108
+ }
109
+ this.cache.set(key, value);
110
+ }
111
+ get(key) {
112
+ return this.cache.get(key);
113
+ }
114
+ has(key) {
115
+ return this.cache.has(key);
116
+ }
117
+ clear() {
118
+ this.cache.clear();
119
+ }
120
+ getStats() {
121
+ return {
122
+ size: this.cache.size,
123
+ maxSize: this.maxSize,
124
+ hitRate: this.cache.size / this.maxSize
125
+ };
126
+ }
127
+ }
128
+ const utilityCache = new UtilityCache();
129
+ let resetContextCaches;
130
+ function setContextCacheReset(reset) {
131
+ resetContextCaches = reset;
132
+ }
133
+ function clearAllCaches() {
134
+ astCache.clear();
135
+ parseResultCache.clear();
136
+ utilityCache.clear();
137
+ resetContextCaches?.();
138
+ console.log("[clearAllCaches] All caches cleared");
139
+ }
140
+ const states = /* @__PURE__ */ new WeakMap();
141
+ let cacheGeneration = 0;
142
+ setContextCacheReset(() => {
143
+ cacheGeneration += 1;
144
+ });
145
+ function initializeContextState(ctx, utilities, modifiers) {
146
+ states.set(ctx, {
147
+ utilities: [...utilities],
148
+ modifiers: [...modifiers],
149
+ astCache: new AstCache(),
150
+ parseResultCache: new ParseResultCache(),
151
+ utilityCache: new UtilityCache(),
152
+ failures: /* @__PURE__ */ new Set(),
153
+ cacheGeneration
154
+ });
155
+ }
156
+ function getContextState(ctx) {
157
+ const state = states.get(ctx);
158
+ if (state && state.cacheGeneration !== cacheGeneration) {
159
+ clearContextCaches(ctx);
160
+ state.cacheGeneration = cacheGeneration;
161
+ }
162
+ return state;
163
+ }
164
+ function clearContextCaches(ctx) {
165
+ const state = states.get(ctx);
166
+ if (!state) return;
167
+ state.astCache.clear();
168
+ state.parseResultCache.clear();
169
+ state.utilityCache.clear();
170
+ state.failures.clear();
171
+ }
30
172
  const utilityRegistry = [];
31
- function registerUtility(util) {
173
+ function registerUtility(util, ctx) {
32
174
  utilityRegistry.push(util);
33
175
  }
34
- function getUtility() {
35
- return utilityRegistry;
176
+ function getUtility(ctx) {
177
+ return ctx && getContextState(ctx)?.utilities || utilityRegistry;
36
178
  }
37
179
  const modifierRegistry = [];
38
- function staticModifier(name, selectors, options = {}) {
39
- modifierRegistry.push({
180
+ function staticModifier(name, selectors, options = {}, ctx) {
181
+ registerModifier({
40
182
  match: (mod) => mod === name,
41
183
  modifySelector: ({ ..._rest }) => {
42
184
  return selectors.map((sel) => ({
@@ -47,11 +189,14 @@ function staticModifier(name, selectors, options = {}) {
47
189
  ...options
48
190
  });
49
191
  }
50
- function functionalModifier(match, modifySelector, wrap, options = {}) {
51
- modifierRegistry.push({ match, modifySelector, wrap, ...options });
192
+ function functionalModifier(match, modifySelector, wrap, options = {}, ctx) {
193
+ registerModifier({ match, modifySelector, wrap, ...options });
52
194
  }
53
- function getModifier() {
54
- return modifierRegistry;
195
+ function registerModifier(modifier, ctx) {
196
+ modifierRegistry.push(modifier);
197
+ }
198
+ function getModifier(ctx) {
199
+ return ctx && getContextState(ctx)?.modifiers || modifierRegistry;
55
200
  }
56
201
  const ESCAPE_REGEX = /[^A-Za-z0-9_-]/g;
57
202
  function escapeClassName(className) {
@@ -90,7 +235,7 @@ function escapeClassName(className) {
90
235
  return "\\" + c;
91
236
  });
92
237
  }
93
- function staticUtility(name, decls, opts) {
238
+ function staticUtility(name, decls, opts, ctx) {
94
239
  registerUtility({
95
240
  name,
96
241
  match: (className) => {
@@ -119,11 +264,11 @@ function staticUtility(name, decls, opts) {
119
264
  priority: opts?.priority
120
265
  });
121
266
  }
122
- function functionalUtility(opts) {
267
+ function functionalUtility(opts, ctx) {
123
268
  registerUtility({
124
269
  name: opts.name,
125
270
  match: (className) => className.startsWith(opts.name + "-"),
126
- handler: (value, ctx, token, _options) => {
271
+ handler: (value, ctx2, token, _options) => {
127
272
  let finalValue = value;
128
273
  const parsedUtility = token;
129
274
  const extra = {
@@ -139,7 +284,7 @@ function functionalUtility(opts) {
139
284
  if (opts.supportsArbitrary && parsedUtility.arbitrary) {
140
285
  const processedValue = finalValue.replace(/_/g, " ");
141
286
  if (opts.handle) {
142
- const result = opts.handle(processedValue, ctx, token, extra);
287
+ const result = opts.handle(processedValue, ctx2, token, extra);
143
288
  if (result) return result;
144
289
  }
145
290
  if (opts.prop) {
@@ -149,12 +294,12 @@ function functionalUtility(opts) {
149
294
  }
150
295
  if (opts.supportsCustomProperty && parsedUtility.customProperty) {
151
296
  if (opts.handleCustomProperty) {
152
- const result = opts.handleCustomProperty(finalValue, ctx, token, extra);
297
+ const result = opts.handleCustomProperty(finalValue, ctx2, token, extra);
153
298
  return result;
154
299
  }
155
300
  const customValue = `var(${finalValue})`;
156
301
  if (opts.handle) {
157
- const result = opts.handle(customValue, ctx, token, extra);
302
+ const result = opts.handle(customValue, ctx2, token, extra);
158
303
  if (result) return result;
159
304
  }
160
305
  if (opts.prop) {
@@ -163,12 +308,12 @@ function functionalUtility(opts) {
163
308
  return [];
164
309
  }
165
310
  let themeValue;
166
- if (opts.themeKey && ctx.theme) {
167
- themeValue = ctx.theme(opts.themeKey, finalValue);
311
+ if (opts.themeKey && ctx2.theme) {
312
+ themeValue = ctx2.theme(opts.themeKey, finalValue);
168
313
  }
169
- if (!themeValue && opts.themeKeys && ctx.theme) {
314
+ if (!themeValue && opts.themeKeys && ctx2.theme) {
170
315
  for (const key of opts.themeKeys) {
171
- themeValue = ctx.theme(key, finalValue);
316
+ themeValue = ctx2.theme(key, finalValue);
172
317
  if (themeValue !== void 0) break;
173
318
  }
174
319
  }
@@ -179,7 +324,7 @@ function functionalUtility(opts) {
179
324
  return [decl(opts.prop, finalValue)];
180
325
  }
181
326
  if (opts.handle) {
182
- const result = opts.handle(finalValue, ctx, token, extra);
327
+ const result = opts.handle(finalValue, ctx2, token, extra);
183
328
  if (result) return result;
184
329
  }
185
330
  return [];
@@ -188,16 +333,16 @@ function functionalUtility(opts) {
188
333
  finalValue = value;
189
334
  }
190
335
  if (parsedUtility.negative && opts.supportsNegative && opts.handleNegativeBareValue) {
191
- const bare = opts.handleNegativeBareValue({ value: String(finalValue).replace(/^-/, ""), ctx, token, extra });
336
+ const bare = opts.handleNegativeBareValue({ value: String(finalValue).replace(/^-/, ""), ctx: ctx2, token, extra });
192
337
  if (bare == null) return [];
193
338
  finalValue = bare;
194
339
  } else if (opts.handleBareValue) {
195
- const bare = opts.handleBareValue({ value: finalValue, ctx, token, extra });
340
+ const bare = opts.handleBareValue({ value: finalValue, ctx: ctx2, token, extra });
196
341
  if (bare == null) return [];
197
342
  finalValue = bare;
198
343
  }
199
344
  if (opts.handle) {
200
- const result = opts.handle(finalValue, ctx, token, extra);
345
+ const result = opts.handle(finalValue, ctx2, token, extra);
201
346
  if (result) return result;
202
347
  }
203
348
  if (opts.prop) {
@@ -245,117 +390,13 @@ function tokenize(className) {
245
390
  }
246
391
  return tokens;
247
392
  }
248
- class AstCache {
249
- constructor() {
250
- this.cache = /* @__PURE__ */ new Map();
251
- this.maxSize = 1e3;
252
- }
253
- // Prevent memory leaks
254
- set(key, ast) {
255
- if (this.cache.size >= this.maxSize) {
256
- const firstKey = this.cache.keys().next().value;
257
- if (firstKey) {
258
- this.cache.delete(firstKey);
259
- }
260
- }
261
- this.cache.set(key, ast);
262
- }
263
- get(key) {
264
- return this.cache.get(key);
265
- }
266
- has(key) {
267
- return this.cache.has(key);
268
- }
269
- clear() {
270
- this.cache.clear();
271
- }
272
- getStats() {
273
- return {
274
- size: this.cache.size,
275
- maxSize: this.maxSize,
276
- hitRate: this.cache.size / this.maxSize
277
- };
278
- }
279
- }
280
- const astCache = new AstCache();
281
- class ParseResultCache {
282
- constructor() {
283
- this.cache = /* @__PURE__ */ new Map();
284
- this.maxSize = 2e3;
285
- }
286
- // Prevent memory leaks
287
- set(key, result) {
288
- if (this.cache.size >= this.maxSize) {
289
- const firstKey = this.cache.keys().next().value;
290
- if (firstKey) {
291
- this.cache.delete(firstKey);
292
- }
293
- }
294
- this.cache.set(key, result);
393
+ function isUtilityPrefix(str, ctx) {
394
+ const cache = ctx && getContextState(ctx)?.utilityCache || utilityCache;
395
+ if (cache.has(str)) {
396
+ return cache.get(str);
295
397
  }
296
- get(key) {
297
- return this.cache.get(key);
298
- }
299
- has(key) {
300
- return this.cache.has(key);
301
- }
302
- clear() {
303
- this.cache.clear();
304
- }
305
- getStats() {
306
- return {
307
- size: this.cache.size,
308
- maxSize: this.maxSize,
309
- hitRate: this.cache.size / this.maxSize
310
- };
311
- }
312
- }
313
- const parseResultCache = new ParseResultCache();
314
- class UtilityCache {
315
- constructor() {
316
- this.cache = /* @__PURE__ */ new Map();
317
- this.maxSize = 1e3;
318
- }
319
- // Prevent memory leaks
320
- set(key, value) {
321
- if (this.cache.size >= this.maxSize) {
322
- const firstKey = this.cache.keys().next().value;
323
- if (firstKey) {
324
- this.cache.delete(firstKey);
325
- }
326
- }
327
- this.cache.set(key, value);
328
- }
329
- get(key) {
330
- return this.cache.get(key);
331
- }
332
- has(key) {
333
- return this.cache.has(key);
334
- }
335
- clear() {
336
- this.cache.clear();
337
- }
338
- getStats() {
339
- return {
340
- size: this.cache.size,
341
- maxSize: this.maxSize,
342
- hitRate: this.cache.size / this.maxSize
343
- };
344
- }
345
- }
346
- const utilityCache = new UtilityCache();
347
- function clearAllCaches() {
348
- astCache.clear();
349
- parseResultCache.clear();
350
- utilityCache.clear();
351
- console.log("[clearAllCaches] All caches cleared");
352
- }
353
- function isUtilityPrefix(str) {
354
- if (utilityCache.has(str)) {
355
- return utilityCache.get(str);
356
- }
357
- const utilities = getUtility();
358
- const modifiers = getModifier();
398
+ const utilities = getUtility(ctx);
399
+ const modifiers = getModifier(ctx);
359
400
  const candidateUtilities = utilities.filter((util) => {
360
401
  const prefix = util.name;
361
402
  return str.startsWith(prefix + "-") || str === prefix || str.startsWith(prefix);
@@ -367,12 +408,13 @@ function isUtilityPrefix(str) {
367
408
  });
368
409
  const isModifier = candidateModifiers.some((mod) => mod.match(str, {}));
369
410
  const result = isUtility && !isModifier;
370
- utilityCache.set(str, result);
411
+ cache.set(str, result);
371
412
  return result;
372
413
  }
373
- function parseClassName(className) {
374
- if (parseResultCache.has(className)) {
375
- return parseResultCache.get(className);
414
+ function parseClassName(className, ctx) {
415
+ const cache = ctx && getContextState(ctx)?.parseResultCache || parseResultCache;
416
+ if (cache.has(className)) {
417
+ return cache.get(className);
376
418
  }
377
419
  let important = false;
378
420
  let realClassName = className;
@@ -381,38 +423,38 @@ function parseClassName(className) {
381
423
  realClassName = className.slice(1);
382
424
  }
383
425
  const tokens = tokenize(realClassName);
384
- const result = parseTokens(tokens);
426
+ const result = parseTokens(tokens, ctx);
385
427
  if (result.utility) {
386
428
  result.utility.important = important;
387
429
  }
388
- parseResultCache.set(className, result);
430
+ cache.set(className, result);
389
431
  return result;
390
432
  }
391
- function parseTokens(tokens) {
433
+ function parseTokens(tokens, ctx) {
392
434
  const modifiers = [];
393
435
  let utility = null;
394
436
  if (tokens.length === 0) {
395
437
  return { modifiers, utility: null };
396
438
  }
397
439
  if (tokens.length === 1) {
398
- utility = parseUtility(tokens[0].value);
440
+ utility = parseUtility(tokens[0].value, ctx);
399
441
  } else if (tokens.length === 2) {
400
442
  const firstToken = tokens[0];
401
443
  const secondToken = tokens[1];
402
- const isFirstUtility = isUtilityPrefix(firstToken.value);
444
+ const isFirstUtility = isUtilityPrefix(firstToken.value, ctx);
403
445
  if (isFirstUtility) {
404
- utility = parseUtility(firstToken.value);
446
+ utility = parseUtility(firstToken.value, ctx);
405
447
  const parsed = parseModifier(secondToken.value);
406
448
  if (parsed) modifiers.push(parsed);
407
449
  } else {
408
450
  const parsed = parseModifier(firstToken.value);
409
451
  if (parsed) modifiers.push(parsed);
410
- utility = parseUtility(secondToken.value);
452
+ utility = parseUtility(secondToken.value, ctx);
411
453
  }
412
454
  } else {
413
- const isFirstUtility = isUtilityPrefix(tokens[0].value);
455
+ const isFirstUtility = isUtilityPrefix(tokens[0].value, ctx);
414
456
  if (isFirstUtility) {
415
- utility = parseUtility(tokens[0].value);
457
+ utility = parseUtility(tokens[0].value, ctx);
416
458
  for (let i = 1; i < tokens.length; i++) {
417
459
  const parsed = parseModifier(tokens[i].value);
418
460
  if (parsed) modifiers.push(parsed);
@@ -422,7 +464,7 @@ function parseTokens(tokens) {
422
464
  const parsed = parseModifier(tokens[i].value);
423
465
  if (parsed) modifiers.push(parsed);
424
466
  }
425
- utility = parseUtility(tokens[tokens.length - 1].value);
467
+ utility = parseUtility(tokens[tokens.length - 1].value, ctx);
426
468
  }
427
469
  }
428
470
  return { modifiers, utility };
@@ -442,7 +484,7 @@ function parseModifier(value) {
442
484
  function nameSort(a, b) {
443
485
  return b.name.length - a.name.length;
444
486
  }
445
- function parseUtility(value) {
487
+ function parseUtility(value, ctx) {
446
488
  let prefix = "";
447
489
  let utilityValue = "";
448
490
  let arbitrary = false;
@@ -469,8 +511,7 @@ function parseUtility(value) {
469
511
  utilityValue = utilityValue.replace(/\)$/, "");
470
512
  customProperty = true;
471
513
  } else {
472
- const utilities = getUtility();
473
- const sortedUtilities = utilities.sort(nameSort);
514
+ const sortedUtilities = [...getUtility(ctx)].sort(nameSort);
474
515
  let matchedUtility = sortedUtilities.find((p) => value === p.name);
475
516
  if (matchedUtility) {
476
517
  prefix = matchedUtility.name;
@@ -681,7 +722,7 @@ ${node.nodes.map((node2) => {
681
722
  }).join("\n");
682
723
  return result;
683
724
  }
684
- const failureCache = /* @__PURE__ */ new Map();
725
+ const failureCache = /* @__PURE__ */ new Set();
685
726
  function collectDeclPaths(nodes = [], path = []) {
686
727
  let result = [];
687
728
  for (const node of nodes) {
@@ -845,32 +886,29 @@ function extractAtRootNodes(nodes, parent, atRootNodes = []) {
845
886
  }
846
887
  }
847
888
  function parseClassToAst(fullClassName, ctx) {
848
- if (failureCache.has(fullClassName)) {
889
+ const state = getContextState(ctx);
890
+ const failures = state?.failures || failureCache;
891
+ const cache = state?.astCache || astCache;
892
+ if (failures.has(fullClassName)) {
849
893
  return [];
850
894
  }
851
- const contextHash = JSON.stringify({
852
- darkMode: ctx.config("darkMode"),
853
- darkModeSelector: ctx.config("darkModeSelector"),
854
- theme: ctx.theme
855
- });
856
- const cacheKey = `${fullClassName}:${contextHash}`;
857
- if (astCache.has(cacheKey)) {
858
- return astCache.get(cacheKey);
895
+ if (cache.has(fullClassName)) {
896
+ return cache.get(fullClassName);
859
897
  }
860
- const { modifiers, utility } = parseClassName(fullClassName);
898
+ const { modifiers, utility } = parseClassName(fullClassName, ctx);
861
899
  if (!utility) {
862
900
  console.warn(`[BAROCSS] Invalid class name format: "${fullClassName}"`);
863
- failureCache.set(fullClassName, true);
901
+ failures.add(fullClassName);
864
902
  return [];
865
903
  }
866
- const utilReg = getUtility().find((u) => {
904
+ const utilReg = getUtility(ctx).find((u) => {
867
905
  const fullClassName2 = utility.value ? `${utility.prefix}-${utility.value}` : utility.prefix;
868
906
  return u.match(fullClassName2);
869
907
  });
870
908
  if (!utilReg) {
871
909
  const utilityName = utility.value ? `${utility.prefix}-${utility.value}` : utility.prefix;
872
910
  console.warn(`[BAROCSS] Unknown utility class: "${utilityName}" in "${fullClassName}"`);
873
- failureCache.set(fullClassName, true);
911
+ failures.add(fullClassName);
874
912
  return [];
875
913
  }
876
914
  let value = utility.value;
@@ -880,10 +918,11 @@ function parseClassToAst(fullClassName, ctx) {
880
918
  const selector = "&";
881
919
  for (let i = 0; i < modifiers.length; i++) {
882
920
  const variant = modifiers[i];
883
- const plugin = getModifier().find((p) => p.match(variant.type, ctx));
921
+ const plugin = getModifier(ctx).find((p) => p.match(variant.type, ctx));
884
922
  if (!plugin) {
885
923
  console.warn(`[BAROCSS] Unknown variant: "${variant.type}" in "${fullClassName}"`);
886
- continue;
924
+ failures.add(fullClassName);
925
+ return [];
887
926
  }
888
927
  if (plugin.wrap) {
889
928
  const items = plugin.wrap(variant, ctx);
@@ -891,7 +930,6 @@ function parseClassToAst(fullClassName, ctx) {
891
930
  type: "wrap",
892
931
  items
893
932
  });
894
- continue;
895
933
  }
896
934
  if (plugin.modifySelector) {
897
935
  const result = plugin.modifySelector({
@@ -902,9 +940,10 @@ function parseClassToAst(fullClassName, ctx) {
902
940
  variantChain: modifiers,
903
941
  index: i
904
942
  });
943
+ if (plugin.wrap && (result === "&" || typeof result === "object" && !Array.isArray(result) && result.selector === "&" || Array.isArray(result) && result.length === 1 && result[0].selector === "&")) continue;
905
944
  if (typeof result === "string" && result.includes("&")) {
906
945
  wrappers.push({ type: "rule", selector: result });
907
- } else if (typeof result === "object" && result.selector) {
946
+ } else if (typeof result === "object" && !Array.isArray(result) && result.selector) {
908
947
  const wrappingType = result.wrappingType || "rule";
909
948
  wrappers.push({
910
949
  type: wrappingType,
@@ -928,10 +967,7 @@ function parseClassToAst(fullClassName, ctx) {
928
967
  for (let i = wrappers.length - 1; i >= 0; i--) {
929
968
  const wrap = wrappers[i];
930
969
  if (wrap.type === "wrap") {
931
- ast = wrap.items.map((item) => ({
932
- ...item,
933
- nodes: Array.isArray(ast) ? ast : [ast]
934
- }));
970
+ ast = wrap.items.map((item) => item.type === "rule" || item.type === "style-rule" || item.type === "at-rule" || item.type === "at-root" ? { ...item, nodes: [...item.nodes || [], ...ast] } : item);
935
971
  } else if (wrap.type === "style-rule") {
936
972
  ast = [
937
973
  {
@@ -965,18 +1001,28 @@ function parseClassToAst(fullClassName, ctx) {
965
1001
  const atRootNodes = [];
966
1002
  extractAtRootNodes(ast, void 0, atRootNodes);
967
1003
  ast = [...atRootNodes, ...ast].filter(Boolean);
968
- astCache.set(cacheKey, ast);
1004
+ cache.set(fullClassName, ast);
969
1005
  return ast;
970
1006
  }
1007
+ function clearAstCache(ctx) {
1008
+ if (ctx) {
1009
+ clearContextCaches(ctx);
1010
+ } else {
1011
+ clearAllCaches();
1012
+ failureCache.clear();
1013
+ }
1014
+ }
971
1015
  function generateCssRules(classList, ctx, opts) {
972
- const options = {
973
- minify: opts?.minify
974
- };
975
1016
  return classList.split(/\s+/).filter((cls) => {
976
1017
  if (!cls) return false;
977
1018
  return true;
978
1019
  }).map((cls) => {
979
1020
  const ast = parseClassToAst(cls, ctx);
1021
+ const parsedResult = (getContextState(ctx)?.parseResultCache || parseResultCache).get(cls);
1022
+ const options = {
1023
+ minify: opts?.minify,
1024
+ important: parsedResult?.utility?.important ?? false
1025
+ };
980
1026
  const cleanAst = optimizeAst(ast);
981
1027
  const allAtRootNodes = cleanAst.filter(
982
1028
  (node) => node.type === "at-root" && !node.source
@@ -1090,7 +1136,7 @@ class IncrementalParser {
1090
1136
  return null;
1091
1137
  }
1092
1138
  try {
1093
- const parseResult = parseClassName(className);
1139
+ const parseResult = parseClassName(className, this.ctx);
1094
1140
  if (!parseResult.utility) {
1095
1141
  return null;
1096
1142
  }
@@ -1223,7 +1269,7 @@ class IncrementalParser {
1223
1269
  processedClasses: this.processedClasses.size,
1224
1270
  pendingClasses: this.pendingClasses.size,
1225
1271
  cacheStats: {
1226
- ast: astCache.getStats(),
1272
+ ast: (getContextState(this.ctx)?.astCache || astCache).getStats(),
1227
1273
  css: {}
1228
1274
  // No CSS cache, so return empty object
1229
1275
  }
@@ -1879,18 +1925,6 @@ const defaultTheme = {
1879
1925
  animationVars,
1880
1926
  blur
1881
1927
  };
1882
- function normalizePrefix(prefix) {
1883
- let p = prefix.trim();
1884
- if (!p.startsWith("--")) p = `--${p}`;
1885
- if (!p.endsWith("-")) p = `${p}-`;
1886
- return p;
1887
- }
1888
- function setVarPrefix(prefix) {
1889
- if (typeof prefix !== "string" || prefix.trim() === "") {
1890
- return;
1891
- }
1892
- normalizePrefix(prefix);
1893
- }
1894
1928
  function escapeKey(key) {
1895
1929
  return key.replace(".", "\\.");
1896
1930
  }
@@ -2793,7 +2827,7 @@ function deepMerge(base, override) {
2793
2827
  }
2794
2828
  return result;
2795
2829
  }
2796
- let staticInProgress;
2830
+ const themeLookupsInProgress = /* @__PURE__ */ new WeakMap();
2797
2831
  function themeGetter(themeObj, ...path) {
2798
2832
  const theme = (...args) => themeGetter(themeObj, ...args);
2799
2833
  let keys = [];
@@ -2813,26 +2847,28 @@ function themeGetter(themeObj, ...path) {
2813
2847
  }
2814
2848
  }
2815
2849
  if (keys.length === 0) return void 0;
2816
- staticInProgress = staticInProgress || /* @__PURE__ */ new Set();
2817
- const pathKey = keys.join(".");
2818
- if (staticInProgress?.has(pathKey)) return void 0;
2819
- staticInProgress?.add(pathKey);
2820
- let value = themeObj[keys[0]];
2821
- if (typeof value === "function") {
2822
- value = value(theme);
2850
+ let inProgress = themeLookupsInProgress.get(themeObj);
2851
+ if (!inProgress) {
2852
+ inProgress = /* @__PURE__ */ new Set();
2853
+ themeLookupsInProgress.set(themeObj, inProgress);
2823
2854
  }
2824
- for (let i = 1; i < keys.length; i++) {
2825
- if (value == null) {
2826
- staticInProgress?.delete(pathKey);
2827
- return void 0;
2855
+ const pathKey = keys.join(".");
2856
+ if (inProgress.has(pathKey)) return void 0;
2857
+ inProgress.add(pathKey);
2858
+ try {
2859
+ let value = themeObj[keys[0]];
2860
+ if (typeof value === "function") {
2861
+ value = value(theme);
2828
2862
  }
2829
- value = value[keys[i]];
2830
- }
2831
- staticInProgress?.delete(pathKey);
2832
- if (typeof value === "function") {
2833
- return void 0;
2863
+ for (let i = 1; i < keys.length; i++) {
2864
+ if (value == null) return void 0;
2865
+ value = value[keys[i]];
2866
+ }
2867
+ if (typeof value === "function") return void 0;
2868
+ return value;
2869
+ } finally {
2870
+ inProgress.delete(pathKey);
2834
2871
  }
2835
- return value;
2836
2872
  }
2837
2873
  function configGetter(config, ...path) {
2838
2874
  let keys = [];
@@ -2880,11 +2916,7 @@ function createContext(configObj) {
2880
2916
  ],
2881
2917
  ...configObj
2882
2918
  };
2883
- setVarPrefix(configWithDefaults.cssVarPrefix || "--bcss-");
2884
2919
  const themeObj = resolveTheme(configWithDefaults);
2885
- if (configObj.clearCacheOnContextChange !== false) {
2886
- clearAllCaches();
2887
- }
2888
2920
  const ctx = {
2889
2921
  hasPreset: (category, preset) => {
2890
2922
  const result = hasPreset(themeObj, category, preset);
@@ -2918,11 +2950,13 @@ function createContext(configObj) {
2918
2950
  ...values
2919
2951
  };
2920
2952
  } else ;
2953
+ clearContextCaches(ctx);
2921
2954
  },
2922
2955
  getPreflightCSS: (level = true) => {
2923
2956
  return getPreflightCSS(level);
2924
2957
  }
2925
2958
  };
2959
+ initializeContextState(ctx, getUtility(), getModifier());
2926
2960
  return ctx;
2927
2961
  }
2928
2962
  function parseFraction(input) {
@@ -4262,7 +4296,7 @@ functionalUtility({
4262
4296
  ["--baro-ring-inset", "inset"],
4263
4297
  ["--baro-ring-offset-width", "0px"],
4264
4298
  ["--baro-ring-offset-color", "#fff"],
4265
- ["--baro-inset-ring-color", "rgb(59 130 246 / 0.5)"],
4299
+ ["--baro-inset-ring-color", "currentcolor"],
4266
4300
  [
4267
4301
  "--baro-inset-ring-shadow",
4268
4302
  `var(--baro-ring-inset) 0 0 0 calc(${px} + var(--baro-ring-offset-width)) var(--baro-inset-ring-color, currentcolor)`
@@ -4270,7 +4304,7 @@ functionalUtility({
4270
4304
  ["--baro-ring-offset-shadow", `0 0 #0000`],
4271
4305
  [
4272
4306
  "box-shadow",
4273
- "var(--baro-inset-shadow), var(--baro-inset-ring-shadow), var(--baro-ring-offset-shadow), var(--baro-ring-shadow), var(--baro-shadow)"
4307
+ "var(--baro-inset-shadow, 0 0 #0000), var(--baro-inset-ring-shadow), var(--baro-ring-offset-shadow, 0 0 #0000), var(--baro-ring-shadow, 0 0 #0000), var(--baro-shadow, 0 0 #0000)"
4274
4308
  ]
4275
4309
  ]);
4276
4310
  });
@@ -4588,6 +4622,18 @@ functionalUtility({
4588
4622
  description: "mask-size utility (static, arbitrary, custom property supported)",
4589
4623
  category: "effects"
4590
4624
  });
4625
+ functionalUtility({
4626
+ name: "mask-linear-from",
4627
+ handleBareValue: ({ value }) => /^(?:100|[1-9]?\d)%$/.test(value) ? value : null,
4628
+ handle: (value) => [
4629
+ decl("mask-image", "var(--tw-mask-linear), var(--tw-mask-radial, linear-gradient(#fff, #fff)), var(--tw-mask-conic, linear-gradient(#fff, #fff))"),
4630
+ decl("mask-composite", "intersect"),
4631
+ decl("--tw-mask-linear-stops", "var(--tw-mask-linear-position, 0deg), var(--tw-mask-linear-from-color, black) var(--tw-mask-linear-from-position, 0%), var(--tw-mask-linear-to-color, transparent) var(--tw-mask-linear-to-position, 100%)"),
4632
+ decl("--tw-mask-linear", "linear-gradient(var(--tw-mask-linear-stops))"),
4633
+ decl("--tw-mask-linear-from-position", value)
4634
+ ],
4635
+ category: "effects"
4636
+ });
4591
4637
  functionalUtility({
4592
4638
  name: "mask",
4593
4639
  supportsArbitrary: true,
@@ -7378,7 +7424,11 @@ functionalUtility({
7378
7424
  });
7379
7425
  staticUtility("forced-color-adjust-auto", [["forced-color-adjust", "auto"]], { category: "accessibility" });
7380
7426
  staticUtility("forced-color-adjust-none", [["forced-color-adjust", "none"]], { category: "accessibility" });
7381
- staticModifier("hover", ["&:hover"], { order: 50, source: "pseudo" });
7427
+ staticModifier("hover", ["&:hover"], {
7428
+ order: 50,
7429
+ source: "pseudo",
7430
+ wrap: () => [atRule("media", "(hover: hover)", [])]
7431
+ });
7382
7432
  staticModifier("focus", ["&:focus"], { order: 50, source: "pseudo" });
7383
7433
  staticModifier("active", ["&:active"], { order: 50, source: "pseudo" });
7384
7434
  staticModifier("visited", ["&:visited"], { order: 50, source: "pseudo" });
@@ -8258,6 +8308,9 @@ class StylePartitionManager {
8258
8308
  getCategoryPartition(category) {
8259
8309
  return this.categoryPartitions.get(category);
8260
8310
  }
8311
+ hasDetachedPartitions() {
8312
+ return [...this.partitions, ...this.categoryPartitions.values()].some((partition) => !partition.styleElement.isConnected);
8313
+ }
8261
8314
  /**
8262
8315
  * Escape CSS rule text
8263
8316
  * - Properly escape special characters
@@ -8404,6 +8457,7 @@ class StylePartitionManager {
8404
8457
  }
8405
8458
  });
8406
8459
  this.partitions = [];
8460
+ this.categoryPartitions.clear();
8407
8461
  this.partitionCounter = 0;
8408
8462
  this.classToPartitionMap.clear();
8409
8463
  this.classToCategoryPartitionMap.clear();
@@ -8429,10 +8483,12 @@ class ChangeDetector {
8429
8483
  */
8430
8484
  constructor(incrementalParser, BrowserRuntime2) {
8431
8485
  this.observer = null;
8432
- this.processedElements = /* @__PURE__ */ new WeakSet();
8433
8486
  this.incrementalParser = incrementalParser;
8434
8487
  this.BrowserRuntime = BrowserRuntime2;
8435
8488
  }
8489
+ setParser(parser) {
8490
+ this.incrementalParser = parser;
8491
+ }
8436
8492
  /**
8437
8493
  * Starts observing DOM changes for new CSS classes
8438
8494
  *
@@ -8472,7 +8528,7 @@ class ChangeDetector {
8472
8528
  }
8473
8529
  if (mutation.type === "childList") {
8474
8530
  mutation.addedNodes.forEach((node) => {
8475
- if (node instanceof HTMLElement) {
8531
+ if (node instanceof Element) {
8476
8532
  this.processElement(node, newClasses);
8477
8533
  node.querySelectorAll("[class]").forEach((el) => {
8478
8534
  this.processElement(el, newClasses);
@@ -8537,17 +8593,14 @@ class ChangeDetector {
8537
8593
  *
8538
8594
  * This method is called for each element discovered during DOM mutations.
8539
8595
  * It:
8540
- * - Checks if the element has already been processed
8541
8596
  * - Extracts all class names from the element's className
8542
8597
  * - Filters out already processed classes
8543
8598
  * - Adds new classes to the collection for batch processing
8544
- * - Marks the element as processed to avoid duplicates
8545
8599
  *
8546
8600
  * @param element - The HTML element to process
8547
8601
  * @param newClasses - Set to collect newly discovered class names
8548
8602
  */
8549
8603
  processElement(element, newClasses) {
8550
- if (this.processedElements.has(element)) return;
8551
8604
  if (element.className) {
8552
8605
  const classes = normalizeClassNameList(element.className);
8553
8606
  classes.forEach((cls) => {
@@ -8556,7 +8609,6 @@ class ChangeDetector {
8556
8609
  }
8557
8610
  });
8558
8611
  }
8559
- this.processedElements.add(element);
8560
8612
  }
8561
8613
  /**
8562
8614
  * Stops observing DOM changes and cleans up resources
@@ -8653,11 +8705,19 @@ class BrowserRuntime {
8653
8705
  * Public method to apply parser results, update internal caches, and inject CSS
8654
8706
  */
8655
8707
  applyParseResults(results, _opts) {
8708
+ if (this.isDestroyed) return;
8709
+ if (this.getInsertionPoint().isConnected && this.stylePartitionManager.hasDetachedPartitions()) {
8710
+ const existingResults = Array.from(this.cache.values());
8711
+ this.reset();
8712
+ results = [...existingResults, ...results];
8713
+ results.forEach((result) => this.incrementalParser.markProcessed(result.cls));
8714
+ }
8656
8715
  const cssRules = [];
8657
8716
  const rootCssRules = [];
8658
8717
  for (const result of results) {
8659
8718
  if (result.css && Array.isArray(result.cssList)) {
8660
8719
  cssRules.push(result);
8720
+ this.cache.set(result.cls, result);
8661
8721
  }
8662
8722
  if (result.rootCss && Array.isArray(result.rootCssList)) {
8663
8723
  for (const rootCss of result.rootCssList) {
@@ -8708,46 +8768,64 @@ class BrowserRuntime {
8708
8768
  * Get comprehensive cache statistics
8709
8769
  */
8710
8770
  getCacheStats() {
8771
+ const incremental = this.incrementalParser.getStats();
8711
8772
  return {
8712
8773
  runtime: {
8713
8774
  cachedClasses: this.cache.size,
8714
8775
  rootCacheSize: this.rootCache.size
8715
8776
  },
8716
- ast: astCache.getStats(),
8717
- incremental: this.incrementalParser.getStats()
8777
+ ast: incremental.cacheStats.ast,
8778
+ incremental
8718
8779
  };
8719
8780
  }
8720
8781
  /**
8721
8782
  * Clear all caches (useful for debugging or memory management)
8722
8783
  */
8723
8784
  clearCaches() {
8785
+ if (this.isDestroyed) return;
8724
8786
  this.cache.clear();
8725
8787
  this.rootCache.clear();
8726
- astCache.clear();
8788
+ clearAstCache(this.context);
8727
8789
  this.incrementalParser.clearProcessed();
8728
8790
  this.stylePartitionManager.cleanup();
8791
+ this.stylePartitionManager = new StylePartitionManager(this.getInsertionPoint(), this.options.maxRulesPerPartition, `${this.options.styleId}-partition`);
8792
+ this.injectPreflightCSS();
8793
+ this.ensureCssVars();
8729
8794
  }
8730
8795
  reset() {
8796
+ if (this.isDestroyed) return;
8731
8797
  this.cache.clear();
8732
8798
  this.rootCache.clear();
8799
+ this.incrementalParser.clearProcessed();
8733
8800
  this.stylePartitionManager.cleanup();
8801
+ this.stylePartitionManager = new StylePartitionManager(this.getInsertionPoint(), this.options.maxRulesPerPartition, `${this.options.styleId}-partition`);
8802
+ this.injectPreflightCSS();
8803
+ this.ensureCssVars();
8734
8804
  }
8735
8805
  updateConfig(newConfig) {
8806
+ if (this.isDestroyed) return;
8807
+ const existingClasses = Array.from(this.cache.keys());
8736
8808
  this.options.config = newConfig;
8737
8809
  this.context = createContext(newConfig);
8738
- const existingClasses = Array.from(this.cache.keys());
8810
+ this.incrementalParser = new IncrementalParser(this.context);
8811
+ this.changeDetector.setParser(this.incrementalParser);
8739
8812
  this.reset();
8740
8813
  if (existingClasses.length > 0) {
8741
8814
  this.addClass(existingClasses);
8742
8815
  }
8743
8816
  }
8744
8817
  removeClass(classes) {
8745
- const classList = this.normalizeClasses(classes);
8746
- for (const cls of classList) {
8747
- this.cache.delete(cls);
8748
- }
8818
+ if (this.isDestroyed) return;
8819
+ const classList = new Set(this.normalizeClasses(classes));
8820
+ const retainedResults = Array.from(this.cache.values()).filter((result) => !classList.has(result.cls));
8821
+ if (retainedResults.length === this.cache.size) return;
8822
+ this.reset();
8823
+ retainedResults.forEach((result) => this.incrementalParser.markProcessed(result.cls));
8824
+ this.applyParseResults(retainedResults);
8749
8825
  }
8750
8826
  destroy() {
8827
+ if (this.isDestroyed) return;
8828
+ this.changeDetector.disconnect();
8751
8829
  this.stylePartitionManager.cleanup();
8752
8830
  this.cache.clear();
8753
8831
  this.rootCache.clear();