@tenphi/tasty 3.4.0 → 3.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.
Files changed (83) hide show
  1. package/README.md +147 -129
  2. package/dist/astro-CzY4LCpr.js +437 -0
  3. package/dist/astro-CzY4LCpr.js.map +1 -0
  4. package/dist/{babel-BUQGeOXA.d.ts → babel-DWCsafYw.d.ts} +2 -2
  5. package/dist/{collector-DUaHCcTS.d.ts → collector-BTVXj2hS.d.ts} +21 -3
  6. package/dist/{collector-DTahQUiV.js → collector-C6TtL8HJ.js} +36 -13
  7. package/dist/collector-C6TtL8HJ.js.map +1 -0
  8. package/dist/{config-B5kHzuNz.js → config-B3gPdCqd.js} +305 -153
  9. package/dist/config-B3gPdCqd.js.map +1 -0
  10. package/dist/{config-YsxGv4tq.d.ts → config-LfIDmVHx.d.ts} +132 -32
  11. package/dist/core/index.d.ts +5 -5
  12. package/dist/core/index.js +6 -6
  13. package/dist/{core-Dr4u1NVD.js → core-Bq7w2kti.js} +215 -95
  14. package/dist/core-Bq7w2kti.js.map +1 -0
  15. package/dist/{css-writer-B-J87ncv.js → css-writer-Bgowobbx.js} +3 -3
  16. package/dist/{css-writer-B-J87ncv.js.map → css-writer-Bgowobbx.js.map} +1 -1
  17. package/dist/{format-rules-DKOA-6qu.js → format-rules-rCZ37rqY.js} +2 -2
  18. package/dist/format-rules-rCZ37rqY.js.map +1 -0
  19. package/dist/{hydrate-OeMX99We.js → hydrate-CNOmZprz.js} +3 -3
  20. package/dist/{hydrate-OeMX99We.js.map → hydrate-CNOmZprz.js.map} +1 -1
  21. package/dist/{index-PqN-DIpn.d.ts → index-Bm9ltvdH.d.ts} +38 -16
  22. package/dist/{index-Cd45t5NM.d.ts → index-BmogEzTo.d.ts} +69 -15
  23. package/dist/index.d.ts +5 -5
  24. package/dist/index.js +7 -7
  25. package/dist/index.js.map +1 -1
  26. package/dist/{keyframes-CV8azJf3.js → keyframes-DE-OE76F.js} +45 -3
  27. package/dist/keyframes-DE-OE76F.js.map +1 -0
  28. package/dist/{merge-styles-CU7JbEwg.d.ts → merge-styles-BcLl1u_d.d.ts} +2 -2
  29. package/dist/{merge-styles-oklji0KB.js → merge-styles-DuoZEsm9.js} +2 -2
  30. package/dist/{merge-styles-oklji0KB.js.map → merge-styles-DuoZEsm9.js.map} +1 -1
  31. package/dist/{resolve-recipes-DTG81rzl.js → resolve-recipes-H9NqOQuP.js} +3 -3
  32. package/dist/{resolve-recipes-DTG81rzl.js.map → resolve-recipes-H9NqOQuP.js.map} +1 -1
  33. package/dist/ssr/astro-client.js +1 -1
  34. package/dist/ssr/astro-middleware-extract-static.d.ts +11 -0
  35. package/dist/ssr/astro-middleware-extract-static.js +9 -0
  36. package/dist/ssr/astro-middleware-extract-static.js.map +1 -0
  37. package/dist/ssr/astro-middleware-extract.d.ts +11 -0
  38. package/dist/ssr/astro-middleware-extract.js +9 -0
  39. package/dist/ssr/astro-middleware-extract.js.map +1 -0
  40. package/dist/ssr/astro-middleware-static.d.ts +3 -1
  41. package/dist/ssr/astro-middleware-static.js +1 -1
  42. package/dist/ssr/astro-middleware.d.ts +3 -1
  43. package/dist/ssr/astro-middleware.js +1 -1
  44. package/dist/ssr/astro.d.ts +45 -3
  45. package/dist/ssr/astro.js +1 -156
  46. package/dist/ssr/index.d.ts +2 -2
  47. package/dist/ssr/index.js +3 -3
  48. package/dist/ssr/index.js.map +1 -1
  49. package/dist/ssr/next.d.ts +1 -1
  50. package/dist/ssr/next.js +4 -4
  51. package/dist/static/index.d.ts +2 -2
  52. package/dist/static/index.js +1 -1
  53. package/dist/zero/babel.d.ts +1 -1
  54. package/dist/zero/babel.js +4 -4
  55. package/dist/zero/babel.js.map +1 -1
  56. package/dist/zero/index.d.ts +1 -1
  57. package/dist/zero/index.js +1 -1
  58. package/dist/zero/next.d.ts +1 -1
  59. package/docs/README.md +13 -8
  60. package/docs/adoption.md +56 -31
  61. package/docs/ai-agents.md +78 -77
  62. package/docs/comparison.md +69 -40
  63. package/docs/configuration.md +97 -87
  64. package/docs/debug.md +4 -2
  65. package/docs/design-system.md +41 -22
  66. package/docs/dsl.md +225 -195
  67. package/docs/getting-started.md +60 -39
  68. package/docs/injector.md +63 -26
  69. package/docs/methodology.md +42 -36
  70. package/docs/migration-v3.md +49 -49
  71. package/docs/plugins.md +37 -33
  72. package/docs/react-api.md +65 -44
  73. package/docs/runtime-benchmarks.md +178 -0
  74. package/docs/ssr.md +124 -61
  75. package/docs/styles.md +1 -1
  76. package/docs/tasty-static.md +137 -104
  77. package/package.json +26 -8
  78. package/dist/collector-DTahQUiV.js.map +0 -1
  79. package/dist/config-B5kHzuNz.js.map +0 -1
  80. package/dist/core-Dr4u1NVD.js.map +0 -1
  81. package/dist/format-rules-DKOA-6qu.js.map +0 -1
  82. package/dist/keyframes-CV8azJf3.js.map +0 -1
  83. package/dist/ssr/astro.js.map +0 -1
