@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.
Files changed (83) hide show
  1. package/README.md +147 -129
  2. package/dist/astro-ib7E7V4Y.js +307 -0
  3. package/dist/astro-ib7E7V4Y.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-BKqNBmzA.js → collector-C6TtL8HJ.js} +36 -13
  7. package/dist/collector-C6TtL8HJ.js.map +1 -0
  8. package/dist/{config-BCdCTIED.js → config-B3gPdCqd.js} +344 -209
  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-wxP3GHQu.js → core-Bq7w2kti.js} +219 -98
  14. package/dist/core-Bq7w2kti.js.map +1 -0
  15. package/dist/{css-writer-D64NY9AX.js → css-writer-Bgowobbx.js} +3 -3
  16. package/dist/{css-writer-D64NY9AX.js.map → css-writer-Bgowobbx.js.map} +1 -1
  17. package/dist/{format-rules-Bo_e2u7r.js → format-rules-rCZ37rqY.js} +2 -2
  18. package/dist/format-rules-rCZ37rqY.js.map +1 -0
  19. package/dist/{hydrate-CMKOuKAx.js → hydrate-CNOmZprz.js} +3 -3
  20. package/dist/{hydrate-CMKOuKAx.js.map → hydrate-CNOmZprz.js.map} +1 -1
  21. package/dist/{index-DhhUI0yi.d.ts → index-Bm9ltvdH.d.ts} +45 -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 +9 -8
  25. package/dist/index.js.map +1 -1
  26. package/dist/{keyframes-D737PShJ.js → keyframes-DE-OE76F.js} +132 -21
  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-CUIQcs5v.js → merge-styles-DuoZEsm9.js} +2 -2
  30. package/dist/{merge-styles-CUIQcs5v.js.map → merge-styles-DuoZEsm9.js.map} +1 -1
  31. package/dist/{resolve-recipes-Df1Ta-Q0.js → resolve-recipes-H9NqOQuP.js} +3 -3
  32. package/dist/{resolve-recipes-Df1Ta-Q0.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 +37 -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 +99 -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-BKqNBmzA.js.map +0 -1
  79. package/dist/config-BCdCTIED.js.map +0 -1
  80. package/dist/core-wxP3GHQu.js.map +0 -1
  81. package/dist/format-rules-Bo_e2u7r.js.map +0 -1
  82. package/dist/keyframes-D737PShJ.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-BCdCTIED.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-D737PShJ.js";
3
- import { n as formatPropertyCSS, r as getRegisteredSSRCollector, t as formatRules } from "./format-rules-Bo_e2u7r.js";
4
- import { t as resolveRecipes } from "./resolve-recipes-Df1Ta-Q0.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));
@@ -600,24 +621,27 @@ function collectAncillaryRSC(rscCache, styles) {
600
621
  * Process all chunks in RSC mode: render CSS to strings, allocate classNames,
601
622
  * and return combined { className, css }.
602
623
  */
603
- function computeStylesRSC(styles, chunkMap) {
624
+ 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));
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) {
671
+ function processChunkSSR(collector, styles, chunkName, styleKeys, stableStyles, keyframeNames) {
648
672
  if (styleKeys.length === 0) return null;
649
- const cacheKey = generateChunkCacheKey(styles, chunkName, styleKeys);
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) {
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, root) {
735
+ function processChunkSync(styles, chunkName, styleKeys, stableStyles, root, keyframeNames) {
678
736
  if (styleKeys.length === 0) return null;
679
- const cacheKey = generateChunkCacheKey(styles, chunkName, styleKeys);
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);
@@ -812,28 +849,35 @@ function collectAncillarySSR(collector, styles, chunks) {
812
849
  function computeStyles(styles, options) {
813
850
  if (!styles || !hasKeys(styles)) return EMPTY_RESULT;
814
851
  const resolved = resolveRecipes(styles);
852
+ const stableStyles = options?.stableStyles === true && resolved === styles;
815
853
  if (isFunctionsPolyfillEnabled() && hasLocalFunctions(resolved)) registerLocalFunctionPolyfills(resolved);
816
854
  const chunkMap = categorizeStyleKeys(resolved);
817
855
  const collector = options?.ssrCollector !== void 0 ? options.ssrCollector : getRegisteredSSRCollector();
818
856
  const chunks = [];
819
857
  if (collector) {
820
858
  collector.collectInternals();
859
+ const ssrKf = getUsedKeyframes(resolved);
860
+ const ssrKeyframeNames = ssrKf ? resolveKeyframesNames(ssrKf) : null;
821
861
  for (const [chunkName, chunkStyleKeys] of chunkMap) {
822
- const chunk = processChunkSSR(collector, resolved, chunkName, chunkStyleKeys);
862
+ const chunk = processChunkSSR(collector, resolved, chunkName, chunkStyleKeys, stableStyles, ssrKeyframeNames);
823
863
  if (chunk) chunks.push(chunk);
824
864
  }
825
865
  collectAncillarySSR(collector, resolved, chunks);
826
- } else if (typeof document === "undefined") return computeStylesRSC(resolved, chunkMap);
866
+ } else if (typeof document === "undefined") return computeStylesRSC(resolved, chunkMap, stableStyles);
827
867
  else {
828
868
  const root = options?.root;
829
869
  injectAncillarySync(resolved, root);
830
870
  const usedKf = getUsedKeyframes(resolved);
831
- const nameMap = usedKf ? injectKeyframesSync(usedKf, root) : null;
871
+ const keyframeNames = usedKf ? resolveKeyframesNames(usedKf) : null;
872
+ const keyframeKeys = usedKf && keyframeNames ? holdKeyframes(usedKf, keyframeNames, { root }) : null;
832
873
  for (const [chunkName, chunkStyleKeys] of chunkMap) {
833
- const chunk = processChunkSync(resolved, chunkName, chunkStyleKeys, root);
874
+ const chunk = processChunkSync(resolved, chunkName, chunkStyleKeys, stableStyles, root, keyframeNames);
834
875
  if (chunk) chunks.push(chunk);
835
876
  }
836
- 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
+ }
837
881
  for (const chunk of chunks) touch(chunk.className, { root });
838
882
  }
839
883
  if (chunks.length === 0) return EMPTY_RESULT;
@@ -1114,16 +1158,19 @@ function countRules(css) {
1114
1158
  function sortTastyClasses(classes) {
1115
1159
  return Array.from(classes).sort((a, b) => a.localeCompare(b));
1116
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
+ */
1117
1170
  function getRegistry(root = document) {
1171
+ flushStyles();
1118
1172
  return injector.instance._sheetManager?.getRegistry(root);
1119
1173
  }
1120
- function getUnusedClasses(root = document) {
1121
- const registry = getRegistry(root);
1122
- if (!registry) return [];
1123
- const result = [];
1124
- for (const [cls, rc] of registry.refCounts) if (rc === 0) result.push(cls);
1125
- return sortTastyClasses(result);
1126
- }
1127
1174
  function findDomTastyClasses(root = document) {
1128
1175
  const classes = /* @__PURE__ */ new Set();
1129
1176
  const elements = root.querySelectorAll?.("[class]") || [];
@@ -1136,6 +1183,36 @@ function findDomTastyClasses(root = document) {
1136
1183
  });
1137
1184
  return sortTastyClasses(classes);
1138
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
+ }
1139
1216
  function prettifyCSS(css) {
1140
1217
  if (!css || !css.trim()) return "";
1141
1218
  const out = [];
@@ -1230,6 +1307,18 @@ function buildChunkBreakdown(root = document) {
1230
1307
  totalClasses
1231
1308
  };
1232
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
+ };
1233
1322
  function getGlobalTypeCSS(type, root = document) {
1234
1323
  const registry = getRegistry(root);
1235
1324
  if (!registry) return {
@@ -1239,6 +1328,15 @@ function getGlobalTypeCSS(type, root = document) {
1239
1328
  };
1240
1329
  const chunks = [];
1241
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
+ }
1242
1340
  if (type === "keyframes") for (const [, entry] of registry.keyframesCache) {
1243
1341
  const info = entry.info;
1244
1342
  const sheetInfo = registry.sheets[info.sheetIndex];
@@ -1256,7 +1354,7 @@ function getGlobalTypeCSS(type, root = document) {
1256
1354
  }
1257
1355
  }
1258
1356
  else {
1259
- const prefix = type === "global" ? "global:" : type === "raw" ? "raw:" : "property:";
1357
+ const prefix = GLOBAL_RULE_PREFIXES[type];
1260
1358
  for (const [key, ri] of registry.globalRules) {
1261
1359
  if (!key.startsWith(prefix)) continue;
1262
1360
  const sheetInfo = registry.sheets[ri.sheetIndex];
@@ -1346,7 +1444,7 @@ const tastyDebug = {
1346
1444
  if (!raw) console.warn("[Tasty] source CSS not available. Falling back to live CSSOM.");
1347
1445
  css = injector.instance.getCSSTextForClasses(target, { root });
1348
1446
  }
1349
- } 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);
1350
1448
  else if (target === "global") {
1351
1449
  css = getGlobalTypeCSS("global", root).css;
1352
1450
  return css;
@@ -1422,34 +1520,56 @@ const tastyDebug = {
1422
1520
  const { root = document, raw = false } = opts || {};
1423
1521
  const activeClasses = findDomTastyClasses(root);
1424
1522
  const unusedClasses = getUnusedClasses(root);
1425
- 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 });
1426
1529
  const activeCSS = injector.instance.getCSSTextForClasses(activeClasses, { root });
1427
1530
  const unusedCSS = injector.instance.getCSSTextForClasses(unusedClasses, { root });
1428
- const allCSS = injector.instance.getCSSText({ root });
1531
+ const allCSS = getAllCSS(root);
1429
1532
  const activeRuleCount = countRules(activeCSS);
1430
1533
  const unusedRuleCount = countRules(unusedCSS);
1431
1534
  const globalData = getGlobalTypeCSS("global", root);
1432
1535
  const rawData = getGlobalTypeCSS("raw", root);
1433
1536
  const kfData = getGlobalTypeCSS("keyframes", root);
1434
1537
  const propData = getGlobalTypeCSS("property", root);
1435
- 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;
1436
1555
  const metrics = injector.instance.getMetrics({ root });
1437
1556
  const defs = getDefs(root);
1438
1557
  const chunkBreakdown = buildChunkBreakdown(root);
1439
1558
  const summary = {
1440
1559
  activeClasses,
1441
1560
  unusedClasses,
1561
+ hotClasses,
1442
1562
  totalStyledClasses,
1443
1563
  activeCSSSize: activeCSS.length,
1444
1564
  unusedCSSSize: unusedCSS.length,
1445
- globalCSSSize: globalData.size,
1565
+ globalCSSSize: globalData.size + atRuleData.size,
1446
1566
  rawCSSSize: rawData.size,
1447
1567
  keyframesCSSSize: kfData.size,
1448
1568
  propertyCSSSize: propData.size,
1449
1569
  totalCSSSize: allCSS.length,
1450
1570
  activeRuleCount,
1451
1571
  unusedRuleCount,
1452
- globalRuleCount: globalData.ruleCount,
1572
+ globalRuleCount: globalData.ruleCount + atRuleData.ruleCount,
1453
1573
  rawRuleCount: rawData.ruleCount,
1454
1574
  keyframesRuleCount: kfData.ruleCount,
1455
1575
  propertyRuleCount: propData.ruleCount,
@@ -1463,7 +1583,8 @@ const tastyDebug = {
1463
1583
  console.group("Tasty Summary");
1464
1584
  console.log(`Active: ${activeClasses.length} classes, ${activeRuleCount} rules, ${fmtSize(activeCSS.length)}`);
1465
1585
  console.log(`Unused: ${unusedClasses.length} classes, ${unusedRuleCount} rules, ${fmtSize(unusedCSS.length)}`);
1466
- 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)}`);
1467
1588
  if (rawData.ruleCount) console.log(`Raw: ${rawData.ruleCount} rules, ${fmtSize(rawData.size)}`);
1468
1589
  if (kfData.ruleCount) console.log(`Keyframes: ${kfData.ruleCount} rules, ${fmtSize(kfData.size)}`);
1469
1590
  if (propData.ruleCount) console.log(`@property: ${propData.ruleCount} rules, ${fmtSize(propData.size)}`);
@@ -1510,7 +1631,7 @@ const tastyDebug = {
1510
1631
  classes: {
1511
1632
  active,
1512
1633
  unused,
1513
- all: [...active, ...unused]
1634
+ all: sortTastyClasses(new Set([...active, ...getOwnedClasses(root)]))
1514
1635
  },
1515
1636
  metrics
1516
1637
  };
@@ -1560,6 +1681,6 @@ function getPageCSS(root = document) {
1560
1681
  }
1561
1682
  if (typeof window !== "undefined" && isDevEnv()) tastyDebug.install();
1562
1683
  //#endregion
1563
- 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 };
1564
1685
 
1565
- //# sourceMappingURL=core-wxP3GHQu.js.map
1686
+ //# sourceMappingURL=core-Bq7w2kti.js.map