@tenphi/tasty 3.3.1 → 3.5.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/README.md +147 -129
- package/dist/astro-ib7E7V4Y.js +307 -0
- package/dist/astro-ib7E7V4Y.js.map +1 -0
- package/dist/{babel-BUQGeOXA.d.ts → babel-DWCsafYw.d.ts} +2 -2
- package/dist/{collector-DUaHCcTS.d.ts → collector-BTVXj2hS.d.ts} +21 -3
- package/dist/{collector-BKqNBmzA.js → collector-C6TtL8HJ.js} +36 -13
- package/dist/collector-C6TtL8HJ.js.map +1 -0
- package/dist/{config-BCdCTIED.js → config-B3gPdCqd.js} +344 -209
- package/dist/config-B3gPdCqd.js.map +1 -0
- package/dist/{config-YsxGv4tq.d.ts → config-LfIDmVHx.d.ts} +132 -32
- package/dist/core/index.d.ts +5 -5
- package/dist/core/index.js +6 -6
- package/dist/{core-wxP3GHQu.js → core-Bq7w2kti.js} +219 -98
- package/dist/core-Bq7w2kti.js.map +1 -0
- package/dist/{css-writer-D64NY9AX.js → css-writer-Bgowobbx.js} +3 -3
- package/dist/{css-writer-D64NY9AX.js.map → css-writer-Bgowobbx.js.map} +1 -1
- package/dist/{format-rules-Bo_e2u7r.js → format-rules-rCZ37rqY.js} +2 -2
- package/dist/format-rules-rCZ37rqY.js.map +1 -0
- package/dist/{hydrate-CMKOuKAx.js → hydrate-CNOmZprz.js} +3 -3
- package/dist/{hydrate-CMKOuKAx.js.map → hydrate-CNOmZprz.js.map} +1 -1
- package/dist/{index-DhhUI0yi.d.ts → index-Bm9ltvdH.d.ts} +45 -16
- package/dist/{index-Cd45t5NM.d.ts → index-BmogEzTo.d.ts} +69 -15
- package/dist/index.d.ts +5 -5
- package/dist/index.js +9 -8
- package/dist/index.js.map +1 -1
- package/dist/{keyframes-D737PShJ.js → keyframes-DE-OE76F.js} +132 -21
- package/dist/keyframes-DE-OE76F.js.map +1 -0
- package/dist/{merge-styles-CU7JbEwg.d.ts → merge-styles-BcLl1u_d.d.ts} +2 -2
- package/dist/{merge-styles-CUIQcs5v.js → merge-styles-DuoZEsm9.js} +2 -2
- package/dist/{merge-styles-CUIQcs5v.js.map → merge-styles-DuoZEsm9.js.map} +1 -1
- package/dist/{resolve-recipes-Df1Ta-Q0.js → resolve-recipes-H9NqOQuP.js} +3 -3
- package/dist/{resolve-recipes-Df1Ta-Q0.js.map → resolve-recipes-H9NqOQuP.js.map} +1 -1
- package/dist/ssr/astro-client.js +1 -1
- package/dist/ssr/astro-middleware-extract-static.d.ts +11 -0
- package/dist/ssr/astro-middleware-extract-static.js +9 -0
- package/dist/ssr/astro-middleware-extract-static.js.map +1 -0
- package/dist/ssr/astro-middleware-extract.d.ts +11 -0
- package/dist/ssr/astro-middleware-extract.js +9 -0
- package/dist/ssr/astro-middleware-extract.js.map +1 -0
- package/dist/ssr/astro-middleware-static.d.ts +3 -1
- package/dist/ssr/astro-middleware-static.js +1 -1
- package/dist/ssr/astro-middleware.d.ts +3 -1
- package/dist/ssr/astro-middleware.js +1 -1
- package/dist/ssr/astro.d.ts +37 -3
- package/dist/ssr/astro.js +1 -156
- package/dist/ssr/index.d.ts +2 -2
- package/dist/ssr/index.js +3 -3
- package/dist/ssr/index.js.map +1 -1
- package/dist/ssr/next.d.ts +1 -1
- package/dist/ssr/next.js +4 -4
- package/dist/static/index.d.ts +2 -2
- package/dist/static/index.js +1 -1
- package/dist/zero/babel.d.ts +1 -1
- package/dist/zero/babel.js +4 -4
- package/dist/zero/babel.js.map +1 -1
- package/dist/zero/index.d.ts +1 -1
- package/dist/zero/index.js +1 -1
- package/dist/zero/next.d.ts +1 -1
- package/docs/README.md +13 -8
- package/docs/adoption.md +56 -31
- package/docs/ai-agents.md +78 -77
- package/docs/comparison.md +69 -40
- package/docs/configuration.md +97 -87
- package/docs/debug.md +4 -2
- package/docs/design-system.md +41 -22
- package/docs/dsl.md +225 -195
- package/docs/getting-started.md +60 -39
- package/docs/injector.md +63 -26
- package/docs/methodology.md +42 -36
- package/docs/migration-v3.md +49 -49
- package/docs/plugins.md +37 -33
- package/docs/react-api.md +65 -44
- package/docs/runtime-benchmarks.md +178 -0
- package/docs/ssr.md +99 -61
- package/docs/styles.md +1 -1
- package/docs/tasty-static.md +137 -104
- package/package.json +26 -8
- package/dist/collector-BKqNBmzA.js.map +0 -1
- package/dist/config-BCdCTIED.js.map +0 -1
- package/dist/core-wxP3GHQu.js.map +0 -1
- package/dist/format-rules-Bo_e2u7r.js.map +0 -1
- package/dist/keyframes-D737PShJ.js.map +0 -1
- package/dist/ssr/astro.js.map +0 -1
|
@@ -1211,6 +1211,15 @@ function classify(raw, opts, recurse) {
|
|
|
1211
1211
|
}
|
|
1212
1212
|
//#endregion
|
|
1213
1213
|
//#region src/parser/lru.ts
|
|
1214
|
+
/**
|
|
1215
|
+
* Doubly-linked-list LRU.
|
|
1216
|
+
*
|
|
1217
|
+
* The list holds direct node references rather than keys, so rewiring on a
|
|
1218
|
+
* `get()` of a non-MRU entry is pure pointer work. Storing keys instead cost
|
|
1219
|
+
* three extra `Map.get()` lookups per read (prev, next and the current head),
|
|
1220
|
+
* which is measurable on these read-mostly caches: they are hit on every
|
|
1221
|
+
* render once the style pipeline is warm.
|
|
1222
|
+
*/
|
|
1214
1223
|
var Lru = class {
|
|
1215
1224
|
limit;
|
|
1216
1225
|
map = /* @__PURE__ */ new Map();
|
|
@@ -1229,86 +1238,60 @@ var Lru = class {
|
|
|
1229
1238
|
}
|
|
1230
1239
|
get(key) {
|
|
1231
1240
|
const node = this.map.get(key);
|
|
1232
|
-
if (
|
|
1233
|
-
this.
|
|
1241
|
+
if (node === void 0) return void 0;
|
|
1242
|
+
if (this.head !== node) this.moveToHead(node);
|
|
1234
1243
|
return node.value;
|
|
1235
1244
|
}
|
|
1236
1245
|
set(key, value) {
|
|
1237
|
-
|
|
1238
|
-
if (
|
|
1239
|
-
|
|
1240
|
-
this.
|
|
1246
|
+
const existing = this.map.get(key);
|
|
1247
|
+
if (existing !== void 0) {
|
|
1248
|
+
existing.value = value;
|
|
1249
|
+
if (this.head !== existing) this.moveToHead(existing);
|
|
1241
1250
|
return;
|
|
1242
1251
|
}
|
|
1243
|
-
node = {
|
|
1252
|
+
const node = {
|
|
1253
|
+
key,
|
|
1244
1254
|
prev: null,
|
|
1245
1255
|
next: this.head,
|
|
1246
1256
|
value
|
|
1247
1257
|
};
|
|
1248
|
-
if (this.head)
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
}
|
|
1252
|
-
this.head = key;
|
|
1253
|
-
if (!this.tail) this.tail = key;
|
|
1258
|
+
if (this.head) this.head.prev = node;
|
|
1259
|
+
this.head = node;
|
|
1260
|
+
if (!this.tail) this.tail = node;
|
|
1254
1261
|
this.map.set(key, node);
|
|
1255
1262
|
if (this.map.size > this.limit) this.evict();
|
|
1256
1263
|
}
|
|
1257
1264
|
delete(key) {
|
|
1258
1265
|
const node = this.map.get(key);
|
|
1259
|
-
if (
|
|
1260
|
-
|
|
1261
|
-
const prevNode = this.map.get(node.prev);
|
|
1262
|
-
if (prevNode) prevNode.next = node.next;
|
|
1263
|
-
}
|
|
1264
|
-
if (node.next) {
|
|
1265
|
-
const nextNode = this.map.get(node.next);
|
|
1266
|
-
if (nextNode) nextNode.prev = node.prev;
|
|
1267
|
-
}
|
|
1268
|
-
if (this.head === key) this.head = node.next;
|
|
1269
|
-
if (this.tail === key) this.tail = node.prev;
|
|
1266
|
+
if (node === void 0) return;
|
|
1267
|
+
this.detach(node);
|
|
1270
1268
|
this.map.delete(key);
|
|
1271
1269
|
}
|
|
1272
1270
|
keys() {
|
|
1273
1271
|
return this.map.keys();
|
|
1274
1272
|
}
|
|
1275
|
-
|
|
1276
|
-
if (
|
|
1277
|
-
if (node.
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
}
|
|
1281
|
-
if (node.next) {
|
|
1282
|
-
const nextNode = this.map.get(node.next);
|
|
1283
|
-
if (nextNode) nextNode.prev = node.prev;
|
|
1284
|
-
}
|
|
1285
|
-
if (this.tail === key) this.tail = node.prev;
|
|
1273
|
+
detach(node) {
|
|
1274
|
+
if (node.prev) node.prev.next = node.next;
|
|
1275
|
+
if (node.next) node.next.prev = node.prev;
|
|
1276
|
+
if (this.head === node) this.head = node.next;
|
|
1277
|
+
if (this.tail === node) this.tail = node.prev;
|
|
1286
1278
|
node.prev = null;
|
|
1279
|
+
node.next = null;
|
|
1280
|
+
}
|
|
1281
|
+
moveToHead(node) {
|
|
1282
|
+
this.detach(node);
|
|
1287
1283
|
node.next = this.head;
|
|
1288
|
-
if (this.head)
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
}
|
|
1292
|
-
this.head = key;
|
|
1284
|
+
if (this.head) this.head.prev = node;
|
|
1285
|
+
this.head = node;
|
|
1286
|
+
if (!this.tail) this.tail = node;
|
|
1293
1287
|
}
|
|
1294
1288
|
evict() {
|
|
1295
|
-
const
|
|
1296
|
-
if (!
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
if (this.head === old) this.head = null;
|
|
1300
|
-
this.tail = null;
|
|
1301
|
-
return;
|
|
1302
|
-
}
|
|
1303
|
-
if (node.prev) {
|
|
1304
|
-
const prevNode = this.map.get(node.prev);
|
|
1305
|
-
if (prevNode) prevNode.next = null;
|
|
1306
|
-
}
|
|
1307
|
-
this.tail = node.prev;
|
|
1308
|
-
if (this.head === old) this.head = null;
|
|
1309
|
-
this.map.delete(old);
|
|
1289
|
+
const node = this.tail;
|
|
1290
|
+
if (!node) return;
|
|
1291
|
+
this.detach(node);
|
|
1292
|
+
this.map.delete(node.key);
|
|
1310
1293
|
if (this.onEvict) try {
|
|
1311
|
-
this.onEvict(
|
|
1294
|
+
this.onEvict(node.key, node.value);
|
|
1312
1295
|
} catch {}
|
|
1313
1296
|
}
|
|
1314
1297
|
clear() {
|
|
@@ -3203,7 +3186,14 @@ function resetStyleBatch() {
|
|
|
3203
3186
|
* Automatically infers CSS @property types from custom property values.
|
|
3204
3187
|
* Supports deferred resolution for var() reference chains of arbitrary depth.
|
|
3205
3188
|
*/
|
|
3206
|
-
|
|
3189
|
+
/**
|
|
3190
|
+
* One `--name: value` declaration, with the surrounding whitespace dropped.
|
|
3191
|
+
*
|
|
3192
|
+
* The value is anchored on `\S` at both ends so no two quantifiers can claim
|
|
3193
|
+
* the same character. A lazy `(.+?)\s*$` is quadratic on a value of nothing
|
|
3194
|
+
* but spaces — every split point gets tried (CodeQL `js/polynomial-redos`).
|
|
3195
|
+
*/
|
|
3196
|
+
const CUSTOM_PROP_DECL = /^\s*(--[a-z0-9_-]+)\s*:\s*(\S|\S.*\S)\s*$/i;
|
|
3207
3197
|
const SINGLE_VAR_REF = /^var\((--[a-z0-9_-]+)\)$/i;
|
|
3208
3198
|
var PropertyTypeResolver = class {
|
|
3209
3199
|
/** propName → the prop it depends on */
|
|
@@ -5057,7 +5047,7 @@ var SheetManager = class {
|
|
|
5057
5047
|
} : void 0;
|
|
5058
5048
|
registry = {
|
|
5059
5049
|
sheets: [],
|
|
5060
|
-
|
|
5050
|
+
pinCounts: /* @__PURE__ */ new Map(),
|
|
5061
5051
|
rules: /* @__PURE__ */ new Map(),
|
|
5062
5052
|
cacheKeyToClassName: /* @__PURE__ */ new Map(),
|
|
5063
5053
|
ruleTextSet: /* @__PURE__ */ new Set(),
|
|
@@ -5071,10 +5061,9 @@ var SheetManager = class {
|
|
|
5071
5061
|
injectedFunctions: /* @__PURE__ */ new Map(),
|
|
5072
5062
|
globalRules: /* @__PURE__ */ new Map(),
|
|
5073
5063
|
propertyTypeResolver: new PropertyTypeResolver(),
|
|
5074
|
-
|
|
5064
|
+
unusedSince: /* @__PURE__ */ new Map(),
|
|
5065
|
+
localKeyframes: /* @__PURE__ */ new Map(),
|
|
5075
5066
|
touchCount: 0,
|
|
5076
|
-
touchTick: -1,
|
|
5077
|
-
touchedTick: /* @__PURE__ */ new Set(),
|
|
5078
5067
|
serverClassSyncIndex: 0,
|
|
5079
5068
|
rscStylesScanned: false,
|
|
5080
5069
|
injectionMode: this.detectInjectionMode(root)
|
|
@@ -5456,25 +5445,26 @@ var SheetManager = class {
|
|
|
5456
5445
|
return registry.atPropertySupported;
|
|
5457
5446
|
}
|
|
5458
5447
|
/**
|
|
5459
|
-
*
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
*
|
|
5448
|
+
* Delete the given classes: their rules leave the sheets and every registry
|
|
5449
|
+
* entry pointing at them is dropped.
|
|
5450
|
+
*
|
|
5451
|
+
* Deciding *what* is unused belongs to `StyleInjector.gc()`, which owns the
|
|
5452
|
+
* DOM scan and the capacity policy. This only re-checks that each class is
|
|
5453
|
+
* still safe to delete, and reports how many were.
|
|
5454
|
+
*
|
|
5455
|
+
* @returns Number of classes actually deleted.
|
|
5466
5456
|
*/
|
|
5467
|
-
|
|
5457
|
+
deleteClasses(registry, classNames) {
|
|
5468
5458
|
const cleanupStartTime = Date.now();
|
|
5469
|
-
const
|
|
5470
|
-
if (unusedClassNames.length === 0) return;
|
|
5471
|
-
const selected = unusedClassNames.map((className) => {
|
|
5459
|
+
const selected = Array.from(classNames).map((className) => {
|
|
5472
5460
|
const ruleInfo = registry.rules.get(className);
|
|
5473
5461
|
return ruleInfo ? {
|
|
5474
5462
|
className,
|
|
5475
5463
|
ruleInfo
|
|
5476
5464
|
} : null;
|
|
5477
5465
|
}).filter((entry) => entry != null);
|
|
5466
|
+
if (selected.length === 0) return 0;
|
|
5467
|
+
const deleted = /* @__PURE__ */ new Set();
|
|
5478
5468
|
let cleanedUpCount = 0;
|
|
5479
5469
|
let totalCssSize = 0;
|
|
5480
5470
|
let totalRulesDeleted = 0;
|
|
@@ -5495,7 +5485,7 @@ var SheetManager = class {
|
|
|
5495
5485
|
for (const [_sheetIndex, rulesInSheet] of rulesBySheet) {
|
|
5496
5486
|
rulesInSheet.sort((a, b) => b.ruleInfo.ruleIndex - a.ruleInfo.ruleIndex);
|
|
5497
5487
|
for (const { className, ruleInfo } of rulesInSheet) {
|
|
5498
|
-
if ((registry.
|
|
5488
|
+
if ((registry.pinCounts.get(className) ?? 0) > 0) continue;
|
|
5499
5489
|
if (registry.rules.get(className) !== ruleInfo) continue;
|
|
5500
5490
|
const sheetInfo = registry.sheets[ruleInfo.sheetIndex];
|
|
5501
5491
|
if (!sheetInfo || !sheetInfo.sheet && !sheetInfo.constructableSheet) continue;
|
|
@@ -5507,13 +5497,22 @@ var SheetManager = class {
|
|
|
5507
5497
|
if (startIdx < 0 || endIdx > maxRuleIndex || startIdx > endIdx) continue;
|
|
5508
5498
|
this.deleteRule(registry, ruleInfo);
|
|
5509
5499
|
registry.rules.delete(className);
|
|
5510
|
-
registry.
|
|
5511
|
-
|
|
5512
|
-
for (const [key,
|
|
5513
|
-
|
|
5500
|
+
registry.pinCounts.delete(className);
|
|
5501
|
+
registry.unusedSince.delete(className);
|
|
5502
|
+
for (const [key, entry] of registry.localKeyframes) {
|
|
5503
|
+
if (!entry.owners.delete(className)) continue;
|
|
5504
|
+
if (entry.owners.size === 0) {
|
|
5505
|
+
entry.dispose();
|
|
5506
|
+
registry.localKeyframes.delete(key);
|
|
5507
|
+
}
|
|
5508
|
+
}
|
|
5509
|
+
deleted.add(className);
|
|
5514
5510
|
cleanedUpCount++;
|
|
5515
5511
|
}
|
|
5516
5512
|
}
|
|
5513
|
+
if (deleted.size > 0) {
|
|
5514
|
+
for (const [key, mappedClassName] of registry.cacheKeyToClassName) if (deleted.has(mappedClassName)) registry.cacheKeyToClassName.delete(key);
|
|
5515
|
+
}
|
|
5517
5516
|
if (registry.metrics) {
|
|
5518
5517
|
registry.metrics.bulkCleanups++;
|
|
5519
5518
|
registry.metrics.stylesCleanedUp += cleanedUpCount;
|
|
@@ -5524,6 +5523,7 @@ var SheetManager = class {
|
|
|
5524
5523
|
rulesDeleted: totalRulesDeleted
|
|
5525
5524
|
});
|
|
5526
5525
|
}
|
|
5526
|
+
return cleanedUpCount;
|
|
5527
5527
|
}
|
|
5528
5528
|
/**
|
|
5529
5529
|
* Get total number of rules across all sheets
|
|
@@ -5532,25 +5532,31 @@ var SheetManager = class {
|
|
|
5532
5532
|
return registry.sheets.reduce((total, sheet) => total + sheet.ruleCount - sheet.holes.length, 0);
|
|
5533
5533
|
}
|
|
5534
5534
|
/**
|
|
5535
|
-
*
|
|
5535
|
+
* The CSS of one managed sheet, or `null` when it holds none this can read —
|
|
5536
|
+
* an empty style element, or a sheet the engine refuses to hand over.
|
|
5536
5537
|
*/
|
|
5537
|
-
|
|
5538
|
-
|
|
5539
|
-
|
|
5540
|
-
if (sheetInfo.
|
|
5541
|
-
const rules = Array.from(sheetInfo.constructableSheet.cssRules);
|
|
5542
|
-
cssChunks.push(rules.map((rule) => rule.cssText).join("\n"));
|
|
5543
|
-
} else if (sheetInfo.sheet) {
|
|
5538
|
+
readSheetCSS(sheetInfo) {
|
|
5539
|
+
try {
|
|
5540
|
+
if (sheetInfo.constructableSheet) return Array.from(sheetInfo.constructableSheet.cssRules).map((rule) => rule.cssText).join("\n");
|
|
5541
|
+
if (sheetInfo.sheet) {
|
|
5544
5542
|
const styleElement = sheetInfo.sheet;
|
|
5545
|
-
if (styleElement.textContent)
|
|
5546
|
-
|
|
5547
|
-
const rules = Array.from(styleElement.sheet.cssRules);
|
|
5548
|
-
cssChunks.push(rules.map((rule) => rule.cssText).join("\n"));
|
|
5549
|
-
}
|
|
5543
|
+
if (styleElement.textContent) return styleElement.textContent;
|
|
5544
|
+
if (styleElement.sheet) return Array.from(styleElement.sheet.cssRules).map((rule) => rule.cssText).join("\n");
|
|
5550
5545
|
}
|
|
5551
5546
|
} catch (error) {
|
|
5552
5547
|
console.warn("[Tasty] Failed to read CSS from sheet:", error);
|
|
5553
5548
|
}
|
|
5549
|
+
return null;
|
|
5550
|
+
}
|
|
5551
|
+
/**
|
|
5552
|
+
* Get CSS text from all sheets (for SSR)
|
|
5553
|
+
*/
|
|
5554
|
+
getCSSText(registry) {
|
|
5555
|
+
const cssChunks = [];
|
|
5556
|
+
for (const sheetInfo of registry.sheets) {
|
|
5557
|
+
const css = this.readSheetCSS(sheetInfo);
|
|
5558
|
+
if (css !== null) cssChunks.push(css);
|
|
5559
|
+
}
|
|
5554
5560
|
return cssChunks.join("\n");
|
|
5555
5561
|
}
|
|
5556
5562
|
/**
|
|
@@ -5558,10 +5564,9 @@ var SheetManager = class {
|
|
|
5558
5564
|
*/
|
|
5559
5565
|
getMetrics(registry) {
|
|
5560
5566
|
if (!registry.metrics) return null;
|
|
5561
|
-
const unusedRulesCount = Array.from(registry.refCounts.values()).filter((count) => count === 0).length;
|
|
5562
5567
|
return {
|
|
5563
5568
|
...registry.metrics,
|
|
5564
|
-
unusedHits:
|
|
5569
|
+
unusedHits: 0
|
|
5565
5570
|
};
|
|
5566
5571
|
}
|
|
5567
5572
|
/**
|
|
@@ -5863,6 +5868,49 @@ var SheetManager = class {
|
|
|
5863
5868
|
/**
|
|
5864
5869
|
* Get the raw CSS content
|
|
5865
5870
|
*/
|
|
5871
|
+
/**
|
|
5872
|
+
* The CSS this injector owns in `root`, one entry per sheet, in the order the
|
|
5873
|
+
* engine applies them.
|
|
5874
|
+
*
|
|
5875
|
+
* `getCSSText()` walks the managed sheets only, and raw CSS has its own —
|
|
5876
|
+
* which sits before, after, or *between* them depending on how it got there:
|
|
5877
|
+
* prepended to `adoptedStyleSheets`, or wherever in `<head>` the first raw
|
|
5878
|
+
* injection happened to land, with every managed sheet opened afterwards
|
|
5879
|
+
* following it. Reporting a fixed order would describe the opposite winner
|
|
5880
|
+
* from the live page whenever two rules of equal specificity meet, so the raw
|
|
5881
|
+
* sheet is spliced in at the position the DOM actually gives it.
|
|
5882
|
+
*/
|
|
5883
|
+
getOwnedCSSInOrder(registry, root) {
|
|
5884
|
+
const raw = this.getRawCSSText(root);
|
|
5885
|
+
const rawElement = this.isAdoptedMode(root) ? null : this.rawStyleElements.get(root);
|
|
5886
|
+
let rawIndex = raw && !rawElement ? 0 : -1;
|
|
5887
|
+
const chunks = [];
|
|
5888
|
+
for (const sheetInfo of registry.sheets) {
|
|
5889
|
+
const css = this.readSheetCSS(sheetInfo);
|
|
5890
|
+
if (css === null) continue;
|
|
5891
|
+
if (rawIndex < 0 && rawElement && sheetInfo.sheet && rawElement.compareDocumentPosition(sheetInfo.sheet) & Node.DOCUMENT_POSITION_FOLLOWING) rawIndex = chunks.length;
|
|
5892
|
+
chunks.push(css);
|
|
5893
|
+
}
|
|
5894
|
+
if (!raw) return chunks;
|
|
5895
|
+
chunks.splice(rawIndex < 0 ? chunks.length : rawIndex, 0, raw);
|
|
5896
|
+
return chunks;
|
|
5897
|
+
}
|
|
5898
|
+
/**
|
|
5899
|
+
* Top-level rules in the raw sheet.
|
|
5900
|
+
*
|
|
5901
|
+
* Read from the sheet the engine parsed, not from the text: a raw block is
|
|
5902
|
+
* one string but any number of rules, and one rule — `@keyframes`, `@media` —
|
|
5903
|
+
* can contain any number of blocks, so counting braces answers neither
|
|
5904
|
+
* question.
|
|
5905
|
+
*/
|
|
5906
|
+
getRawRuleCount(root) {
|
|
5907
|
+
const sheet = this.isAdoptedMode(root) ? this.rawConstructableSheets.get(root) : this.rawStyleElements.get(root)?.sheet;
|
|
5908
|
+
try {
|
|
5909
|
+
return sheet?.cssRules.length ?? 0;
|
|
5910
|
+
} catch {
|
|
5911
|
+
return 0;
|
|
5912
|
+
}
|
|
5913
|
+
}
|
|
5866
5914
|
getRawCSSText(root) {
|
|
5867
5915
|
if (this.isAdoptedMode(root)) {
|
|
5868
5916
|
const blocksMap = this.rawCSSBlocks.get(root);
|
|
@@ -5985,6 +6033,13 @@ function formatCounterStyleRule(name, descriptors) {
|
|
|
5985
6033
|
//#endregion
|
|
5986
6034
|
//#region src/injector/injector.ts
|
|
5987
6035
|
/**
|
|
6036
|
+
* How long a class is left alone after it was last known to be wanted.
|
|
6037
|
+
* Long enough that a render cannot plausibly still be waiting to commit one.
|
|
6038
|
+
*/
|
|
6039
|
+
const DEFAULT_GC_GRACE = 1e4;
|
|
6040
|
+
/** Dispose handle handed back for injections that took no pin. */
|
|
6041
|
+
const noop = () => {};
|
|
6042
|
+
/**
|
|
5988
6043
|
* Placeholder `KeyframesInfo` for a cache entry reserved by a batched write and
|
|
5989
6044
|
* not yet backed by a real rule. Only ever read through `entry.pending`, which
|
|
5990
6045
|
* is checked before the info is used.
|
|
@@ -6041,13 +6096,14 @@ function registerHydratedClass(registry, className) {
|
|
|
6041
6096
|
ruleIndex: -2,
|
|
6042
6097
|
sheetIndex: -2
|
|
6043
6098
|
});
|
|
6044
|
-
registry.
|
|
6099
|
+
registry.pinCounts.set(className, 0);
|
|
6045
6100
|
}
|
|
6046
6101
|
var StyleInjector = class {
|
|
6047
6102
|
sheetManager;
|
|
6048
6103
|
config;
|
|
6049
6104
|
globalRuleCounter = 0;
|
|
6050
|
-
|
|
6105
|
+
/** Cancels the scheduled sweep, whichever timer scheduled it. */
|
|
6106
|
+
cancelPendingGC = null;
|
|
6051
6107
|
namePrefix;
|
|
6052
6108
|
classRegex;
|
|
6053
6109
|
rscClassRegex;
|
|
@@ -6176,6 +6232,7 @@ var StyleInjector = class {
|
|
|
6176
6232
|
inject(rules, options) {
|
|
6177
6233
|
const root = options?.root || document;
|
|
6178
6234
|
const registry = this.sheetManager.getRegistry(root);
|
|
6235
|
+
const pin = options?.pin ?? true;
|
|
6179
6236
|
if (rules.length === 0) return {
|
|
6180
6237
|
className: "",
|
|
6181
6238
|
dispose: () => {}
|
|
@@ -6186,30 +6243,34 @@ var StyleInjector = class {
|
|
|
6186
6243
|
className = registry.cacheKeyToClassName.get(cacheKey);
|
|
6187
6244
|
const existingRuleInfo = registry.rules.get(className);
|
|
6188
6245
|
if (existingRuleInfo.ruleIndex === -3) {
|
|
6189
|
-
registry.
|
|
6246
|
+
registry.unusedSince.delete(className);
|
|
6247
|
+
if (pin) registry.pinCounts.set(className, (registry.pinCounts.get(className) || 0) + 1);
|
|
6190
6248
|
if (registry.metrics) registry.metrics.hits++;
|
|
6191
6249
|
return {
|
|
6192
6250
|
className,
|
|
6193
|
-
dispose: () => this.
|
|
6251
|
+
dispose: pin ? () => this.unpin(className, registry) : noop
|
|
6194
6252
|
};
|
|
6195
6253
|
}
|
|
6196
6254
|
if (!(existingRuleInfo.ruleIndex === -1 && existingRuleInfo.sheetIndex === -1)) {
|
|
6197
|
-
|
|
6198
|
-
|
|
6255
|
+
registry.unusedSince.delete(className);
|
|
6256
|
+
if (pin) {
|
|
6257
|
+
const pins = registry.pinCounts.get(className) || 0;
|
|
6258
|
+
registry.pinCounts.set(className, pins + 1);
|
|
6259
|
+
}
|
|
6199
6260
|
if (registry.metrics) registry.metrics.hits++;
|
|
6200
6261
|
return {
|
|
6201
6262
|
className,
|
|
6202
|
-
dispose: () => this.
|
|
6263
|
+
dispose: pin ? () => this.unpin(className, registry) : noop
|
|
6203
6264
|
};
|
|
6204
6265
|
}
|
|
6205
6266
|
} else if (cacheKey) {
|
|
6206
6267
|
className = this.generateClassName(cacheKey);
|
|
6207
6268
|
if (this.tryHydratedHit(registry, cacheKey, className)) {
|
|
6208
|
-
registry.
|
|
6269
|
+
if (pin) registry.pinCounts.set(className, (registry.pinCounts.get(className) || 0) + 1);
|
|
6209
6270
|
if (registry.metrics) registry.metrics.hits++;
|
|
6210
6271
|
return {
|
|
6211
6272
|
className,
|
|
6212
|
-
dispose: () => this.
|
|
6273
|
+
dispose: pin ? () => this.unpin(className, registry) : noop
|
|
6213
6274
|
};
|
|
6214
6275
|
}
|
|
6215
6276
|
} else {
|
|
@@ -6270,7 +6331,8 @@ var StyleInjector = class {
|
|
|
6270
6331
|
sheetIndex: -3
|
|
6271
6332
|
});
|
|
6272
6333
|
if (cacheKey) registry.cacheKeyToClassName.set(cacheKey, className);
|
|
6273
|
-
registry.
|
|
6334
|
+
if (pin) registry.pinCounts.set(className, 1);
|
|
6335
|
+
registry.unusedSince.set(className, Date.now());
|
|
6274
6336
|
const queued = enqueueStyleWrite(() => {
|
|
6275
6337
|
if (applySheetWrite()) return;
|
|
6276
6338
|
registry.rules.set(className, {
|
|
@@ -6281,26 +6343,27 @@ var StyleInjector = class {
|
|
|
6281
6343
|
});
|
|
6282
6344
|
return {
|
|
6283
6345
|
className,
|
|
6284
|
-
dispose: () => {
|
|
6285
|
-
if (!queued.done && registry.
|
|
6346
|
+
dispose: pin ? () => {
|
|
6347
|
+
if (!queued.done && registry.pinCounts.get(className) === 1 && registry.rules.get(className)?.ruleIndex === -3) {
|
|
6286
6348
|
queued.cancelled = true;
|
|
6287
6349
|
registry.rules.delete(className);
|
|
6288
6350
|
if (cacheKey) registry.cacheKeyToClassName.delete(cacheKey);
|
|
6289
|
-
registry.
|
|
6351
|
+
registry.pinCounts.set(className, 0);
|
|
6290
6352
|
return;
|
|
6291
6353
|
}
|
|
6292
|
-
this.
|
|
6293
|
-
}
|
|
6354
|
+
this.unpin(className, registry);
|
|
6355
|
+
} : noop
|
|
6294
6356
|
};
|
|
6295
6357
|
}
|
|
6296
6358
|
if (!applySheetWrite()) return {
|
|
6297
6359
|
className,
|
|
6298
6360
|
dispose: () => {}
|
|
6299
6361
|
};
|
|
6300
|
-
registry.
|
|
6362
|
+
if (pin) registry.pinCounts.set(className, 1);
|
|
6363
|
+
registry.unusedSince.set(className, Date.now());
|
|
6301
6364
|
return {
|
|
6302
6365
|
className,
|
|
6303
|
-
dispose: () => this.
|
|
6366
|
+
dispose: pin ? () => this.unpin(className, registry) : noop
|
|
6304
6367
|
};
|
|
6305
6368
|
}
|
|
6306
6369
|
/**
|
|
@@ -6380,41 +6443,86 @@ var StyleInjector = class {
|
|
|
6380
6443
|
return this.sheetManager.getRawCSSText(root);
|
|
6381
6444
|
}
|
|
6382
6445
|
/**
|
|
6383
|
-
*
|
|
6384
|
-
*
|
|
6385
|
-
*
|
|
6386
|
-
*
|
|
6446
|
+
* Take a reference on local `@keyframes`, under the deterministic names the
|
|
6447
|
+
* caller resolved.
|
|
6448
|
+
*
|
|
6449
|
+
* One reference per distinct set of steps, shared by every class that ends up
|
|
6450
|
+
* animating it, so a repeat render takes nothing further. Ownership is
|
|
6451
|
+
* assigned by `ownKeyframes()` once the rules exist to be inspected.
|
|
6452
|
+
*/
|
|
6453
|
+
holdKeyframes(steps, names, options) {
|
|
6454
|
+
const root = options?.root || document;
|
|
6455
|
+
const registry = this.sheetManager.getRegistry(root);
|
|
6456
|
+
const keys = /* @__PURE__ */ new Map();
|
|
6457
|
+
for (const [authored, definition] of Object.entries(steps)) {
|
|
6458
|
+
const resolved = names.get(authored) ?? authored;
|
|
6459
|
+
let entry = registry.localKeyframes.get(resolved);
|
|
6460
|
+
if (!entry) {
|
|
6461
|
+
const injected = this.keyframes(definition, {
|
|
6462
|
+
name: resolved,
|
|
6463
|
+
root,
|
|
6464
|
+
distinctByName: true
|
|
6465
|
+
});
|
|
6466
|
+
entry = {
|
|
6467
|
+
name: injected.toString(),
|
|
6468
|
+
dispose: injected.dispose,
|
|
6469
|
+
owners: /* @__PURE__ */ new Set()
|
|
6470
|
+
};
|
|
6471
|
+
registry.localKeyframes.set(resolved, entry);
|
|
6472
|
+
}
|
|
6473
|
+
keys.set(authored, resolved);
|
|
6474
|
+
}
|
|
6475
|
+
return keys;
|
|
6476
|
+
}
|
|
6477
|
+
/**
|
|
6478
|
+
* Record that `className` animates these keyframes, so the reference is
|
|
6479
|
+
* released when the last such class is collected.
|
|
6480
|
+
*
|
|
6481
|
+
* Only classes whose rules actually reference the animation should be here:
|
|
6482
|
+
* a class that merely rendered alongside one would otherwise keep the
|
|
6483
|
+
* keyframes alive for as long as it lives.
|
|
6484
|
+
*/
|
|
6485
|
+
ownKeyframes(key, className, options) {
|
|
6486
|
+
this.sheetManager.getRegistry(options?.root || document).localKeyframes.get(key)?.owners.add(className);
|
|
6487
|
+
}
|
|
6488
|
+
/**
|
|
6489
|
+
* Pin an already-injected cacheKey and return the handle that releases it.
|
|
6490
|
+
* For callers that skipped the pipeline on a cache hit but still need the
|
|
6491
|
+
* class held. Returns null if the cacheKey is not found.
|
|
6387
6492
|
*/
|
|
6388
6493
|
trackRef(cacheKey, options) {
|
|
6389
6494
|
const root = options?.root || document;
|
|
6390
6495
|
const registry = this.sheetManager.getRegistry(root);
|
|
6391
6496
|
if (!registry.cacheKeyToClassName.has(cacheKey)) return null;
|
|
6392
6497
|
const className = registry.cacheKeyToClassName.get(cacheKey);
|
|
6393
|
-
const
|
|
6394
|
-
registry.
|
|
6498
|
+
const pins = registry.pinCounts.get(className) || 0;
|
|
6499
|
+
registry.pinCounts.set(className, pins + 1);
|
|
6395
6500
|
if (registry.metrics) registry.metrics.hits++;
|
|
6396
6501
|
return {
|
|
6397
6502
|
className,
|
|
6398
|
-
dispose: () => this.
|
|
6503
|
+
dispose: () => this.unpin(className, registry)
|
|
6399
6504
|
};
|
|
6400
6505
|
}
|
|
6401
6506
|
/**
|
|
6402
|
-
*
|
|
6507
|
+
* Release one pin on a className. At zero pins the class is not deleted — it
|
|
6508
|
+
* stays cached and collectible, and `gc()` decides when it actually goes.
|
|
6403
6509
|
*/
|
|
6404
|
-
|
|
6405
|
-
const
|
|
6406
|
-
if (
|
|
6407
|
-
const
|
|
6408
|
-
registry.
|
|
6409
|
-
if (
|
|
6510
|
+
unpin(className, registry) {
|
|
6511
|
+
const pins = registry.pinCounts.get(className);
|
|
6512
|
+
if (pins == null || pins <= 0) return;
|
|
6513
|
+
const remaining = pins - 1;
|
|
6514
|
+
registry.pinCounts.set(className, remaining);
|
|
6515
|
+
if (remaining === 0 && registry.metrics) registry.metrics.totalUnused++;
|
|
6410
6516
|
}
|
|
6411
6517
|
/**
|
|
6412
|
-
*
|
|
6518
|
+
* Remove every style that is neither in the DOM nor referenced by an
|
|
6519
|
+
* outstanding `inject()` handle, ignoring the GC capacity threshold.
|
|
6413
6520
|
*/
|
|
6414
6521
|
cleanup(root) {
|
|
6415
|
-
|
|
6416
|
-
|
|
6417
|
-
|
|
6522
|
+
this.gc({
|
|
6523
|
+
root,
|
|
6524
|
+
force: true
|
|
6525
|
+
});
|
|
6418
6526
|
}
|
|
6419
6527
|
/**
|
|
6420
6528
|
* Get CSS text from all sheets (for SSR)
|
|
@@ -6457,7 +6565,9 @@ var StyleInjector = class {
|
|
|
6457
6565
|
flushStyles();
|
|
6458
6566
|
const root = options?.root || document;
|
|
6459
6567
|
const registry = this.sheetManager.getRegistry(root);
|
|
6460
|
-
|
|
6568
|
+
const metrics = this.sheetManager.getMetrics(registry);
|
|
6569
|
+
if (metrics && typeof document !== "undefined") metrics.unusedHits = this.collectUnused(registry, root).length;
|
|
6570
|
+
return metrics;
|
|
6461
6571
|
}
|
|
6462
6572
|
/**
|
|
6463
6573
|
* Reset cache performance metrics
|
|
@@ -6631,13 +6741,14 @@ var StyleInjector = class {
|
|
|
6631
6741
|
keyframes(steps, nameOrOptions) {
|
|
6632
6742
|
const isStringName = typeof nameOrOptions === "string";
|
|
6633
6743
|
const providedName = isStringName ? nameOrOptions : nameOrOptions?.name;
|
|
6744
|
+
const distinctByName = isStringName ? false : nameOrOptions?.distinctByName ?? false;
|
|
6634
6745
|
const root = isStringName ? document : nameOrOptions?.root || document;
|
|
6635
6746
|
const registry = this.sheetManager.getRegistry(root);
|
|
6636
6747
|
if (Object.keys(steps).length === 0) return {
|
|
6637
6748
|
toString: () => "",
|
|
6638
6749
|
dispose: () => {}
|
|
6639
6750
|
};
|
|
6640
|
-
const contentHash = JSON.stringify(steps);
|
|
6751
|
+
const contentHash = distinctByName && providedName ? `${providedName}\u0000${JSON.stringify(steps)}` : JSON.stringify(steps);
|
|
6641
6752
|
const existing = registry.keyframesCache.get(contentHash);
|
|
6642
6753
|
if (existing) {
|
|
6643
6754
|
existing.refCount++;
|
|
@@ -6729,108 +6840,132 @@ var StyleInjector = class {
|
|
|
6729
6840
|
}
|
|
6730
6841
|
}
|
|
6731
6842
|
/**
|
|
6732
|
-
*
|
|
6733
|
-
*
|
|
6734
|
-
*
|
|
6735
|
-
*
|
|
6736
|
-
*
|
|
6843
|
+
* Count a render, and schedule a collection pass every `touchInterval` of
|
|
6844
|
+
* them. Nothing else: what a class is worth keeping is decided by the sweep's
|
|
6845
|
+
* own DOM scan, so rendering does not track usage at all.
|
|
6846
|
+
*
|
|
6847
|
+
* @deprecated The class name is ignored — pass anything, or stop calling it.
|
|
6848
|
+
* Collection no longer records per-class usage, and scheduling does not need
|
|
6849
|
+
* to know which class was rendered. A class handed back by `inject()` is
|
|
6850
|
+
* marked wanted there, which is what reuse actually goes through.
|
|
6737
6851
|
*/
|
|
6738
|
-
touch(
|
|
6852
|
+
touch(_className, options) {
|
|
6739
6853
|
if (typeof document === "undefined") return;
|
|
6740
6854
|
if (!this.config.gc) return;
|
|
6741
|
-
const
|
|
6742
|
-
|
|
6743
|
-
const now = Date.now();
|
|
6744
|
-
if (registry.touchTick !== now) {
|
|
6745
|
-
registry.touchTick = now;
|
|
6746
|
-
registry.touchedTick.clear();
|
|
6747
|
-
} else if (registry.touchedTick.has(className)) return;
|
|
6748
|
-
registry.touchedTick.add(className);
|
|
6749
|
-
const parts = className.indexOf(" ") === -1 ? [className] : className.split(" ");
|
|
6750
|
-
for (const cls of parts) {
|
|
6751
|
-
if (!this.classRegex.test(cls)) continue;
|
|
6752
|
-
if (!registry.rules.has(cls)) continue;
|
|
6753
|
-
const entry = registry.usageMap.get(cls);
|
|
6754
|
-
if (entry) entry.lastTouchedAt = now;
|
|
6755
|
-
else registry.usageMap.set(cls, { lastTouchedAt: now });
|
|
6756
|
-
registry.touchCount++;
|
|
6757
|
-
}
|
|
6758
|
-
const touchInterval = this.config.gc.touchInterval ?? 1e3;
|
|
6759
|
-
if (registry.touchCount >= touchInterval) {
|
|
6855
|
+
const registry = this.sheetManager.getRegistry(options?.root || document);
|
|
6856
|
+
if (++registry.touchCount >= (this.config.gc.touchInterval ?? 1e3)) {
|
|
6760
6857
|
registry.touchCount = 0;
|
|
6761
6858
|
this.scheduleGC();
|
|
6762
6859
|
}
|
|
6763
6860
|
}
|
|
6764
6861
|
/**
|
|
6765
|
-
* Schedule a GC
|
|
6766
|
-
*
|
|
6862
|
+
* Schedule a GC in idle time. Runs GC on all active roots, and avoids
|
|
6863
|
+
* double-scheduling.
|
|
6864
|
+
*
|
|
6865
|
+
* Idle only. Without `requestIdleCallback` nothing is collected
|
|
6866
|
+
* automatically: running the sweep inline here would put it inside the render
|
|
6867
|
+
* that touched the class, and collection is never urgent enough for that.
|
|
6767
6868
|
*/
|
|
6768
6869
|
scheduleGC() {
|
|
6769
|
-
if (this.
|
|
6870
|
+
if (this.cancelPendingGC) return;
|
|
6770
6871
|
const runGC = () => {
|
|
6771
|
-
this.
|
|
6872
|
+
this.cancelPendingGC = null;
|
|
6772
6873
|
this.sheetManager.pruneDisconnectedRoots();
|
|
6773
6874
|
for (const root of this.sheetManager.getActiveRoots()) this.gc({ root });
|
|
6774
6875
|
};
|
|
6775
|
-
if (typeof requestIdleCallback !== "undefined")
|
|
6776
|
-
|
|
6876
|
+
if (typeof requestIdleCallback !== "undefined") {
|
|
6877
|
+
const handle = requestIdleCallback(() => runGC());
|
|
6878
|
+
this.cancelPendingGC = () => cancelIdleCallback(handle);
|
|
6879
|
+
}
|
|
6880
|
+
}
|
|
6881
|
+
/**
|
|
6882
|
+
* The one definition of "unused": this injector owns the class's rules, no
|
|
6883
|
+
* element in `root` carries it, and nobody pinned it.
|
|
6884
|
+
*
|
|
6885
|
+
* `gc()` evicts from this set, `getMetrics()` counts it, and `tastyDebug`
|
|
6886
|
+
* reports it — all through here, so the three can never disagree about what
|
|
6887
|
+
* "unused" means. Entries carry their last `touch()` so callers can drop the
|
|
6888
|
+
* oldest first; a class that was never touched sorts as oldest.
|
|
6889
|
+
*/
|
|
6890
|
+
/**
|
|
6891
|
+
* Everything the injector holds falls into one of five bands, and only the
|
|
6892
|
+
* last of them is ever deleted:
|
|
6893
|
+
*
|
|
6894
|
+
* 1. rendered — some element carries the class right now
|
|
6895
|
+
* 2. not ours — queued for a batched write, pre-allocated, or server-rendered
|
|
6896
|
+
* 3. hot — nothing carries it, but that was noticed less than `grace` ago
|
|
6897
|
+
* 4. cached — cold, but within `capacity` when ordered by when it went cold
|
|
6898
|
+
* 5. the rest
|
|
6899
|
+
*
|
|
6900
|
+
* This returns bands 4 and 5 together, most recently cold first; `gc()` draws
|
|
6901
|
+
* the capacity line through them. Band 3 is what makes collection safe
|
|
6902
|
+
* without a commit signal: a render can resolve a class and commit it a
|
|
6903
|
+
* little later, and during that gap nothing on the page carries it.
|
|
6904
|
+
*/
|
|
6905
|
+
collectUnused(registry, root) {
|
|
6906
|
+
const now = Date.now();
|
|
6907
|
+
const grace = this.config.gc?.grace ?? DEFAULT_GC_GRACE;
|
|
6908
|
+
const liveClasses = /* @__PURE__ */ new Set();
|
|
6909
|
+
for (const el of root.querySelectorAll("[class]")) for (const token of el.classList) if (this.classRegex.test(token)) liveClasses.add(token);
|
|
6910
|
+
const unused = [];
|
|
6911
|
+
for (const [className, ruleInfo] of registry.rules) {
|
|
6912
|
+
if (ruleInfo.sheetIndex < 0) continue;
|
|
6913
|
+
if (liveClasses.has(className)) {
|
|
6914
|
+
registry.unusedSince.delete(className);
|
|
6915
|
+
continue;
|
|
6916
|
+
}
|
|
6917
|
+
if ((registry.pinCounts.get(className) ?? 0) > 0) continue;
|
|
6918
|
+
let since = registry.unusedSince.get(className);
|
|
6919
|
+
if (since === void 0) {
|
|
6920
|
+
since = now;
|
|
6921
|
+
registry.unusedSince.set(className, now);
|
|
6922
|
+
}
|
|
6923
|
+
if (now - since < grace) continue;
|
|
6924
|
+
unused.push(className);
|
|
6925
|
+
}
|
|
6926
|
+
unused.sort((a, b) => (registry.unusedSince.get(b) ?? 0) - (registry.unusedSince.get(a) ?? 0));
|
|
6927
|
+
return unused;
|
|
6928
|
+
}
|
|
6929
|
+
/**
|
|
6930
|
+
* Class names this injector holds CSS for that nothing renders and nobody
|
|
6931
|
+
* pinned — exactly what `gc({ force: true })` would delete. Unordered.
|
|
6932
|
+
*/
|
|
6933
|
+
getUnusedClasses(options) {
|
|
6934
|
+
flushStyles();
|
|
6935
|
+
if (typeof document === "undefined") return [];
|
|
6936
|
+
const root = options?.root || document;
|
|
6937
|
+
const registry = this.sheetManager.getRegistry(root);
|
|
6938
|
+
return this.collectUnused(registry, root);
|
|
6777
6939
|
}
|
|
6778
6940
|
/**
|
|
6779
6941
|
* Synchronous garbage collection.
|
|
6780
6942
|
*
|
|
6781
|
-
* 1. Quick upper-bound check: skip if
|
|
6782
|
-
* 2. Scans the DOM for live tasty classNames
|
|
6783
|
-
*
|
|
6784
|
-
*
|
|
6943
|
+
* 1. Quick upper-bound check: skip if the registry is smaller than capacity.
|
|
6944
|
+
* 2. Scans the DOM for live tasty classNames — the DOM, not a ref count, is
|
|
6945
|
+
* what says a class rendered by a component is still in use.
|
|
6946
|
+
* 3. With `force: true`: deletes every unused class.
|
|
6947
|
+
* Without `force`: keeps the `capacity` most recently touched and deletes
|
|
6948
|
+
* the rest, oldest first.
|
|
6785
6949
|
*
|
|
6786
6950
|
* @returns Number of styles evicted.
|
|
6787
6951
|
*/
|
|
6788
6952
|
gc(options) {
|
|
6789
6953
|
flushStyles();
|
|
6790
6954
|
if (typeof document === "undefined") return 0;
|
|
6791
|
-
|
|
6792
|
-
|
|
6793
|
-
this.pendingGCHandle = null;
|
|
6794
|
-
}
|
|
6955
|
+
this.cancelPendingGC?.();
|
|
6956
|
+
this.cancelPendingGC = null;
|
|
6795
6957
|
const root = options?.root || document;
|
|
6796
|
-
const force = options?.force
|
|
6958
|
+
const force = options?.force;
|
|
6797
6959
|
const registry = this.sheetManager.getRegistry(root);
|
|
6798
6960
|
const capacity = this.config.gc?.capacity ?? 1e3;
|
|
6799
|
-
if (!force)
|
|
6800
|
-
|
|
6801
|
-
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
|
|
6805
|
-
|
|
6806
|
-
|
|
6807
|
-
if (force) for (const [className] of registry.usageMap) {
|
|
6808
|
-
if (liveClasses.has(className)) continue;
|
|
6809
|
-
if ((registry.refCounts.get(className) ?? 0) > 0) continue;
|
|
6810
|
-
registry.usageMap.delete(className);
|
|
6811
|
-
swept++;
|
|
6812
|
-
}
|
|
6813
|
-
else {
|
|
6814
|
-
const unused = [];
|
|
6815
|
-
for (const [className, usage] of registry.usageMap) {
|
|
6816
|
-
if (liveClasses.has(className)) continue;
|
|
6817
|
-
if ((registry.refCounts.get(className) ?? 0) > 0) continue;
|
|
6818
|
-
unused.push({
|
|
6819
|
-
className,
|
|
6820
|
-
lastTouchedAt: usage.lastTouchedAt
|
|
6821
|
-
});
|
|
6822
|
-
}
|
|
6823
|
-
if (unused.length > capacity) {
|
|
6824
|
-
unused.sort((a, b) => a.lastTouchedAt - b.lastTouchedAt);
|
|
6825
|
-
const toEvict = unused.length - capacity;
|
|
6826
|
-
for (let i = 0; i < toEvict; i++) {
|
|
6827
|
-
registry.usageMap.delete(unused[i].className);
|
|
6828
|
-
swept++;
|
|
6829
|
-
}
|
|
6830
|
-
}
|
|
6831
|
-
}
|
|
6832
|
-
if (swept > 0) this.sheetManager.forceCleanup(registry);
|
|
6833
|
-
return swept;
|
|
6961
|
+
if (!force && registry.rules.size <= capacity) return 0;
|
|
6962
|
+
const unused = this.collectUnused(registry, root);
|
|
6963
|
+
let doomed;
|
|
6964
|
+
if (force) doomed = unused;
|
|
6965
|
+
else if (unused.length > capacity) doomed = unused.slice(capacity);
|
|
6966
|
+
else return 0;
|
|
6967
|
+
if (doomed.length === 0) return 0;
|
|
6968
|
+
return this.sheetManager.deleteClasses(registry, doomed);
|
|
6834
6969
|
}
|
|
6835
6970
|
/**
|
|
6836
6971
|
* Destroy all resources for a root
|
|
@@ -6839,9 +6974,9 @@ var StyleInjector = class {
|
|
|
6839
6974
|
flushStyles();
|
|
6840
6975
|
const targetRoot = root || document;
|
|
6841
6976
|
this.sheetManager.cleanup(targetRoot);
|
|
6842
|
-
if (this.
|
|
6843
|
-
|
|
6844
|
-
this.
|
|
6977
|
+
if (this.cancelPendingGC && !this.sheetManager.hasActiveRoots()) {
|
|
6978
|
+
this.cancelPendingGC();
|
|
6979
|
+
this.cancelPendingGC = null;
|
|
6845
6980
|
}
|
|
6846
6981
|
}
|
|
6847
6982
|
};
|
|
@@ -11714,7 +11849,7 @@ function createDefaultConfig(isTest) {
|
|
|
11714
11849
|
function markStylesGenerated() {
|
|
11715
11850
|
if (stylesGenerated) return;
|
|
11716
11851
|
stylesGenerated = true;
|
|
11717
|
-
if (typeof document !== "undefined" && document.querySelector("
|
|
11852
|
+
if (typeof document !== "undefined" && document.querySelector("[data-tasty-ssr]")) {
|
|
11718
11853
|
warnOnce("ssr-globals-skip", "[Tasty] SSR styles detected — skipping client-side global CSS injection to avoid duplicates.");
|
|
11719
11854
|
return;
|
|
11720
11855
|
}
|
|
@@ -12283,4 +12418,4 @@ function resetConfig() {
|
|
|
12283
12418
|
//#endregion
|
|
12284
12419
|
export { SheetManager as $, StyleParser as $t, FLOW_STYLES as A, STYLE_TO_CHUNK as At, createStateParserContext as B, getGlobalParseFunctions as Bt, BASE_STYLES as C, APPEARANCE_CHUNK_STYLES as Ct, COLOR_STYLES as D, FONT_CHUNK_STYLES as Dt, BLOCK_STYLES as E, DISPLAY_CHUNK_STYLES as Et, hasPipelineCacheEntry as F, registerFunctionPolyfill as Ft, StyleInjector as G, parseStyle as Gt, extractPredefinedStateRefs as H, getGlobalPredefinedTokens as Ht, isSelector as I, registerLocalFunctionPolyfills as It, hasLocalCounterStyle as J, okhstPlugin as Jt, extractLocalCounterStyle as K, stringifyStyles as Kt, renderStyles as L, CUSTOM_UNITS as Lt, OUTER_STYLES as M, formatFunctionRule as Mt, POSITION_STYLES as N, hasLocalFunctions as Nt, CONTAINER_STYLES as O, LAYOUT_CHUNK_STYLES as Ot, TEXT_STYLES as P, parseFunctionName as Pt, hasLocalFontFace as Q, isDevEnv as Qt, parseStateKey as R, DIRECTIONS as Rt, baseStylePropsRegistry as S, propHandlerRegistry as St, BLOCK_OUTER_STYLES as T, DIMENSION_CHUNK_STYLES as Tt, getGlobalPredefinedStates as U, normalizeColorTokenValue as Ut, extractLocalPredefinedStates as V, getGlobalParser as Vt, setGlobalPredefinedStates as W, parseColor as Wt, fontFaceContentHash as X, okhslPlugin as Xt, extractLocalFontFace as Y, okhslFunction as Yt, formatFontFaceRule as Z, createColorFunc as Zt, isFunctionsPolyfillEnabled as _, hashString as _t, getGlobalCounterStyles as a, hslToRgbValues as an, closeBatchWindow as at, resetConfig as b, hasLocalProperties as bt, getGlobalInjector as c, openBatchWindow as ct, getGlobalStyles as d, DEFAULT_ZERO_NAME_PREFIX as dt, Lru as en, STYLE_HANDLER_MAP as et, getNamePrefix as f, makeClassName as ft, isConfigLocked as g, validateNamePrefix as gt, hasStylesGenerated as h, tastyClassRegex as ht, getGlobalConfigTokens as i, hexToRgb as in, PropertyTypeResolver as it, INNER_STYLES as j, extractLocalFunctions as jt, DIMENSION_STYLES as k, POSITION_CHUNK_STYLES as kt, getGlobalKeyframes as l, resetStyleBatch as lt, hasGlobalRecipes as m, makeKeyframeName as mt, getConfig as n, getNamedColorHex as nn, styleHandlers as nt, getGlobalFontFaces as o, strToRgb as on, flushStyles as ot, hasGlobalKeyframes as p, makeCounterStyleName as pt, formatCounterStyleRule as q, okhstFunction as qt, getEffectiveProperties as r, getRgbValuesFromRgbaString as rn, createStyle as rt, getGlobalFunctions as s, normalizeDslName as sn, hasPendingStyleWrites as st, configure as t, overrideColorAlpha as tn, defineHandler as tt, getGlobalRecipes as u, DEFAULT_NAME_PREFIX as ut, isTestEnvironment as v, extractLocalProperties as vt, BLOCK_INNER_STYLES as w, CHUNK_NAMES as wt, generateTypographyTokens as x, parsePropertyToken as xt, markStylesGenerated as y, getEffectiveDefinition as yt, camelToKebab as z, filterMods as zt };
|
|
12285
12420
|
|
|
12286
|
-
//# sourceMappingURL=config-
|
|
12421
|
+
//# sourceMappingURL=config-B3gPdCqd.js.map
|