@@ -1,7 +1,7 @@
1
- import { Bt as getGlobalParseFunctions, G as StyleInjector, Gt as parseStyle, It as registerLocalFunctionPolyfills, J as hasLocalCounterStyle, K as extractLocalCounterStyle, Mt as formatFunctionRule, Nt as hasLocalFunctions, Pt as parseFunctionName, Q as hasLocalFontFace, Qt as isDevEnv, Ut as normalizeColorTokenValue, Vt as getGlobalParser, X as fontFaceContentHash, Y as extractLocalFontFace, Z as formatFontFaceRule, _ as isFunctionsPolyfillEnabled, _t as hashString, bt as hasLocalProperties, c as getGlobalInjector, en as Lru, et as STYLE_HANDLER_MAP, f as getNamePrefix, ft as makeClassName, ht as tastyClassRegex, it as PropertyTypeResolver, jt as extractLocalFunctions, l as getGlobalKeyframes, n as getConfig, p as hasGlobalKeyframes, q as formatCounterStyleRule, rt as createStyle, sn as normalizeDslName, tn as overrideColorAlpha, v as isTestEnvironment, vt as extractLocalProperties, wt as CHUNK_NAMES, xt as parsePropertyToken, y as markStylesGenerated, z as camelToKebab } from "./config-B5kHzuNz.js";
2
- import { a as mergeKeyframes, c as generateChunkCacheKey, i as hasLocalKeyframes, l as categorizeStyleKeys, n as extractLocalKeyframes, o as replaceAnimationNames, r as filterUsedKeyframes, s as renderStylesForChunk, t as extractAnimationNamesFromStyles } from "./keyframes-CV8azJf3.js";
3
- import { n as formatPropertyCSS, r as getRegisteredSSRCollector, t as formatRules } from "./format-rules-DKOA-6qu.js";
4
- import { t as resolveRecipes } from "./resolve-recipes-DTG81rzl.js";
1
+ import { Bt as getGlobalParseFunctions, G as StyleInjector, Gt as parseStyle, It as registerLocalFunctionPolyfills, J as hasLocalCounterStyle, K as extractLocalCounterStyle, Mt as formatFunctionRule, Nt as hasLocalFunctions, Pt as parseFunctionName, Q as hasLocalFontFace, Qt as isDevEnv, Ut as normalizeColorTokenValue, Vt as getGlobalParser, X as fontFaceContentHash, Y as extractLocalFontFace, Z as formatFontFaceRule, _ as isFunctionsPolyfillEnabled, _t as hashString, bt as hasLocalProperties, c as getGlobalInjector, en as Lru, et as STYLE_HANDLER_MAP, f as getNamePrefix, ft as makeClassName, ht as tastyClassRegex, it as PropertyTypeResolver, jt as extractLocalFunctions, l as getGlobalKeyframes, n as getConfig, ot as flushStyles, p as hasGlobalKeyframes, q as formatCounterStyleRule, rt as createStyle, sn as normalizeDslName, tn as overrideColorAlpha, v as isTestEnvironment, vt as extractLocalProperties, wt as CHUNK_NAMES, xt as parsePropertyToken, y as markStylesGenerated, z as camelToKebab } from "./config-B3gPdCqd.js";
2
+ import { a as mergeKeyframes, c as resolveKeyframesNames, d as categorizeStyleKeys, i as hasLocalKeyframes, l as renderStylesForChunk, n as extractLocalKeyframes, o as referencesAnimation, r as filterUsedKeyframes, s as replaceAnimationNames, t as extractAnimationNamesFromStyles, u as generateChunkCacheKey } from "./keyframes-DE-OE76F.js";
3
+ import { n as formatPropertyCSS, r as getRegisteredSSRCollector, t as formatRules } from "./format-rules-rCZ37rqY.js";
4
+ import { t as resolveRecipes } from "./resolve-recipes-H9NqOQuP.js";
5
5
  import { cache } from "react";
