@barocss/browser 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.es.js CHANGED
@@ -1,18 +1,30 @@
1
- import { parseResultCache as y, createContext as f, IncrementalParser as g, clearAstCache as P } from "@barocss/kit";
2
- class u {
3
- constructor(t, e = 50, s = "barocss-style-partition-") {
4
- this.partitions = [], this.categoryPartitions = /* @__PURE__ */ new Map(), this.partitionCounter = 0, this.maxRulesPerPartition = 50, this.classToPartitionMap = /* @__PURE__ */ new Map(), this.classToCategoryPartitionMap = /* @__PURE__ */ new Map(), this.styleIdPrefix = "barocss-style-partition-", this.insertionPoint = t, this.maxRulesPerPartition = e, this.styleIdPrefix = s, this.initializeDefaultPartition();
1
+ import { parseClassName as g, upperBound as R, ruleSortKey as y, compareKeys as b, createContext as m, IncrementalParser as p, clearAstCache as w } from "@barocss/kit";
2
+ class d {
3
+ constructor(t, e = 50, s = "barocss-style-partition-", i = (r) => g(r).utility?.category) {
4
+ this.partitions = [], this.categoryPartitions = /* @__PURE__ */ new Map(), this.partitionCounter = 0, this.maxRulesPerPartition = 50, this.classToPartitionMap = /* @__PURE__ */ new Map(), this.classToCategoryPartitionMap = /* @__PURE__ */ new Map(), this.styleIdPrefix = "barocss-style-partition-", this.insertionPoint = t, this.maxRulesPerPartition = e, this.styleIdPrefix = s, this.getCategory = i, this.initializeDefaultPartition();
5
+ }
6
+ /**
7
+ * Insert `rule` at its Tailwind variant position within `partition` (#254):
8
+ * one insertRule at a binary-searched index, no sheet rewrite.
9
+ */
10
+ insertSorted(t, e, s) {
11
+ const i = t.keys ??= [], r = R(i, s), n = t.styleElement.sheet;
12
+ n && n.cssRules.length === i.length ? (n.insertRule(this.escapeCssRule(e), r), t.styles.splice(r, 0, e)) : (t.styles.splice(r, 0, e), t.styleElement.textContent = t.styles.join(`
13
+ `) + `
14
+ `), i.splice(r, 0, s);
5
15
  }
6
16
  initializeDefaultPartition() {
7
17
  this.createNewPartition();
8
18
  }
9
- createNewCategoryPartition(t) {
10
- const e = {
19
+ createNewCategoryPartition(t, e = !1) {
20
+ const s = {
11
21
  id: this.styleIdPrefix + `-${t}`,
12
22
  styles: [],
13
23
  styleElement: document.createElement("style")
14
24
  };
15
- return e.styleElement.id = e.id, e.styleElement.setAttribute("data-barocss", "partition"), e.styleElement.setAttribute("data-category", t), this.insertionPoint.appendChild(e.styleElement), this.categoryPartitions.set(t, e), e;
25
+ s.styleElement.id = s.id, s.styleElement.setAttribute("data-barocss", "partition"), s.styleElement.setAttribute("data-category", t);
26
+ const i = this.insertionPoint.ownerDocument?.head;
27
+ return e && i ? i.insertBefore(s.styleElement, i.firstChild) : this.insertionPoint.appendChild(s.styleElement), this.categoryPartitions.set(t, s), s;
16
28
  }
17
29
  createNewPartition() {
18
30
  const t = {
@@ -57,16 +69,19 @@ class u {
57
69
  addRule(t) {
58
70
  if (this.hasRule(t))
59
71
  return !1;
60
- this.currentPartition.styles.length >= this.maxRulesPerPartition && this.createNewPartition();
61
- const e = this.currentPartition, s = this.partitions.length - 1;
72
+ const e = y(t);
73
+ let s = this.partitions.findIndex((r) => {
74
+ const n = r.keys;
75
+ return !!n && n.length > 0 && b(n[n.length - 1], e) > 0;
76
+ });
77
+ s === -1 && (this.currentPartition.styles.length >= this.maxRulesPerPartition && this.createNewPartition(), s = this.partitions.length - 1);
78
+ const i = this.partitions[s];
62
79
  try {
63
- const i = e.styleElement.sheet;
64
- return i ? i.insertRule(this.escapeCssRule(t), i.cssRules.length) : e.styleElement.textContent += t + `
65
- `, this.setRuleCache(t, s), e.styles.push(t), !0;
66
- } catch (i) {
80
+ return this.insertSorted(i, t, e), this.setRuleCache(t, s), !0;
81
+ } catch (r) {
67
82
  return console.warn(
68
83
  `[StylePartitionManager] Failed to insert rule: ${t}`,
69
- i
84
+ r
70
85
  ), !1;
71
86
  }
72
87
  }
@@ -76,16 +91,14 @@ class u {
76
91
  let s = this.getCategoryPartition(e);
77
92
  s || (s = this.createNewCategoryPartition(e));
78
93
  try {
79
- const i = s.styleElement.sheet;
80
- i ? i.insertRule(this.escapeCssRule(t), i.cssRules.length) : s.styleElement.textContent += t + `
81
- `;
94
+ this.insertSorted(s, t, y(t));
82
95
  } catch (i) {
83
96
  return console.warn(
84
97
  `[StylePartitionManager] Failed to insert rule in category: ${e} ${t}`,
85
98
  i
86
99
  ), !1;
87
100
  }
88
- return this.setCategoryRuleCache(t, e), s.styles.push(t), !0;
101
+ return this.setCategoryRuleCache(t, e), !0;
89
102
  }
90
103
  addRootRules(t) {
91
104
  let e = this.getCategoryPartition("root");
@@ -107,16 +120,43 @@ class u {
107
120
  addRules(t) {
108
121
  let e = 0, s = 0;
109
122
  for (const i of t) {
110
- const n = y.get(i.cls)?.utility?.category;
111
- if (n)
112
- for (const o of i.cssList)
113
- this.addCategoryRule(o, n);
123
+ const r = this.getCategory(i.cls);
124
+ if (r)
125
+ for (const n of i.cssList)
126
+ this.addCategoryRule(n, r);
114
127
  else
115
- for (const o of i.cssList)
116
- this.addRule(o) ? e++ : s++;
128
+ for (const n of i.cssList)
129
+ this.addRule(n) ? e++ : s++;
117
130
  }
118
131
  return { success: e, failed: s };
119
132
  }
133
+ /**
134
+ * Remove one generated rule (#269 GC). Keeps `styles`, the #254 `keys` and the
135
+ * sheet's cssRules parallel: one deleteRule at the rule's index, or a text
136
+ * rebuild when the sheet isn't solely ours / has no CSSOM. Returns whether
137
+ * the rule was found.
138
+ */
139
+ removeRule(t, e) {
140
+ let s;
141
+ if (e) {
142
+ if (this.classToCategoryPartitionMap.get(t) !== e) return !1;
143
+ s = this.categoryPartitions.get(e);
144
+ } else {
145
+ const a = this.classToPartitionMap.get(t);
146
+ s = a === void 0 ? void 0 : this.partitions[a];
147
+ }
148
+ if (!s) return !1;
149
+ const i = s.styles.indexOf(t);
150
+ if (i === -1) return !1;
151
+ const r = s.styleElement.sheet, n = !!r && r.cssRules.length === s.styles.length;
152
+ return s.styles.splice(i, 1), s.keys?.splice(i, 1), n && r ? r.deleteRule(i) : s.styleElement.textContent = s.styles.length ? s.styles.join(`
153
+ `) + `
154
+ ` : "", e ? this.classToCategoryPartitionMap.delete(t) : this.classToPartitionMap.delete(t), !0;
155
+ }
156
+ /** Number of generated (non-root, non-preflight) rules currently held. */
157
+ get ruleCount() {
158
+ return this.classToPartitionMap.size + this.classToCategoryPartitionMap.size;
159
+ }
120
160
  /**
121
161
  * 특정 규칙이 어느 파티션에 있는지 찾기
122
162
  */
@@ -127,13 +167,13 @@ class u {
127
167
  const s = this.classToCategoryPartitionMap.get(t);
128
168
  return s !== void 0 && this.categoryPartitions.get(s) || null;
129
169
  }
130
- updateRuleContent(t, e) {
131
- const s = this.getCategoryPartition(t);
132
- if (s)
133
- s.styleElement.textContent = e;
170
+ updateRuleContent(t, e, s = !1) {
171
+ const i = this.getCategoryPartition(t);
172
+ if (i)
173
+ i.styleElement.textContent = e;
134
174
  else {
135
- const i = this.createNewCategoryPartition(t);
136
- console.log(`[StylePartitionManager] Created new partition for category: ${t}`), i.styleElement.textContent = e;
175
+ const r = this.createNewCategoryPartition(t, s);
176
+ console.log(`[StylePartitionManager] Created new partition for category: ${t}`), r.styleElement.textContent = e;
137
177
  }
138
178
  }
139
179
  /**
@@ -147,21 +187,24 @@ class u {
147
187
  }), this.partitions = [], this.categoryPartitions.clear(), this.partitionCounter = 0, this.classToPartitionMap.clear(), this.classToCategoryPartitionMap.clear();
148
188
  }
149
189
  }
150
- function p(a) {
151
- return a ? a instanceof SVGAnimatedString ? a.baseVal.toString() : a.toString() : "";
190
+ function x(o) {
191
+ return o ? typeof o == "object" && typeof o.baseVal == "string" ? o.baseVal : o.toString() : "";
152
192
  }
153
- function c(a) {
154
- return a ? p(a).split(/\s+/).filter(Boolean) : [];
193
+ function u(o) {
194
+ return o ? x(o).split(/\s+/).filter(Boolean) : [];
155
195
  }
156
- class m {
196
+ class E {
157
197
  /**
158
198
  * Create a new ChangeDetector instance
159
199
  *
160
200
  * @param incrementalParser - IncrementalParser instance for class processing
161
201
  * @param BrowserRuntime - Optional BrowserRuntime instance for CSS injection
162
202
  */
163
- constructor(t, e) {
164
- this.observer = null, this.incrementalParser = t, this.BrowserRuntime = e;
203
+ constructor(t, e, s = (i) => g(i).utility?.category) {
204
+ this.observer = null, this.gc = null, this.incrementalParser = t, this.BrowserRuntime = e, this.getCategory = s;
205
+ }
206
+ setGc(t) {
207
+ this.gc = t;
165
208
  }
166
209
  setParser(t) {
167
210
  this.incrementalParser = t;
@@ -183,24 +226,29 @@ class m {
183
226
  */
184
227
  observe(t = document.body, e) {
185
228
  return typeof window > "u" ? new MutationObserver(() => {
186
- }) : (this.observer && this.observer.disconnect(), this.observer = new MutationObserver((s) => {
187
- const i = /* @__PURE__ */ new Set();
188
- if (s.forEach((r) => {
189
- if (r.type === "attributes" && r.attributeName === "class") {
190
- const n = r.target;
191
- n.className && c(n.className).forEach((l) => {
229
+ }) : (this.observer && this.observer.disconnect(), this.gc?.setRoot(t), this.observer = new MutationObserver((s) => {
230
+ const i = /* @__PURE__ */ new Set(), r = this.gc;
231
+ if (s.forEach((n) => {
232
+ if (r && (n.type === "attributes" ? r.reconcile(n.target) : n.type === "childList" && (n.removedNodes.forEach((a) => r.reconcileTree(a)), n.addedNodes.forEach((a) => r.reconcileTree(a)))), n.type === "attributes" && n.attributeName === "class" && t.contains(n.target)) {
233
+ const a = n.target;
234
+ a.className && u(a.className).forEach((l) => {
192
235
  this.incrementalParser.isProcessed(l) || i.add(l);
193
236
  });
194
237
  }
195
- r.type === "childList" && r.addedNodes.forEach((n) => {
196
- n instanceof Element && (this.processElement(n, i), n.querySelectorAll("[class]").forEach((o) => {
197
- this.processElement(o, i);
198
- }));
238
+ n.type === "childList" && n.addedNodes.forEach((a) => {
239
+ if (a.nodeType === Node.ELEMENT_NODE && t.contains(a)) {
240
+ const c = a;
241
+ this.processElement(c, i), c.querySelectorAll("[class]").forEach((l) => {
242
+ this.processElement(l, i);
243
+ });
244
+ }
199
245
  });
200
246
  }), i.size > 0) {
201
- const r = Array.from(i), n = this.incrementalParser.processClasses(r);
202
- this.BrowserRuntime?.applyParseResults(n);
203
- }
247
+ const n = Array.from(i), a = this.incrementalParser.processClasses(n);
248
+ this.BrowserRuntime?.applyParseResults(a);
249
+ } else
250
+ this.BrowserRuntime?.applyParseResults([]);
251
+ r?.afterBatch();
204
252
  }), this.observer.observe(t, {
205
253
  attributes: !0,
206
254
  subtree: !0,
@@ -213,20 +261,21 @@ class m {
213
261
  */
214
262
  scanExistingClasses(t, e) {
215
263
  const s = /* @__PURE__ */ new Set();
216
- t.className && c(t.className).forEach((n) => {
264
+ t.className && u(t.className).forEach((n) => {
217
265
  this.incrementalParser.isProcessed(n) || s.add(n);
218
266
  });
219
267
  const i = t.querySelectorAll("[class]");
220
268
  for (const r of i)
221
269
  if (r.className) {
222
- const n = c(r.className);
223
- for (const o of n)
224
- this.incrementalParser.isProcessed(o) || s.add(o);
270
+ const n = u(r.className);
271
+ for (const a of n)
272
+ this.incrementalParser.isProcessed(a) || s.add(a);
225
273
  }
226
274
  if (s.size > 0) {
227
- const r = Array.from(s), n = this.incrementalParser.processClasses(r), o = n.filter((h) => y.get(h.cls)?.utility?.category === "layout"), l = n.filter((h) => y.get(h.cls)?.utility?.category !== "layout");
228
- this.BrowserRuntime?.applyParseResults(o), e?.onReady?.(), this.BrowserRuntime?.applyParseResults(l);
229
- }
275
+ const r = Array.from(s), n = this.incrementalParser.processClasses(r), a = n.filter((l) => this.getCategory(l.cls) === "layout"), c = n.filter((l) => this.getCategory(l.cls) !== "layout");
276
+ this.BrowserRuntime?.applyParseResults(a), e?.onReady?.(), this.BrowserRuntime?.applyParseResults(c);
277
+ } else
278
+ e?.onReady?.();
230
279
  }
231
280
  /**
232
281
  * Processes an individual element and extracts new classes
@@ -241,7 +290,7 @@ class m {
241
290
  * @param newClasses - Set to collect newly discovered class names
242
291
  */
243
292
  processElement(t, e) {
244
- t.className && c(t.className).forEach((i) => {
293
+ t.className && u(t.className).forEach((i) => {
245
294
  this.incrementalParser.isProcessed(i) || e.add(i);
246
295
  });
247
296
  }
@@ -256,16 +305,120 @@ class m {
256
305
  this.observer && (this.observer.disconnect(), this.observer = null);
257
306
  }
258
307
  }
259
- class C {
308
+ function S(o) {
309
+ return o.replace(/\\([0-9a-fA-F]{1,6})\s?|\\(.)/g, (t, e, s) => e ? String.fromCodePoint(parseInt(e, 16)) : s);
310
+ }
311
+ const M = /^\s*\.((?:\\[0-9a-fA-F]{1,6}\s?|\\.|[\w-]|[^\x00-\x7F])+)/;
312
+ function v(o) {
313
+ const t = [];
314
+ let e = 0, s = 0;
315
+ for (let i = 0; i < o.length; i++) {
316
+ const r = o[i];
317
+ r === "\\" ? i++ : r === "(" || r === "[" ? e++ : r === ")" || r === "]" ? e-- : r === "," && e === 0 && (t.push(o.slice(s, i)), s = i + 1);
318
+ }
319
+ return t.push(o.slice(s)), t;
320
+ }
321
+ function C(o, t = /* @__PURE__ */ new Set()) {
322
+ for (const e of Array.from(o)) {
323
+ const s = e.selectorText;
324
+ if (typeof s == "string")
325
+ for (const r of v(s)) {
326
+ const n = M.exec(r);
327
+ n && t.add(S(n[1]));
328
+ }
329
+ const i = e.cssRules;
330
+ i && i.length && C(i, t);
331
+ }
332
+ return t;
333
+ }
334
+ class A {
335
+ constructor(t, e, s, i = () => Date.now()) {
336
+ this.host = t, this.graceMs = e, this.maxRules = s, this.now = i, this.counts = /* @__PURE__ */ new Map(), this.counted = /* @__PURE__ */ new WeakMap(), this.candidates = /* @__PURE__ */ new Map(), this.timer = null, this.root = null;
337
+ }
338
+ /** Start counting for a new root: count every element currently inside it. */
339
+ setRoot(t) {
340
+ this.counts.clear(), this.counted = /* @__PURE__ */ new WeakMap(), this.candidates.clear(), this.cancel(), this.root = t, this.reconcileTree(t);
341
+ }
342
+ count(t) {
343
+ return this.counts.get(t) ?? 0;
344
+ }
345
+ /** Re-count `el` and (optionally) all its descendants from their current state. */
346
+ reconcileTree(t) {
347
+ if (t.nodeType !== 1) return;
348
+ const e = t;
349
+ this.reconcile(e), e.querySelectorAll("[class]").forEach((s) => this.reconcile(s));
350
+ }
351
+ reconcile(t) {
352
+ const e = this.root, i = !!e && e.contains(t) ? Array.from(new Set(u(t.getAttribute("class")))) : [], r = this.counted.get(t);
353
+ if (!r && i.length === 0) return;
354
+ const n = new Set(r ?? []), a = new Set(i);
355
+ for (const c of a) {
356
+ if (n.has(c)) continue;
357
+ const l = (this.counts.get(c) ?? 0) + 1;
358
+ this.counts.set(c, l), this.candidates.delete(c);
359
+ }
360
+ for (const c of n) {
361
+ if (a.has(c)) continue;
362
+ const l = (this.counts.get(c) ?? 0) - 1;
363
+ l > 0 ? this.counts.set(c, l) : (this.counts.delete(c), this.candidates.delete(c), this.candidates.set(c, this.now()));
364
+ }
365
+ i.length ? this.counted.set(t, i) : this.counted.delete(t);
366
+ }
367
+ /** Call after a mutation batch has been counted and its classes inserted. */
368
+ afterBatch() {
369
+ this.candidates.size !== 0 && (this.host.cachedCount() > this.maxRules ? this.schedule(0) : this.schedule(this.graceMs));
370
+ }
371
+ schedule(t) {
372
+ if (this.timer !== null) {
373
+ if (t > 0) return;
374
+ clearTimeout(this.timer);
375
+ }
376
+ this.timer = setTimeout(() => {
377
+ this.timer = null, this.sweep();
378
+ }, t);
379
+ }
380
+ /** Reclaim candidates whose grace period elapsed (plus LRU overflow). Public for tests. */
381
+ sweep() {
382
+ const t = this.now(), e = Math.max(0, this.host.cachedCount() - this.maxRules), s = [];
383
+ let i = 0;
384
+ for (const [r, n] of this.candidates) {
385
+ const a = t - n >= this.graceMs;
386
+ !a && i >= e || (this.candidates.delete(r), !(this.count(r) > 0 || this.inDom(r) || this.host.isPermanent(r)) && (s.push(r), a || i++));
387
+ }
388
+ s.length && this.host.reclaim(s), this.candidates.size && this.schedule(this.graceMs);
389
+ }
390
+ inDom(t) {
391
+ const e = this.root;
392
+ if (!e) return !1;
393
+ const s = e.ownerDocument ?? document;
394
+ return e.classList.contains(t) || s.documentElement.classList.contains(t) || s.getElementsByClassName(t).length > 0;
395
+ }
396
+ cancel() {
397
+ this.timer !== null && clearTimeout(this.timer), this.timer = null;
398
+ }
399
+ stats() {
400
+ return { trackedClasses: this.counts.size, candidates: this.candidates.size };
401
+ }
402
+ }
403
+ const D = "@layer theme, base, components, utilities;";
404
+ class L {
260
405
  constructor(t = {}) {
261
- this.cache = /* @__PURE__ */ new Map(), this.rootCache = /* @__PURE__ */ new Set(), this.isDestroyed = !1;
406
+ this.cache = /* @__PURE__ */ new Map(), this.rootCache = /* @__PURE__ */ new Set(), this.isDestroyed = !1, this.existing = null, this.existingSheetCount = -1, this.pinned = /* @__PURE__ */ new Set(), this.gc = null, this.reclaimedCount = 0, this.getCategory = (s) => g(s, this.context).utility?.category;
262
407
  const e = {};
263
408
  this.options = {
264
409
  config: t.config || e,
265
410
  styleId: t.styleId || "barocss-runtime",
266
411
  insertionPoint: t.insertionPoint || "head",
267
- maxRulesPerPartition: t.maxRulesPerPartition || 50
268
- }, this.context = f(this.options.config), this.incrementalParser = new g(this.context), this.changeDetector = new m(this.incrementalParser, this), this.stylePartitionManager = new u(this.getInsertionPoint(), this.options.maxRulesPerPartition, `${this.options.styleId}-partition`), this.init();
412
+ maxRulesPerPartition: t.maxRulesPerPartition || 50,
413
+ skipExisting: t.skipExisting ?? !1,
414
+ gc: t.gc ?? !0,
415
+ gcGraceMs: t.gcGraceMs ?? 3e3,
416
+ maxRules: t.maxRules ?? 1 / 0
417
+ }, this.context = m(this.options.config), this.incrementalParser = new p(this.context), this.changeDetector = new E(this.incrementalParser, this, this.getCategory), this.stylePartitionManager = new d(this.getInsertionPoint(), this.options.maxRulesPerPartition, `${this.options.styleId}-partition`, this.getCategory), this.options.gc && (this.gc = new A({
418
+ reclaim: (s) => this.reclaim(s),
419
+ isPermanent: (s) => this.isPermanent(s),
420
+ cachedCount: () => this.cache.size
421
+ }, this.options.gcGraceMs, this.options.maxRules), this.changeDetector.setGc(this.gc)), this.init();
269
422
  }
270
423
  // Debugging and logging helpers
271
424
  /**
@@ -278,9 +431,17 @@ class C {
278
431
  console.log("[BrowserRuntime] init"), this.injectPreflightCSS(), this.ensureCssVars();
279
432
  }
280
433
  injectPreflightCSS() {
281
- if (this.options.config.preflight) {
282
- const t = this.context.getPreflightCSS(this.options.config.preflight);
283
- this.stylePartitionManager.updateRuleContent("preflight", t);
434
+ const t = this.options.config.preflight ?? !0;
435
+ if (t) {
436
+ const e = this.context.getPreflightCSS(t);
437
+ this.stylePartitionManager.updateRuleContent(
438
+ "preflight",
439
+ `${D}
440
+ @layer base {
441
+ ${e}
442
+ }`,
443
+ !0
444
+ );
284
445
  }
285
446
  }
286
447
  ensureCssVars() {
@@ -289,7 +450,7 @@ class C {
289
450
  this.stylePartitionManager.updateRuleContent("css-vars", t);
290
451
  }
291
452
  getInsertionPoint() {
292
- if (this.options.insertionPoint instanceof HTMLElement)
453
+ if (typeof this.options.insertionPoint != "string")
293
454
  return this.options.insertionPoint;
294
455
  switch (this.options.insertionPoint) {
295
456
  case "body":
@@ -304,8 +465,8 @@ class C {
304
465
  */
305
466
  addClass(t) {
306
467
  if (this.isDestroyed) return;
307
- const e = this.normalizeClasses(t);
308
- this.processClasses(e);
468
+ const e = this.normalizeClasses(t).filter(Boolean);
469
+ e.forEach((s) => this.pinned.add(s)), this.processClasses(e);
309
470
  }
310
471
  /**
311
472
  * Process classes
@@ -329,6 +490,11 @@ class C {
329
490
  const r = Array.from(this.cache.values());
330
491
  this.reset(), t = [...r, ...t], t.forEach((n) => this.incrementalParser.markProcessed(n.cls));
331
492
  }
493
+ if (this.options.skipExisting && t.length > 0 && typeof document < "u") {
494
+ const r = this.getExistingClasses();
495
+ t = t.filter((n) => !r.has(n.cls));
496
+ }
497
+ if (t.length === 0) return;
332
498
  const s = [], i = [];
333
499
  for (const r of t)
334
500
  if (r.css && Array.isArray(r.cssList) && (s.push(r), this.cache.set(r.cls, r)), r.rootCss && Array.isArray(r.rootCssList))
@@ -339,6 +505,51 @@ class C {
339
505
  rootCssCount: i.length
340
506
  });
341
507
  }
508
+ /** #269: a class that must never be reclaimed. */
509
+ isPermanent(t) {
510
+ return this.pinned.has(t) || typeof document > "u" ? !0 : this.getExistingClasses().has(t);
511
+ }
512
+ /**
513
+ * #269: delete the generated rules of classes no live element uses. Root/@property rules stay
514
+ * (they are shared and harmless); a rule text another cached class still emits is kept.
515
+ */
516
+ reclaim(t) {
517
+ if (this.isDestroyed) return;
518
+ const e = t.filter((r) => this.cache.has(r));
519
+ if (e.length === 0) return;
520
+ const s = e.map((r) => this.cache.get(r));
521
+ e.forEach((r) => {
522
+ this.cache.delete(r), this.incrementalParser.unmarkProcessed(r);
523
+ });
524
+ const i = /* @__PURE__ */ new Set();
525
+ for (const r of this.cache.values()) r.cssList.forEach((n) => i.add(n));
526
+ for (const r of s) {
527
+ const n = this.getCategory(r.cls);
528
+ for (const a of r.cssList)
529
+ i.has(a) || this.stylePartitionManager.removeRule(a, n);
530
+ }
531
+ this.reclaimedCount += e.length;
532
+ }
533
+ /** Class names defined by the page's own stylesheets (BaroCSS's sheets and cross-origin sheets excluded). */
534
+ getExistingClasses() {
535
+ const t = new Set(Array.from(document.querySelectorAll("style[data-barocss]"), (i) => i.sheet)), e = Array.from(document.styleSheets).filter((i) => {
536
+ if (t.has(i)) return !1;
537
+ const r = i.ownerNode;
538
+ return !(r && typeof r.hasAttribute == "function" && (r.hasAttribute("data-barocss") || (r.id || "").startsWith(this.options.styleId)));
539
+ });
540
+ if (this.existing && e.length === this.existingSheetCount) return this.existing;
541
+ const s = /* @__PURE__ */ new Set();
542
+ for (const i of e) {
543
+ let r;
544
+ try {
545
+ r = i.cssRules;
546
+ } catch {
547
+ continue;
548
+ }
549
+ C(r, s);
550
+ }
551
+ return this.existing = s, this.existingSheetCount = e.length, s;
552
+ }
342
553
  /**
343
554
  * MutationObserver instance method to automatically call addClass when class attributes change in DOM
344
555
  */
@@ -356,7 +567,7 @@ class C {
356
567
  `);
357
568
  }
358
569
  getAllCss() {
359
- return Array.from(this.cache.values()).flatMap((e) => e.cssList).join(`
570
+ return [...this.rootCache, ...Array.from(this.cache.values()).flatMap((e) => e.cssList)].join(`
360
571
  `);
361
572
  }
362
573
  getClasses() {
@@ -370,7 +581,10 @@ class C {
370
581
  return {
371
582
  runtime: {
372
583
  cachedClasses: this.cache.size,
373
- rootCacheSize: this.rootCache.size
584
+ rootCacheSize: this.rootCache.size,
585
+ ruleCount: this.stylePartitionManager.ruleCount,
586
+ reclaimedClasses: this.reclaimedCount,
587
+ gc: this.gc?.stats() ?? null
374
588
  },
375
589
  ast: t.cacheStats.ast,
376
590
  incremental: t
@@ -380,15 +594,15 @@ class C {
380
594
  * Clear all caches (useful for debugging or memory management)
381
595
  */
382
596
  clearCaches() {
383
- this.isDestroyed || (this.cache.clear(), this.rootCache.clear(), P(this.context), this.incrementalParser.clearProcessed(), this.stylePartitionManager.cleanup(), this.stylePartitionManager = new u(this.getInsertionPoint(), this.options.maxRulesPerPartition, `${this.options.styleId}-partition`), this.injectPreflightCSS(), this.ensureCssVars());
597
+ this.isDestroyed || (this.cache.clear(), this.rootCache.clear(), w(this.context), this.incrementalParser.clearProcessed(), this.stylePartitionManager.cleanup(), this.stylePartitionManager = new d(this.getInsertionPoint(), this.options.maxRulesPerPartition, `${this.options.styleId}-partition`, this.getCategory), this.injectPreflightCSS(), this.ensureCssVars());
384
598
  }
385
599
  reset() {
386
- this.isDestroyed || (this.cache.clear(), this.rootCache.clear(), this.incrementalParser.clearProcessed(), this.stylePartitionManager.cleanup(), this.stylePartitionManager = new u(this.getInsertionPoint(), this.options.maxRulesPerPartition, `${this.options.styleId}-partition`), this.injectPreflightCSS(), this.ensureCssVars());
600
+ this.isDestroyed || (this.cache.clear(), this.rootCache.clear(), this.incrementalParser.clearProcessed(), this.stylePartitionManager.cleanup(), this.stylePartitionManager = new d(this.getInsertionPoint(), this.options.maxRulesPerPartition, `${this.options.styleId}-partition`, this.getCategory), this.injectPreflightCSS(), this.ensureCssVars());
387
601
  }
388
602
  updateConfig(t) {
389
603
  if (this.isDestroyed) return;
390
604
  const e = Array.from(this.cache.keys());
391
- this.options.config = t, this.context = f(t), this.incrementalParser = new g(this.context), this.changeDetector.setParser(this.incrementalParser), this.reset(), e.length > 0 && this.addClass(e);
605
+ this.options.config = t, this.context = m(t), this.incrementalParser = new p(this.context), this.changeDetector.setParser(this.incrementalParser), this.reset(), e.length > 0 && this.addClass(e);
392
606
  }
393
607
  removeClass(t) {
394
608
  if (this.isDestroyed) return;
@@ -396,7 +610,7 @@ class C {
396
610
  s.length !== this.cache.size && (this.reset(), s.forEach((i) => this.incrementalParser.markProcessed(i.cls)), this.applyParseResults(s));
397
611
  }
398
612
  destroy() {
399
- this.isDestroyed || (this.changeDetector.disconnect(), this.stylePartitionManager.cleanup(), this.cache.clear(), this.rootCache.clear(), this.isDestroyed = !0);
613
+ this.isDestroyed || (this.changeDetector.disconnect(), this.gc?.cancel(), this.stylePartitionManager.cleanup(), this.cache.clear(), this.rootCache.clear(), this.isDestroyed = !0);
400
614
  }
401
615
  getStats() {
402
616
  return {
@@ -408,28 +622,98 @@ class C {
408
622
  };
409
623
  }
410
624
  }
411
- let d = null;
412
- function R(a) {
413
- return d || (d = new C(a)), d;
625
+ let h = null, f;
626
+ function N(o = {}) {
627
+ return !h || h.getStats().isDestroyed ? (h = new L(o), f = o.config) : o.config && o.config !== f && (h.updateConfig(o.config), f = o.config), h;
414
628
  }
415
- function b({ loadingClassName: a = "baro-boot", ...t } = {}) {
416
- const e = `${a}-doing`, s = `${a}-done`;
629
+ function P({ loadingClassName: o = "baro-boot", ...t } = {}) {
630
+ if (!document.body) {
631
+ document.addEventListener("DOMContentLoaded", () => P({ loadingClassName: o, ...t }), { once: !0 });
632
+ return;
633
+ }
634
+ const e = `${o}-doing`, s = `${o}-done`;
417
635
  try {
418
- document.body.classList.add(e), R(t).observe(document.body, { scan: !0, onReady: () => {
636
+ document.body.classList.add(e), N(t).observe(document.body, { scan: !0, onReady: () => {
419
637
  document.body.classList.remove(e), document.body.classList.add(s);
420
638
  } });
421
639
  } catch (i) {
422
- console.error("BaroCSS boot failed:", i);
640
+ document.body?.classList.remove(e), console.error("BaroCSS boot failed:", i);
423
641
  }
424
642
  }
425
- const E = b;
643
+ const z = P;
644
+ function T(o) {
645
+ if (!o || typeof o != "object" || Array.isArray(o)) return [];
646
+ const t = o.elements;
647
+ if (!t || typeof t != "object" || Array.isArray(t)) return [];
648
+ const e = /* @__PURE__ */ new Set();
649
+ for (const s of Object.keys(t)) {
650
+ const i = t[s];
651
+ if (!i || typeof i != "object" || Array.isArray(i)) continue;
652
+ const r = i.props;
653
+ if (!r || typeof r != "object" || Array.isArray(r)) continue;
654
+ const n = r.className;
655
+ if (typeof n == "string")
656
+ for (const a of n.split(/\s+/))
657
+ a && e.add(a);
658
+ }
659
+ return Array.from(e);
660
+ }
661
+ function B(o, t) {
662
+ const e = T(o);
663
+ e.length > 0 && t.addClass(e);
664
+ }
665
+ const I = [
666
+ "background",
667
+ "foreground",
668
+ "card",
669
+ "card-foreground",
670
+ "popover",
671
+ "popover-foreground",
672
+ "primary",
673
+ "primary-foreground",
674
+ "secondary",
675
+ "secondary-foreground",
676
+ "muted",
677
+ "muted-foreground",
678
+ "accent",
679
+ "accent-foreground",
680
+ "destructive",
681
+ "border",
682
+ "input",
683
+ "ring",
684
+ "chart-1",
685
+ "chart-2",
686
+ "chart-3",
687
+ "chart-4",
688
+ "chart-5",
689
+ "sidebar",
690
+ "sidebar-foreground",
691
+ "sidebar-primary",
692
+ "sidebar-primary-foreground",
693
+ "sidebar-accent",
694
+ "sidebar-accent-foreground",
695
+ "sidebar-border",
696
+ "sidebar-ring"
697
+ ], $ = {
698
+ colors: Object.fromEntries(I.map((o) => [o, `var(--${o})`])),
699
+ borderRadius: {
700
+ sm: "calc(var(--radius) - 4px)",
701
+ md: "calc(var(--radius) - 2px)",
702
+ lg: "var(--radius)",
703
+ xl: "calc(var(--radius) + 4px)"
704
+ }
705
+ };
426
706
  export {
427
- C as BrowserRuntime,
428
- m as ChangeDetector,
429
- u as StylePartitionManager,
430
- b as baroBoot,
431
- E as baroStart,
432
- R as getRuntime,
433
- p as normalizeClassName,
434
- c as normalizeClassNameList
707
+ L as BrowserRuntime,
708
+ E as ChangeDetector,
709
+ D as LAYER_ORDER,
710
+ d as StylePartitionManager,
711
+ P as baroBoot,
712
+ z as baroStart,
713
+ T as collectJsonRenderClassNames,
714
+ N as getRuntime,
715
+ x as normalizeClassName,
716
+ u as normalizeClassNameList,
717
+ B as preloadJsonRenderClasses,
718
+ $ as shadcnTheme
435
719
  };