6
6
  //#region src/utils/function-color.ts
7
7
  const RE_FUNC_NAME = /^([a-z][a-z0-9-]*)\s*\(/i;
@@ -245,24 +245,43 @@ function getCSSTextForNode(node, options) {
245
245
  return getGlobalInjector().getCSSTextForClasses(classSet, options);
246
246
  }
247
247
  /**
248
- * Force cleanup of unused rules
248
+ * Take a reference on local `@keyframes` under the deterministic names the
249
+ * caller resolved, and report which entry holds each. Pair with
250
+ * `ownKeyframes()` once the rules exist to inspect.
251
+ */
252
+ function holdKeyframes(steps, names, options) {
253
+ return getGlobalInjector().holdKeyframes(steps, names, options);
254
+ }
255
+ /**
256
+ * Record that a class animates these keyframes, so the reference is released
257
+ * when the last such class is collected.
258
+ */
259
+ function ownKeyframes(key, className, options) {
260
+ getGlobalInjector().ownKeyframes(key, className, options);
261
+ }
262
+ /**
263
+ * Remove every injected rule that is neither in the DOM nor held by an
264
+ * outstanding `inject()` handle. Equivalent to `gc({ force: true })`.
249
265
  */
250
266
  function cleanup(root) {
251
267
  return getGlobalInjector().cleanup(root);
252
268
  }
253
269
  /**
254
- * Record a render-time usage hit for one or more classNames.
255
- * Used internally by computeStyles and tasty() to track usage for GC.
256
- * When the global touch counter reaches `touchInterval`, schedules GC.
270
+ * Count a render, so that a collection pass is scheduled every
271
+ * `gc.touchInterval` of them. Used internally by computeStyles and tasty().
272
+ *
273
+ * @deprecated The class name is ignored — collection asks the DOM what is
274
+ * rendered rather than recording usage per class. The argument is kept so
275
+ * existing calls still compile.
257
276
  */
258
277
  function touch(className, options) {
259
278
  if (!getConfig().gc) return;
260
279
  getGlobalInjector().touch(className, options);
261
280
  }
262
281
  /**
263
- * Synchronous garbage collection of unused styles.
264
- * Evicts the oldest unused styles when usageMap exceeds capacity.
265
- * With `{ force: true }`, removes ALL unused styles regardless of capacity.
282
+ * Synchronous garbage collection of unused styles — those no element carries
283
+ * and no `inject()` handle references. Evicts the oldest ones once they exceed
284
+ * capacity. With `{ force: true }`, removes all of them regardless of capacity.
266
285
  *
267
286
  * @returns Number of styles evicted.
268
287
  */
@@ -543,8 +562,10 @@ function collectInternalsRSC(rscCache) {
543
562
  function collectAncillaryRSC(rscCache, styles) {
544
563
  const parts = [];
545
564
  const usedKf = getUsedKeyframes(styles);
546
- if (usedKf) for (const [name, steps] of Object.entries(usedKf)) {
547
- const key = `__kf:${name}:${JSON.stringify(steps)}`;
565
+ const rscKeyframeNames = usedKf ? resolveKeyframesNames(usedKf) : null;
566
+ if (usedKf && rscKeyframeNames) for (const [authored, steps] of Object.entries(usedKf)) {
567
+ const name = rscKeyframeNames.get(authored);
568
+ const key = `__kf:${name}`;
548
569
  if (!rscCache.emittedKeys.has(key)) {
549
570
  rscCache.emittedKeys.add(key);
550
571
  parts.push(formatKeyframesCSS(name, steps));
@@ -604,20 +625,23 @@ function computeStylesRSC(styles, chunkMap, stableStyles) {
604
625
  const rscCache = getRSCCache();
605
626
  const cssParts = [];
606
627
  const classNames = [];
628
+ const rscUsedKf = getUsedKeyframes(styles);
629
+ const rscKeyframeNames = rscUsedKf ? resolveKeyframesNames(rscUsedKf) : null;
607
630
  const pendingCSS = flushPendingCSS(rscCache);
608
631
  if (pendingCSS) cssParts.push(pendingCSS);
609
632
  const internalsCSS = collectInternalsRSC(rscCache);
610
633
  if (internalsCSS) cssParts.push(internalsCSS);
611
634
  for (const [chunkName, chunkStyleKeys] of chunkMap) {
612
635
  if (chunkStyleKeys.length === 0) continue;
613
- const { className, isNew } = rscAllocateClassName(rscCache, generateChunkCacheKey(styles, chunkName, chunkStyleKeys, stableStyles));
636
+ const baseKey = generateChunkCacheKey(styles, chunkName, chunkStyleKeys, stableStyles);
637
+ const renderResult = renderStylesForChunk(styles, chunkName, chunkStyleKeys);
638
+ if (renderResult.rules.length === 0) continue;
639
+ const { rules, cacheKey } = applyKeyframeNames(renderResult.rules, baseKey, rscKeyframeNames);
640
+ const { className, isNew } = rscAllocateClassName(rscCache, cacheKey);
614
641
  classNames.push(className);
615
642
  if (isNew) {
616
- const renderResult = renderStylesForChunk(styles, chunkName, chunkStyleKeys);
617
- if (renderResult.rules.length > 0) {
618
- const css = formatRules(renderResult.rules, className);
619
- if (css) cssParts.push(css);
620
- }
643
+ const css = formatRules(rules, className);
644
+ if (css) cssParts.push(css);
621
645
  }
622
646
  }
623
647
  const ancillaryCSS = collectAncillaryRSC(rscCache, styles);
@@ -644,23 +668,26 @@ function getUsedKeyframes(styles) {
644
668
  /**
645
669
  * Process a chunk on the SSR path: allocate via collector, render, collect CSS.
646
670
  */
647
- function processChunkSSR(collector, styles, chunkName, styleKeys, stableStyles) {
671
+ function processChunkSSR(collector, styles, chunkName, styleKeys, stableStyles, keyframeNames) {
648
672
  if (styleKeys.length === 0) return null;
649
- const cacheKey = generateChunkCacheKey(styles, chunkName, styleKeys, stableStyles);
673
+ const baseKey = generateChunkCacheKey(styles, chunkName, styleKeys, stableStyles);
674
+ const renderResult = renderStylesForChunk(styles, chunkName, styleKeys);
675
+ if (renderResult.rules.length === 0) return null;
676
+ const { animations, rules, cacheKey } = applyKeyframeNames(renderResult.rules, baseKey, keyframeNames);
650
677
  const { className, isNewAllocation } = collector.allocateClassName(cacheKey);
651
678
  if (isNewAllocation) {
652
- const renderResult = renderStylesForChunk(styles, chunkName, styleKeys);
653
- if (renderResult.rules.length > 0) {
654
- collector.collectChunk(cacheKey, className, renderResult.rules);
655
- return {
656
- name: chunkName,
657
- styleKeys,
658
- cacheKey,
659
- renderResult,
660
- className
661
- };
662
- }
663
- return null;
679
+ collector.collectChunk(cacheKey, className, rules);
680
+ return {
681
+ name: chunkName,
682
+ styleKeys,
683
+ cacheKey,
684
+ renderResult: {
685
+ ...renderResult,
686
+ rules
687
+ },
688
+ className,
689
+ animations
690
+ };
664
691
  }
665
692
  return {
666
693
  name: chunkName,
@@ -671,57 +698,64 @@ function processChunkSSR(collector, styles, chunkName, styleKeys, stableStyles)
671
698
  };
672
699
  }
673
700
  /**
701
+ * Point a chunk's rules at the resolved keyframe names, and fold those names
702
+ * into its cache key.
703
+ *
704
+ * Both halves matter, and both have to happen before the rules are written
705
+ * anywhere: the declarations have to name the animation that will exist, and
706
+ * the key has to distinguish two components that authored the same shorthand
707
+ * over different definitions. Shared by the client and the server so they
708
+ * cannot disagree about either.
709
+ */
710
+ function applyKeyframeNames(ruleset, baseKey, keyframeNames) {
711
+ if (!keyframeNames || keyframeNames.size === 0) return {
712
+ animations: [],
713
+ rules: ruleset,
714
+ cacheKey: baseKey
715
+ };
716
+ const animations = [...keyframeNames.keys()].filter((authored) => ruleset.some((rule) => referencesAnimation(rule.declarations, authored)));
717
+ if (animations.length === 0) return {
718
+ animations,
719
+ rules: ruleset,
720
+ cacheKey: baseKey
721
+ };
722
+ return {
723
+ animations,
724
+ rules: ruleset.map((rule) => ({
725
+ ...rule,
726
+ declarations: replaceAnimationNames(rule.declarations, keyframeNames)
727
+ })),
728
+ cacheKey: `${baseKey}\u0000kf:${animations.map((authored) => `${authored}=${keyframeNames.get(authored)}`).sort().join(",")}`
729
+ };
730
+ }
731
+ /**
674
732
  * Process a chunk on the client: render, allocate className, and inject
675
733
  * CSS synchronously. The injector's cache makes this idempotent.
676
734
  */
677
- function processChunkSync(styles, chunkName, styleKeys, stableStyles, root) {
735
+ function processChunkSync(styles, chunkName, styleKeys, stableStyles, root, keyframeNames) {
678
736
  if (styleKeys.length === 0) return null;
679
737
  const cacheKey = generateChunkCacheKey(styles, chunkName, styleKeys, stableStyles);
680
738
  const renderResult = renderStylesForChunk(styles, chunkName, styleKeys, cacheKey);
681
739
  if (renderResult.rules.length === 0) return null;
682
- const { className } = inject(renderResult.rules, {
683
- cacheKey,
684
- root
740
+ const { animations, rules, cacheKey: injectKey } = applyKeyframeNames(renderResult.rules, cacheKey, keyframeNames);
741
+ const { className } = inject(rules, {
742
+ cacheKey: injectKey,
743
+ root,
744
+ pin: false
685
745
  });
686
746
  return {
687
747
  name: chunkName,
688
748
  styleKeys,
689
- cacheKey,
690
- renderResult,
691
- className
749
+ cacheKey: injectKey,
750
+ renderResult: {
751
+ ...renderResult,
752
+ rules
753
+ },
754
+ className,
755
+ animations
692
756
  };
693
757
  }
694
758
  /**
695
- * Inject keyframes synchronously and return a name replacement map.
696
- * On the client, keyframes are injected into the DOM.
697
- */
698
- function injectKeyframesSync(usedKeyframes, root) {
699
- let nameMap = null;
700
- for (const [name, steps] of Object.entries(usedKeyframes)) {
701
- const injectedName = keyframes(steps, {
702
- name,
703
- root
704
- }).toString();
705
- if (injectedName !== name) {
706
- if (!nameMap) nameMap = /* @__PURE__ */ new Map();
707
- nameMap.set(name, injectedName);
708
- }
709
- }
710
- return nameMap;
711
- }
712
- /**
713
- * Inject chunk rules synchronously, replacing animation names if needed.
714
- */
715
- function injectChunkRulesSync(chunks, nameMap, root) {
716
- for (const chunk of chunks) if (chunk.renderResult.rules.length > 0) inject(nameMap ? chunk.renderResult.rules.map((rule) => ({
717
- ...rule,
718
- declarations: replaceAnimationNames(rule.declarations, nameMap)
719
- })) : chunk.renderResult.rules, {
720
- cacheKey: chunk.cacheKey,
721
- root
722
- });
723
- }
724
- /**
725
759
  * Inject all ancillary rules (properties, font-faces, counter-styles) synchronously.
726
760
  */
727
761
  function injectAncillarySync(styles, root) {
@@ -753,9 +787,12 @@ function injectAncillarySync(styles, root) {
753
787
  */
754
788
  function collectAncillarySSR(collector, styles, chunks) {
755
789
  const usedKf = getUsedKeyframes(styles);
756
- if (usedKf) for (const [name, steps] of Object.entries(usedKf)) {
757
- const css = formatKeyframesCSS(name, steps);
758
- collector.collectKeyframes(name, css);
790
+ if (usedKf) {
791
+ const names = resolveKeyframesNames(usedKf);
792
+ for (const [authored, steps] of Object.entries(usedKf)) {
793
+ const name = names.get(authored);
794
+ collector.collectKeyframes(name, formatKeyframesCSS(name, steps));
795
+ }
759
796
  }
760
797
  if (hasLocalProperties(styles)) {
761
798
  const localProperties = extractLocalProperties(styles);
@@ -819,8 +856,10 @@ function computeStyles(styles, options) {
819
856
  const chunks = [];
820
857
  if (collector) {
821
858
  collector.collectInternals();
859
+ const ssrKf = getUsedKeyframes(resolved);
860
+ const ssrKeyframeNames = ssrKf ? resolveKeyframesNames(ssrKf) : null;
822
861
  for (const [chunkName, chunkStyleKeys] of chunkMap) {
823
- const chunk = processChunkSSR(collector, resolved, chunkName, chunkStyleKeys, stableStyles);
862
+ const chunk = processChunkSSR(collector, resolved, chunkName, chunkStyleKeys, stableStyles, ssrKeyframeNames);
824
863
  if (chunk) chunks.push(chunk);
825
864
  }
826
865
  collectAncillarySSR(collector, resolved, chunks);
@@ -829,12 +868,16 @@ function computeStyles(styles, options) {
829
868
  const root = options?.root;
830
869
  injectAncillarySync(resolved, root);
831
870
  const usedKf = getUsedKeyframes(resolved);
832
- const nameMap = usedKf ? injectKeyframesSync(usedKf, root) : null;
871
+ const keyframeNames = usedKf ? resolveKeyframesNames(usedKf) : null;
872
+ const keyframeKeys = usedKf && keyframeNames ? holdKeyframes(usedKf, keyframeNames, { root }) : null;
833
873
  for (const [chunkName, chunkStyleKeys] of chunkMap) {
834
- const chunk = processChunkSync(resolved, chunkName, chunkStyleKeys, stableStyles, root);
874
+ const chunk = processChunkSync(resolved, chunkName, chunkStyleKeys, stableStyles, root, keyframeNames);
835
875
  if (chunk) chunks.push(chunk);
836
876
  }
837
- if (nameMap) injectChunkRulesSync(chunks, nameMap, root);
877
+ if (keyframeKeys) for (const chunk of chunks) for (const authored of chunk.animations ?? []) {
878
+ const key = keyframeKeys.get(authored);
879
+ if (key) ownKeyframes(key, chunk.className, { root });
880
+ }
838
881
  for (const chunk of chunks) touch(chunk.className, { root });
839
882
  }
840
883
  if (chunks.length === 0) return EMPTY_RESULT;
@@ -1115,16 +1158,19 @@ function countRules(css) {
1115
1158
  function sortTastyClasses(classes) {
1116
1159
  return Array.from(classes).sort((a, b) => a.localeCompare(b));
1117
1160
  }
1161
+ /**
1162
+ * The registry for `root`, with every queued write landed first.
1163
+ *
1164
+ * Every injector read API is a flush point, and the reads below reach past
1165
+ * those APIs straight into the registry and the sheet manager. Without this
1166
+ * they would report a batch window's contents as absent — a rule that is
1167
+ * enqueued but not yet in a sheet is missing from `globalRules`, from the
1168
+ * sheets, and from anything counting either.
1169
+ */
1118
1170
  function getRegistry(root = document) {
1171
+ flushStyles();
1119
1172
  return injector.instance._sheetManager?.getRegistry(root);
1120
1173
  }
1121
- function getUnusedClasses(root = document) {
1122
- const registry = getRegistry(root);
1123
- if (!registry) return [];
1124
- const result = [];
1125
- for (const [cls, rc] of registry.refCounts) if (rc === 0) result.push(cls);
1126
- return sortTastyClasses(result);
1127
- }
1128
1174
  function findDomTastyClasses(root = document) {
1129
1175
  const classes = /* @__PURE__ */ new Set();
1130
1176
  const elements = root.querySelectorAll?.("[class]") || [];
@@ -1137,6 +1183,36 @@ function findDomTastyClasses(root = document) {
1137
1183
  });
1138
1184
  return sortTastyClasses(classes);
1139
1185
  }
1186
+ /**
1187
+ * Everything this injector holds in `root`, in the order the engine applies it,
1188
+ * with the sources kept byte-for-byte — trimming would report a total smaller
1189
+ * than one of its own parts whenever raw CSS has edge whitespace.
1190
+ */
1191
+ function getAllCSS(root = document) {
1192
+ const registry = getRegistry(root);
1193
+ const sheetManager = injector.instance._sheetManager;
1194
+ if (!registry || !sheetManager) return "";
1195
+ return sheetManager.getOwnedCSSInOrder(registry, root).join("\n");
1196
+ }
1197
+ /**
1198
+ * Injected classes that no element carries and nobody pinned — the exact set
1199
+ * `gc({ force: true })` would delete.
1200
+ *
1201
+ * Deliberately borrowed from the injector rather than recomputed here: the two
1202
+ * drifted apart once before, when this file still read "unused" off the pin
1203
+ * counts the render path had stopped maintaining.
1204
+ */
1205
+ function getUnusedClasses(root = document) {
1206
+ return sortTastyClasses(injector.instance.getUnusedClasses({ root }));
1207
+ }
1208
+ /** Every class this injector holds CSS for in `root`. */
1209
+ function getOwnedClasses(root = document) {
1210
+ const registry = getRegistry(root);
1211
+ if (!registry) return [];
1212
+ const owned = [];
1213
+ for (const [className, info] of registry.rules) if (info.sheetIndex >= 0) owned.push(className);
1214
+ return sortTastyClasses(owned);
1215
+ }
1140
1216
  function prettifyCSS(css) {
1141
1217
  if (!css || !css.trim()) return "";
1142
1218
  const out = [];
@@ -1231,6 +1307,18 @@ function buildChunkBreakdown(root = document) {
1231
1307
  totalClasses
1232
1308
  };
1233
1309
  }
1310
+ /**
1311
+ * Every prefix `registry.globalRules` is keyed by. Anything missing here is a
1312
+ * rule the summary would hold but never count, which is how the totals stopped
1313
+ * adding up the first time.
1314
+ */
1315
+ const GLOBAL_RULE_PREFIXES = {
1316
+ global: "global:",
1317
+ property: "property:",
1318
+ fontFace: "fontface:",
1319
+ counterStyle: "counterstyle:",
1320
+ function: "function:"
1321
+ };
1234
1322
  function getGlobalTypeCSS(type, root = document) {
1235
1323
  const registry = getRegistry(root);
1236
1324
  if (!registry) return {
@@ -1240,6 +1328,15 @@ function getGlobalTypeCSS(type, root = document) {
1240
1328
  };
1241
1329
  const chunks = [];
1242
1330
  let rc = 0;
1331
+ if (type === "raw") {
1332
+ const css = injector.instance.getRawCSSText({ root });
1333
+ const sheetManager = injector.instance._sheetManager;
1334
+ return {
1335
+ css: prettifyCSS(css),
1336
+ ruleCount: sheetManager?.getRawRuleCount(root) ?? 0,
1337
+ size: css.length
1338
+ };
1339
+ }
1243
1340
  if (type === "keyframes") for (const [, entry] of registry.keyframesCache) {
1244
1341
  const info = entry.info;
1245
1342
  const sheetInfo = registry.sheets[info.sheetIndex];
@@ -1257,7 +1354,7 @@ function getGlobalTypeCSS(type, root = document) {
1257
1354
  }
1258
1355
  }
1259
1356
  else {
1260
- const prefix = type === "global" ? "global:" : type === "raw" ? "raw:" : "property:";
1357
+ const prefix = GLOBAL_RULE_PREFIXES[type];
1261
1358
  for (const [key, ri] of registry.globalRules) {
1262
1359
  if (!key.startsWith(prefix)) continue;
1263
1360
  const sheetInfo = registry.sheets[ri.sheetIndex];
@@ -1347,7 +1444,7 @@ const tastyDebug = {
1347
1444
  if (!raw) console.warn("[Tasty] source CSS not available. Falling back to live CSSOM.");
1348
1445
  css = injector.instance.getCSSTextForClasses(target, { root });
1349
1446
  }
1350
- } else if (typeof target === "string") if (target === "all") css = injector.instance.getCSSText({ root });
1447
+ } else if (typeof target === "string") if (target === "all") css = getAllCSS(root);
1351
1448
  else if (target === "global") {
1352
1449
  css = getGlobalTypeCSS("global", root).css;
1353
1450
  return css;
@@ -1423,34 +1520,56 @@ const tastyDebug = {
1423
1520
  const { root = document, raw = false } = opts || {};
1424
1521
  const activeClasses = findDomTastyClasses(root);
1425
1522
  const unusedClasses = getUnusedClasses(root);
1426
- const totalStyledClasses = [...activeClasses, ...unusedClasses];
1523
+ const ownedClasses = getOwnedClasses(root);
1524
+ const totalStyledClasses = sortTastyClasses(new Set([...activeClasses, ...ownedClasses]));
1525
+ const unusedSet = new Set(unusedClasses);
1526
+ const activeSet = new Set(activeClasses);
1527
+ const hotClasses = ownedClasses.filter((className) => !activeSet.has(className) && !unusedSet.has(className));
1528
+ const hotCSS = injector.instance.getCSSTextForClasses(hotClasses, { root });
1427
1529
  const activeCSS = injector.instance.getCSSTextForClasses(activeClasses, { root });
1428
1530
  const unusedCSS = injector.instance.getCSSTextForClasses(unusedClasses, { root });
1429
- const allCSS = injector.instance.getCSSText({ root });
1531
+ const allCSS = getAllCSS(root);
1430
1532
  const activeRuleCount = countRules(activeCSS);
1431
1533
  const unusedRuleCount = countRules(unusedCSS);
1432
1534
  const globalData = getGlobalTypeCSS("global", root);
1433
1535
  const rawData = getGlobalTypeCSS("raw", root);
1434
1536
  const kfData = getGlobalTypeCSS("keyframes", root);
1435
1537
  const propData = getGlobalTypeCSS("property", root);
1436
- const totalRuleCount = activeRuleCount + unusedRuleCount + globalData.ruleCount + rawData.ruleCount + kfData.ruleCount + propData.ruleCount;
1538
+ const atRuleData = [
1539
+ "fontFace",
1540
+ "counterStyle",
1541
+ "function"
1542
+ ].reduce((all, type) => {
1543
+ const data = getGlobalTypeCSS(type, root);
1544
+ return {
1545
+ css: data.css ? `${all.css}\n${data.css}`.trim() : all.css,
1546
+ ruleCount: all.ruleCount + data.ruleCount,
1547
+ size: all.size + data.size
1548
+ };
1549
+ }, {
1550
+ css: "",
1551
+ ruleCount: 0,
1552
+ size: 0
1553
+ });
1554
+ const totalRuleCount = activeRuleCount + unusedRuleCount + countRules(hotCSS) + globalData.ruleCount + atRuleData.ruleCount + rawData.ruleCount + kfData.ruleCount + propData.ruleCount;
1437
1555
  const metrics = injector.instance.getMetrics({ root });
1438
1556
  const defs = getDefs(root);
1439
1557
  const chunkBreakdown = buildChunkBreakdown(root);
1440
1558
  const summary = {
1441
1559
  activeClasses,
1442
1560
  unusedClasses,
1561
+ hotClasses,
1443
1562
  totalStyledClasses,
1444
1563
  activeCSSSize: activeCSS.length,
1445
1564
  unusedCSSSize: unusedCSS.length,
1446
- globalCSSSize: globalData.size,
1565
+ globalCSSSize: globalData.size + atRuleData.size,
1447
1566
  rawCSSSize: rawData.size,
1448
1567
  keyframesCSSSize: kfData.size,
1449
1568
  propertyCSSSize: propData.size,
1450
1569
  totalCSSSize: allCSS.length,
1451
1570
  activeRuleCount,
1452
1571
  unusedRuleCount,
1453
- globalRuleCount: globalData.ruleCount,
1572
+ globalRuleCount: globalData.ruleCount + atRuleData.ruleCount,
1454
1573
  rawRuleCount: rawData.ruleCount,
1455
1574
  keyframesRuleCount: kfData.ruleCount,
1456
1575
  propertyRuleCount: propData.ruleCount,
@@ -1464,7 +1583,8 @@ const tastyDebug = {
1464
1583
  console.group("Tasty Summary");
1465
1584
  console.log(`Active: ${activeClasses.length} classes, ${activeRuleCount} rules, ${fmtSize(activeCSS.length)}`);
1466
1585
  console.log(`Unused: ${unusedClasses.length} classes, ${unusedRuleCount} rules, ${fmtSize(unusedCSS.length)}`);
1467
- console.log(`Global: ${globalData.ruleCount} rules, ${fmtSize(globalData.size)}`);
1586
+ if (hotClasses.length) console.log(`Held: ${hotClasses.length} classes, ${countRules(hotCSS)} rules, ${fmtSize(hotCSS.length)} (not rendered, not yet collectable)`);
1587
+ console.log(`Global: ${globalData.ruleCount + atRuleData.ruleCount} rules, ${fmtSize(globalData.size + atRuleData.size)}`);
1468
1588
  if (rawData.ruleCount) console.log(`Raw: ${rawData.ruleCount} rules, ${fmtSize(rawData.size)}`);
1469
1589
  if (kfData.ruleCount) console.log(`Keyframes: ${kfData.ruleCount} rules, ${fmtSize(kfData.size)}`);
1470
1590
  if (propData.ruleCount) console.log(`@property: ${propData.ruleCount} rules, ${fmtSize(propData.size)}`);
@@ -1511,7 +1631,7 @@ const tastyDebug = {
1511
1631
  classes: {
1512
1632
  active,
1513
1633
  unused,
1514
- all: [...active, ...unused]
1634
+ all: sortTastyClasses(new Set([...active, ...getOwnedClasses(root)]))
1515
1635
  },
1516
1636
  metrics
1517
1637
  };
@@ -1561,6 +1681,6 @@ function getPageCSS(root = document) {
1561
1681
  }
1562
1682
  if (typeof window !== "undefined" && isDevEnv()) tastyDebug.install();
1563
1683
  //#endregion
1564
- export { property as A, getRawCSSText as C, injector as D, injectRawCSS as E, ChunkSheetRegistry as M, chunkSheetRegistry as N, isPropertyDefined as O, resolveFunctionColor as P, getCSSTextForNode as S, injectGlobal as T, destroy as _, color as a, gc as b, hasKeys as c, collectAutoInferredPropertiesRSC as d, getStyleTarget as f, createInjector as g, counterStyle as h, _modAttrs as i, touch as j, keyframes as k, formatKeyframesCSS as l, cleanup as m, processTokens as n, filterBaseProps as o, pushRSCCSS as p, dotize as r, computeStyles as s, tastyDebug as t, collectAutoInferredProperties as u, fontFace as v, inject as w, getCSSText as x, func as y };
1684
+ export { keyframes as A, getRawCSSText as C, injectRawCSS as D, injectGlobal as E, chunkSheetRegistry as F, resolveFunctionColor as I, property as M, touch as N, injector as O, ChunkSheetRegistry as P, getCSSTextForNode as S, inject as T, destroy as _, color as a, gc as b, hasKeys as c, collectAutoInferredPropertiesRSC as d, getStyleTarget as f, createInjector as g, counterStyle as h, _modAttrs as i, ownKeyframes as j, isPropertyDefined as k, formatKeyframesCSS as l, cleanup as m, processTokens as n, filterBaseProps as o, pushRSCCSS as p, dotize as r, computeStyles as s, tastyDebug as t, collectAutoInferredProperties as u, fontFace as v, holdKeyframes as w, getCSSText as x, func as y };
1565
1685
 
1566
- //# sourceMappingURL=core-Dr4u1NVD.js.map
1686
+ //# sourceMappingURL=core-Bq7w2kti.js.map