@tenphi/tasty 3.1.0 → 3.2.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 (48) hide show
  1. package/README.md +1 -0
  2. package/dist/{babel-R2qT7yLN.d.ts → babel-D8dm92E_.d.ts} +2 -2
  3. package/dist/{collector-D8o4Wdq-.d.ts → collector-BFuqdF2F.d.ts} +2 -2
  4. package/dist/{collector-D7yzmG5G.js → collector-Di3C8btw.js} +3 -3
  5. package/dist/{collector-D7yzmG5G.js.map → collector-Di3C8btw.js.map} +1 -1
  6. package/dist/{config-CwQ-fAsp.js → config-BrDt11hO.js} +460 -80
  7. package/dist/config-BrDt11hO.js.map +1 -0
  8. package/dist/{config-De8L9NWM.d.ts → config-DH7I0Ggx.d.ts} +73 -2
  9. package/dist/core/index.d.ts +5 -5
  10. package/dist/core/index.js +6 -6
  11. package/dist/{core-CqSh853z.js → core-YWn1zgh4.js} +5 -5
  12. package/dist/core-YWn1zgh4.js.map +1 -0
  13. package/dist/{css-writer-dS1srTkS.js → css-writer-CQYbT4g_.js} +3 -3
  14. package/dist/{css-writer-dS1srTkS.js.map → css-writer-CQYbT4g_.js.map} +1 -1
  15. package/dist/{format-rules-CaW4lJGg.js → format-rules-DdmLdntR.js} +2 -2
  16. package/dist/{format-rules-CaW4lJGg.js.map → format-rules-DdmLdntR.js.map} +1 -1
  17. package/dist/{hydrate-uFv9kx7G.js → hydrate-D2ivfS-B.js} +2 -2
  18. package/dist/{hydrate-uFv9kx7G.js.map → hydrate-D2ivfS-B.js.map} +1 -1
  19. package/dist/{index-DzGxoeyN.d.ts → index-DljBkZhV.d.ts} +59 -6
  20. package/dist/{index-KUYya3x7.d.ts → index-LC3O3Jj4.d.ts} +102 -2
  21. package/dist/index.d.ts +5 -5
  22. package/dist/index.js +62 -8
  23. package/dist/index.js.map +1 -1
  24. package/dist/{keyframes-DaZhjqkd.js → keyframes-CoLLjBcd.js} +2 -2
  25. package/dist/{keyframes-DaZhjqkd.js.map → keyframes-CoLLjBcd.js.map} +1 -1
  26. package/dist/{merge-styles-DLm4wdnb.d.ts → merge-styles-Cx_6ySBv.d.ts} +2 -2
  27. package/dist/{merge-styles-H8LFJ5HY.js → merge-styles-bdh7-1uh.js} +2 -2
  28. package/dist/{merge-styles-H8LFJ5HY.js.map → merge-styles-bdh7-1uh.js.map} +1 -1
  29. package/dist/{resolve-recipes-aN94fjqS.js → resolve-recipes-9JYSgubn.js} +3 -3
  30. package/dist/{resolve-recipes-aN94fjqS.js.map → resolve-recipes-9JYSgubn.js.map} +1 -1
  31. package/dist/ssr/astro-client.js +1 -1
  32. package/dist/ssr/astro.js +3 -3
  33. package/dist/ssr/index.d.ts +1 -1
  34. package/dist/ssr/index.js +3 -3
  35. package/dist/ssr/next.d.ts +1 -1
  36. package/dist/ssr/next.js +4 -4
  37. package/dist/static/index.d.ts +2 -2
  38. package/dist/static/index.js +1 -1
  39. package/dist/zero/babel.d.ts +1 -1
  40. package/dist/zero/babel.js +4 -4
  41. package/dist/zero/index.d.ts +1 -1
  42. package/dist/zero/index.js +1 -1
  43. package/dist/zero/next.d.ts +1 -1
  44. package/docs/configuration.md +127 -0
  45. package/docs/injector.md +11 -0
  46. package/package.json +4 -4
  47. package/dist/config-CwQ-fAsp.js.map +0 -1
  48. package/dist/core-CqSh853z.js.map +0 -1
@@ -3423,6 +3423,217 @@ function rscClassRegexGlobal(prefix) {
3423
3423
  return new RegExp(`\\.(${escapeRegex(prefix)}[a-z0-9]+)\\.\\1`, "g");
3424
3424
  }
3425
3425
  //#endregion
3426
+ //#region src/utils/warnings.ts
3427
+ const PREFIX = "[Tasty]";
3428
+ function warn(...args) {
3429
+ console.warn(PREFIX, ...args);
3430
+ }
3431
+ //#endregion
3432
+ //#region src/injector/batch.ts
3433
+ /**
3434
+ * Deferred CSSOM writes ("batched injection").
3435
+ *
3436
+ * Every `insertRule()` on a live stylesheet invalidates style for the sheet's
3437
+ * scope, so Blink recalculates style the next time anything reads layout or
3438
+ * computed style. When components inject during React's render phase and other
3439
+ * components read layout in the same pass, the two interleave:
3440
+ *
3441
+ * inject -> read (forced recalc) -> inject -> read (forced recalc) -> ...
3442
+ *
3443
+ * Batching moves every sheet write out from between those reads. Writes are
3444
+ * queued in FIFO order and drained in one go, so the tree is invalidated once
3445
+ * per flush instead of once per component.
3446
+ *
3447
+ * ## Ordering
3448
+ *
3449
+ * A single queue holds *all* writes — component rules, global rules, keyframes,
3450
+ * `@property`, `@font-face`, `@counter-style`, `@function` and raw CSS. Draining
3451
+ * it in insertion order keeps the sheet byte-identical to unbatched output,
3452
+ * which matters because equal-specificity rules resolve by document order.
3453
+ *
3454
+ * ## Batch windows — why queuing is safe
3455
+ *
3456
+ * Deferring a write past React's layout phase would let a `useLayoutEffect`
3457
+ * measure an element whose rules are not in the sheet yet, reading the unstyled
3458
+ * box. `<TastyBatchProvider>` closes that hole by opening a *window* during its
3459
+ * render and closing it — flushing — in its `useInsertionEffect`, which React
3460
+ * runs in the mutation phase, before any layout effect:
3461
+ *
3462
+ * provider renders -> window OPEN
3463
+ * children render -> injections queued
3464
+ * provider insertionEffect -> FLUSH, window CLOSED
3465
+ * layout effects run -> rules are in the sheet
3466
+ *
3467
+ * So in the default (`batchInjection: true`) mode a write is only ever queued
3468
+ * inside a commit whose flush is already guaranteed by that same commit. Every
3469
+ * injection outside a window — a deep update the provider did not re-render
3470
+ * for, a `useLayoutEffect` that injects, an event handler, an async callback —
3471
+ * is written straight through, exactly as with batching off.
3472
+ *
3473
+ * `batchInjection: 'always'` opts out of the gate and queues unconditionally.
3474
+ * That wins on more commits, at the cost of the measurement hazard above.
3475
+ *
3476
+ * ## Flush points (earliest wins)
3477
+ *
3478
+ * 1. `<TastyBatchProvider>`'s `useInsertionEffect` — closes the window.
3479
+ * 2. A microtask — a backstop for a render that was aborted or suspended and
3480
+ * therefore never reached its insertion effect. An aborted render mounts
3481
+ * nothing, so nothing can measure what it queued. Microtasks also always
3482
+ * drain before paint, so styles are never visually missing.
3483
+ * 3. `flushStyles()` — explicit, and called internally by every injector read
3484
+ * API (`getCSSText`, `cleanup`, `gc`, `destroy`, ...).
3485
+ */
3486
+ /**
3487
+ * FIFO of pending writes. Drained with a moving `head` index rather than
3488
+ * `shift()` so a large batch stays O(n) instead of O(n²).
3489
+ */
3490
+ let queue = [];
3491
+ let head = 0;
3492
+ let microtaskScheduled = false;
3493
+ let flushing = false;
3494
+ /**
3495
+ * Whether a `<TastyBatchProvider>` has rendered in the current commit and will
3496
+ * therefore flush in its insertion effect, making it safe to queue a write.
3497
+ *
3498
+ * A flag rather than a depth count, because renders and insertion effects do
3499
+ * not pair up one-to-one. StrictMode double-invokes render but runs the
3500
+ * insertion effect once, so a counter ends the commit stuck above zero — and a
3501
+ * window that stays open past its commit turns the next provider-less commit
3502
+ * into `'always'` mode behind the user's back, which is exactly the measurement
3503
+ * hazard `true` exists to avoid.
3504
+ *
3505
+ * Clearing on the first close is safe with nested or sibling providers: React
3506
+ * finishes every render in a commit before running any insertion effect, so once
3507
+ * one closes, no further render-phase injection can arrive in that commit.
3508
+ */
3509
+ let windowOpen = false;
3510
+ /** Whether any window has ever been opened, i.e. a provider is in the tree. */
3511
+ let everOpened = false;
3512
+ /** Dev-only: warn at most once that batching is on with no provider mounted. */
3513
+ let warnedNoProvider = false;
3514
+ /**
3515
+ * Queue a sheet write.
3516
+ *
3517
+ * Returns a handle whose `cancel()` drops the write if the caller disposes
3518
+ * before the flush. The handle is intentionally tiny — one is allocated per
3519
+ * injected class, on the cache-miss path only.
3520
+ */
3521
+ function enqueueStyleWrite(run) {
3522
+ if (flushing) {
3523
+ run();
3524
+ return {
3525
+ run,
3526
+ cancelled: false,
3527
+ done: true
3528
+ };
3529
+ }
3530
+ const entry = {
3531
+ run,
3532
+ cancelled: false,
3533
+ done: false
3534
+ };
3535
+ queue.push(entry);
3536
+ scheduleMicrotaskFlush();
3537
+ return entry;
3538
+ }
3539
+ /** Whether any write is still waiting to hit a stylesheet. */
3540
+ function hasPendingStyleWrites() {
3541
+ return head < queue.length;
3542
+ }
3543
+ /**
3544
+ * Open a batch window. Called from `<TastyBatchProvider>`'s render, so every
3545
+ * descendant injection in this commit is covered by the provider's insertion
3546
+ * effect.
3547
+ *
3548
+ * Called during render on purpose: the window must be open before children
3549
+ * render. It is idempotent — so StrictMode's double render costs nothing — and
3550
+ * carries no other side effect. A render that is thrown away is recovered by the
3551
+ * microtask backstop.
3552
+ *
3553
+ * A no-op without a `document`. On the server there is no sheet to batch
3554
+ * against, and `useInsertionEffect` never runs, so nothing would ever close a
3555
+ * window this opened. Skipping it keeps the provider inert during SSR and RSC
3556
+ * instead of merely harmless.
3557
+ */
3558
+ function openBatchWindow() {
3559
+ if (typeof document === "undefined") return;
3560
+ windowOpen = true;
3561
+ everOpened = true;
3562
+ }
3563
+ /**
3564
+ * Close a batch window and flush. Called from the provider's
3565
+ * `useInsertionEffect`, i.e. after every render in the commit and before any
3566
+ * layout effect.
3567
+ */
3568
+ function closeBatchWindow() {
3569
+ windowOpen = false;
3570
+ flushStyles();
3571
+ }
3572
+ /** Whether a batch window is currently open. */
3573
+ function isBatchWindowOpen() {
3574
+ return windowOpen;
3575
+ }
3576
+ function scheduleMicrotaskFlush() {
3577
+ if (microtaskScheduled || flushing) return;
3578
+ microtaskScheduled = true;
3579
+ queueMicrotask(() => {
3580
+ microtaskScheduled = false;
3581
+ windowOpen = false;
3582
+ flushStyles();
3583
+ });
3584
+ }
3585
+ /**
3586
+ * Drain every pending sheet write, in insertion order.
3587
+ *
3588
+ * Safe to call when the queue is empty (the common case, so the guard comes
3589
+ * first) and safe to call re-entrantly: a nested `flushStyles()` is a no-op,
3590
+ * and work a draining write triggers is written in place by
3591
+ * `enqueueStyleWrite` rather than queued behind the rest of the batch.
3592
+ */
3593
+ function flushStyles() {
3594
+ if (head >= queue.length) return;
3595
+ if (flushing) return;
3596
+ flushing = true;
3597
+ try {
3598
+ while (head < queue.length) {
3599
+ const entry = queue[head++];
3600
+ if (entry.cancelled) {
3601
+ entry.done = true;
3602
+ continue;
3603
+ }
3604
+ entry.run();
3605
+ entry.done = true;
3606
+ }
3607
+ } finally {
3608
+ queue = [];
3609
+ head = 0;
3610
+ flushing = false;
3611
+ }
3612
+ }
3613
+ /**
3614
+ * Dev-only: `batchInjection: true` batches nothing unless a window opens, and no
3615
+ * window has ever opened, so no provider is in the tree. Called by the injector
3616
+ * the first time it declines to batch.
3617
+ */
3618
+ function warnBatchProviderMissing() {
3619
+ if (everOpened || warnedNoProvider || !isDevEnv()) return;
3620
+ warnedNoProvider = true;
3621
+ warn("[Tasty] batchInjection needs <TastyBatchProvider> mounted to batch.");
3622
+ }
3623
+ /**
3624
+ * Drop every pending write without applying it. Test helper — production code
3625
+ * should call `flushStyles()` instead.
3626
+ */
3627
+ function resetStyleBatch() {
3628
+ queue = [];
3629
+ head = 0;
3630
+ microtaskScheduled = false;
3631
+ flushing = false;
3632
+ windowOpen = false;
3633
+ everOpened = false;
3634
+ warnedNoProvider = false;
3635
+ }
3636
+ //#endregion
3426
3637
  //#region src/properties/property-type-resolver.ts
3427
3638
  /**
3428
3639
  * PropertyTypeResolver
@@ -4777,12 +4988,6 @@ scrollMarginStyle.__lookupStyles = [
4777
4988
  "scrollMarginInline"
4778
4989
  ];
4779
4990
  //#endregion
4780
- //#region src/utils/warnings.ts
4781
- const PREFIX = "[Tasty]";
4782
- function warn(...args) {
4783
- console.warn(PREFIX, ...args);
4784
- }
4785
- //#endregion
4786
4991
  //#region src/styles/scrollbar.ts
4787
4992
  /**
4788
4993
  * Standard CSS scrollbar styling via `scrollbar-width`, `scrollbar-color`,
@@ -5455,6 +5660,8 @@ var SheetManager = class {
5455
5660
  propertyTypeResolver: new PropertyTypeResolver(),
5456
5661
  usageMap: /* @__PURE__ */ new Map(),
5457
5662
  touchCount: 0,
5663
+ touchTick: -1,
5664
+ touchedTick: /* @__PURE__ */ new Set(),
5458
5665
  serverClassSyncIndex: 0,
5459
5666
  rscStylesScanned: false,
5460
5667
  injectionMode: this.detectInjectionMode(root)
@@ -6365,6 +6572,16 @@ function formatCounterStyleRule(name, descriptors) {
6365
6572
  //#endregion
6366
6573
  //#region src/injector/injector.ts
6367
6574
  /**
6575
+ * Placeholder `KeyframesInfo` for a cache entry reserved by a batched write and
6576
+ * not yet backed by a real rule. Only ever read through `entry.pending`, which
6577
+ * is checked before the info is used.
6578
+ */
6579
+ const EMPTY_KEYFRAMES_INFO = {
6580
+ name: "",
6581
+ ruleIndex: -3,
6582
+ sheetIndex: -3
6583
+ };
6584
+ /**
6368
6585
  * Extract class names from `<style data-tasty-rsc>` tags.
6369
6586
  * The doubled-specificity pattern `.tXXX.tXXX` makes extraction reliable.
6370
6587
  */
@@ -6425,6 +6642,56 @@ var StyleInjector = class {
6425
6642
  get _sheetManager() {
6426
6643
  return this.sheetManager;
6427
6644
  }
6645
+ /**
6646
+ * Whether sheet writes should be queued instead of applied immediately.
6647
+ *
6648
+ * Only ever true on the client: SSR collects CSS as text and the RSC path
6649
+ * returns it as strings, so neither has a live sheet to batch writes against.
6650
+ *
6651
+ * In the default `true` mode a write is only queued inside an open batch
6652
+ * window — a commit in which `<TastyBatchProvider>` rendered and will
6653
+ * therefore flush in its insertion effect, before any layout effect can
6654
+ * measure. Everything else falls through to a synchronous write, so enabling
6655
+ * the flag cannot make a `useLayoutEffect` read an unstyled element.
6656
+ * `'always'` drops the gate and accepts that trade for wider coverage.
6657
+ */
6658
+ get batching() {
6659
+ const mode = this.config.batchInjection;
6660
+ if (!mode || typeof document === "undefined") return false;
6661
+ if (mode === "always") return true;
6662
+ if (isBatchWindowOpen()) return true;
6663
+ warnBatchProviderMissing();
6664
+ return false;
6665
+ }
6666
+ /**
6667
+ * Apply a sheet write now, or queue it when batching is on.
6668
+ * Returns the queue handle when deferred, so the caller can cancel it if it
6669
+ * disposes before the flush.
6670
+ */
6671
+ writeSheet(task) {
6672
+ if (this.batching) return enqueueStyleWrite(task);
6673
+ task();
6674
+ return null;
6675
+ }
6676
+ /**
6677
+ * Insert a global (non-class) rule, honouring batching.
6678
+ *
6679
+ * `onApplied` records the caller's dedupe bookkeeping. When the write is
6680
+ * queued it runs eagerly, so a repeat call before the flush bails out instead
6681
+ * of queueing the same rule twice — the same reasoning as
6682
+ * `insertPropertyRule`'s eager marking. When written synchronously it runs
6683
+ * only on success, preserving the existing retry-on-failure behaviour.
6684
+ */
6685
+ writeGlobalRule(registry, rules, key, root, onApplied) {
6686
+ if (this.batching) {
6687
+ onApplied?.();
6688
+ enqueueStyleWrite(() => {
6689
+ this.sheetManager.insertGlobalRule(registry, rules, key, root);
6690
+ });
6691
+ return;
6692
+ }
6693
+ if (this.sheetManager.insertGlobalRule(registry, rules, key, root)) onApplied?.();
6694
+ }
6428
6695
  constructor(config = {}) {
6429
6696
  if (config.namePrefix !== void 0) validateNamePrefix(config.namePrefix);
6430
6697
  this.config = config;
@@ -6502,12 +6769,18 @@ var StyleInjector = class {
6502
6769
  };
6503
6770
  const cacheKey = options?.cacheKey;
6504
6771
  let className;
6505
- let isPreAllocated = false;
6506
6772
  if (cacheKey && registry.cacheKeyToClassName.has(cacheKey)) {
6507
6773
  className = registry.cacheKeyToClassName.get(cacheKey);
6508
6774
  const existingRuleInfo = registry.rules.get(className);
6509
- isPreAllocated = existingRuleInfo.ruleIndex === -1 && existingRuleInfo.sheetIndex === -1;
6510
- if (!isPreAllocated) {
6775
+ if (existingRuleInfo.ruleIndex === -3) {
6776
+ registry.refCounts.set(className, (registry.refCounts.get(className) || 0) + 1);
6777
+ if (registry.metrics) registry.metrics.hits++;
6778
+ return {
6779
+ className,
6780
+ dispose: () => this.dispose(className, registry)
6781
+ };
6782
+ }
6783
+ if (!(existingRuleInfo.ruleIndex === -1 && existingRuleInfo.sheetIndex === -1)) {
6511
6784
  const currentRefCount = registry.refCounts.get(className) || 0;
6512
6785
  registry.refCounts.set(className, currentRefCount + 1);
6513
6786
  if (registry.metrics) registry.metrics.hits++;
@@ -6548,39 +6821,70 @@ var StyleInjector = class {
6548
6821
  rootPrefix: void 0
6549
6822
  };
6550
6823
  });
6551
- if (this.config.autoPropertyTypes !== false) {
6552
- const resolver = registry.propertyTypeResolver;
6553
- const defined = registry.injectedProperties;
6554
- for (const rule of rulesToInsert) {
6555
- if (!rule.declarations) continue;
6556
- resolver.scanDeclarations(rule.declarations, (name) => defined.has(name), (name, syntax, initialValue) => {
6557
- this.property(name, {
6558
- syntax,
6559
- inherits: true,
6560
- initialValue,
6561
- root
6824
+ const applySheetWrite = () => {
6825
+ if (this.config.autoPropertyTypes !== false) {
6826
+ const resolver = registry.propertyTypeResolver;
6827
+ const defined = registry.injectedProperties;
6828
+ for (const rule of rulesToInsert) {
6829
+ if (!rule.declarations) continue;
6830
+ resolver.scanDeclarations(rule.declarations, (name) => defined.has(name), (name, syntax, initialValue) => {
6831
+ this.property(name, {
6832
+ syntax,
6833
+ inherits: true,
6834
+ initialValue,
6835
+ root
6836
+ });
6562
6837
  });
6563
- });
6838
+ }
6564
6839
  }
6565
- }
6566
- const ruleInfo = this.sheetManager.insertRule(registry, rulesToInsert, className, root);
6567
- if (!ruleInfo) {
6568
- if (registry.metrics) registry.metrics.misses++;
6840
+ const ruleInfo = this.sheetManager.insertRule(registry, rulesToInsert, className, root);
6841
+ if (!ruleInfo) {
6842
+ if (registry.metrics) registry.metrics.misses++;
6843
+ return null;
6844
+ }
6845
+ registry.rules.set(className, ruleInfo);
6846
+ if (cacheKey) registry.cacheKeyToClassName.set(cacheKey, className);
6847
+ if (registry.metrics) {
6848
+ registry.metrics.totalInsertions++;
6849
+ registry.metrics.misses++;
6850
+ }
6851
+ return ruleInfo;
6852
+ };
6853
+ if (this.batching) {
6854
+ registry.rules.set(className, {
6855
+ className,
6856
+ ruleIndex: -3,
6857
+ sheetIndex: -3
6858
+ });
6859
+ if (cacheKey) registry.cacheKeyToClassName.set(cacheKey, className);
6860
+ registry.refCounts.set(className, 1);
6861
+ const queued = enqueueStyleWrite(() => {
6862
+ if (applySheetWrite()) return;
6863
+ registry.rules.set(className, {
6864
+ className,
6865
+ ruleIndex: -1,
6866
+ sheetIndex: -1
6867
+ });
6868
+ });
6569
6869
  return {
6570
6870
  className,
6571
- dispose: () => {}
6871
+ dispose: () => {
6872
+ if (!queued.done && registry.refCounts.get(className) === 1 && registry.rules.get(className)?.ruleIndex === -3) {
6873
+ queued.cancelled = true;
6874
+ registry.rules.delete(className);
6875
+ if (cacheKey) registry.cacheKeyToClassName.delete(cacheKey);
6876
+ registry.refCounts.set(className, 0);
6877
+ return;
6878
+ }
6879
+ this.dispose(className, registry);
6880
+ }
6572
6881
  };
6573
6882
  }
6883
+ if (!applySheetWrite()) return {
6884
+ className,
6885
+ dispose: () => {}
6886
+ };
6574
6887
  registry.refCounts.set(className, 1);
6575
- if (isPreAllocated) registry.rules.set(className, ruleInfo);
6576
- else {
6577
- registry.rules.set(className, ruleInfo);
6578
- if (cacheKey) registry.cacheKeyToClassName.set(cacheKey, className);
6579
- }
6580
- if (registry.metrics) {
6581
- registry.metrics.totalInsertions++;
6582
- registry.metrics.misses++;
6583
- }
6584
6888
  return {
6585
6889
  className,
6586
6890
  dispose: () => this.dispose(className, registry)
@@ -6595,24 +6899,41 @@ var StyleInjector = class {
6595
6899
  const root = options?.root || document;
6596
6900
  const registry = this.sheetManager.getRegistry(root);
6597
6901
  if (!rules || rules.length === 0) return { dispose: () => {} };
6598
- if (this.config.autoPropertyTypes !== false) {
6599
- const resolver = registry.propertyTypeResolver;
6600
- const defined = registry.injectedProperties;
6601
- for (const rule of rules) {
6602
- if (!rule.declarations) continue;
6603
- resolver.scanDeclarations(rule.declarations, (name) => defined.has(name), (name, syntax, initialValue) => {
6604
- this.property(name, {
6605
- syntax,
6606
- inherits: true,
6607
- initialValue,
6608
- root
6902
+ const key = `global:${this.globalRuleCounter++}`;
6903
+ const applyWrite = () => {
6904
+ if (this.config.autoPropertyTypes !== false) {
6905
+ const resolver = registry.propertyTypeResolver;
6906
+ const defined = registry.injectedProperties;
6907
+ for (const rule of rules) {
6908
+ if (!rule.declarations) continue;
6909
+ resolver.scanDeclarations(rule.declarations, (name) => defined.has(name), (name, syntax, initialValue) => {
6910
+ this.property(name, {
6911
+ syntax,
6912
+ inherits: true,
6913
+ initialValue,
6914
+ root
6915
+ });
6609
6916
  });
6610
- });
6917
+ }
6611
6918
  }
6919
+ const inserted = this.sheetManager.insertGlobalRule(registry, rules, key, root);
6920
+ if (registry.metrics) registry.metrics.totalInsertions++;
6921
+ return inserted;
6922
+ };
6923
+ if (this.batching) {
6924
+ let info = null;
6925
+ const queued = enqueueStyleWrite(() => {
6926
+ info = applyWrite();
6927
+ });
6928
+ return { dispose: () => {
6929
+ if (!queued.done) {
6930
+ queued.cancelled = true;
6931
+ return;
6932
+ }
6933
+ if (info) this.sheetManager.deleteGlobalRule(registry, key);
6934
+ } };
6612
6935
  }
6613
- const key = `global:${this.globalRuleCounter++}`;
6614
- const info = this.sheetManager.insertGlobalRule(registry, rules, key, root);
6615
- if (registry.metrics) registry.metrics.totalInsertions++;
6936
+ const info = applyWrite();
6616
6937
  return { dispose: () => {
6617
6938
  if (info) this.sheetManager.deleteGlobalRule(registry, key);
6618
6939
  } };
@@ -6624,12 +6945,24 @@ var StyleInjector = class {
6624
6945
  */
6625
6946
  injectRawCSS(css, options) {
6626
6947
  const root = options?.root || document;
6627
- return this.sheetManager.injectRawCSS(css, root);
6948
+ if (!this.batching) return this.sheetManager.injectRawCSS(css, root);
6949
+ let result = null;
6950
+ const queued = enqueueStyleWrite(() => {
6951
+ result = this.sheetManager.injectRawCSS(css, root);
6952
+ });
6953
+ return { dispose: () => {
6954
+ if (!queued.done) {
6955
+ queued.cancelled = true;
6956
+ return;
6957
+ }
6958
+ result?.dispose();
6959
+ } };
6628
6960
  }
6629
6961
  /**
6630
6962
  * Get raw CSS text for SSR
6631
6963
  */
6632
6964
  getRawCSSText(options) {
6965
+ flushStyles();
6633
6966
  const root = options?.root || document;
6634
6967
  return this.sheetManager.getRawCSSText(root);
6635
6968
  }
@@ -6666,6 +6999,7 @@ var StyleInjector = class {
6666
6999
  * Force bulk cleanup of unused styles
6667
7000
  */
6668
7001
  cleanup(root) {
7002
+ flushStyles();
6669
7003
  const registry = this.sheetManager.getRegistry(root || document);
6670
7004
  this.sheetManager.forceCleanup(registry);
6671
7005
  }
@@ -6673,6 +7007,7 @@ var StyleInjector = class {
6673
7007
  * Get CSS text from all sheets (for SSR)
6674
7008
  */
6675
7009
  getCSSText(options) {
7010
+ flushStyles();
6676
7011
  const root = options?.root || document;
6677
7012
  const registry = this.sheetManager.getRegistry(root);
6678
7013
  return this.sheetManager.getCSSText(registry);
@@ -6681,6 +7016,7 @@ var StyleInjector = class {
6681
7016
  * Get CSS only for the provided tasty classNames (e.g., ["t0","t3"])
6682
7017
  */
6683
7018
  getCSSTextForClasses(classNames, options) {
7019
+ flushStyles();
6684
7020
  const root = options?.root || document;
6685
7021
  const registry = this.sheetManager.getRegistry(root);
6686
7022
  const cssChunks = [];
@@ -6705,6 +7041,7 @@ var StyleInjector = class {
6705
7041
  * Get cache performance metrics
6706
7042
  */
6707
7043
  getMetrics(options) {
7044
+ flushStyles();
6708
7045
  const root = options?.root || document;
6709
7046
  const registry = this.sheetManager.getRegistry(root);
6710
7047
  return this.sheetManager.getMetrics(registry);
@@ -6784,7 +7121,7 @@ var StyleInjector = class {
6784
7121
  declarations
6785
7122
  };
6786
7123
  registry.injectedProperties.set(cssName, normalizePropertyDefinition(definition));
6787
- this.sheetManager.insertGlobalRule(registry, [rule], `property:${cacheKey}`, root);
7124
+ this.writeGlobalRule(registry, [rule], `property:${cacheKey}`, root);
6788
7125
  }
6789
7126
  /**
6790
7127
  * Check whether a given @property name was already injected by this injector.
@@ -6795,6 +7132,7 @@ var StyleInjector = class {
6795
7132
  * - `--name` → checks `--name` (legacy format)
6796
7133
  */
6797
7134
  isPropertyDefined(name, options) {
7135
+ flushStyles();
6798
7136
  const root = options?.root || document;
6799
7137
  const registry = this.sheetManager.getRegistry(root);
6800
7138
  const effectiveResult = getEffectiveDefinition(name, {});
@@ -6816,7 +7154,9 @@ var StyleInjector = class {
6816
7154
  selector: "@font-face",
6817
7155
  declarations: formatFontFaceDeclarations(family, descriptors)
6818
7156
  };
6819
- if (this.sheetManager.insertGlobalRule(registry, [rule], `fontface:${hash}`, root)) registry.injectedFontFaces.add(hash);
7157
+ this.writeGlobalRule(registry, [rule], `fontface:${hash}`, root, () => {
7158
+ registry.injectedFontFaces.add(hash);
7159
+ });
6820
7160
  }
6821
7161
  /**
6822
7162
  * Inject a CSS @counter-style rule.
@@ -6834,13 +7174,17 @@ var StyleInjector = class {
6834
7174
  const existingIsStrong = registry.injectedCounterStyles.get(name);
6835
7175
  if (existingIsStrong !== void 0) {
6836
7176
  if (isWeak || existingIsStrong === true) return;
6837
- this.sheetManager.deleteGlobalRule(registry, `counterstyle:${name}`);
7177
+ this.writeSheet(() => {
7178
+ this.sheetManager.deleteGlobalRule(registry, `counterstyle:${name}`);
7179
+ });
6838
7180
  }
6839
7181
  const rule = {
6840
7182
  selector: `@counter-style ${name}`,
6841
7183
  declarations: formatCounterStyleDeclarations(descriptors)
6842
7184
  };
6843
- if (this.sheetManager.insertGlobalRule(registry, [rule], `counterstyle:${name}`, root)) registry.injectedCounterStyles.set(name, !isWeak);
7185
+ this.writeGlobalRule(registry, [rule], `counterstyle:${name}`, root, () => {
7186
+ registry.injectedCounterStyles.set(name, !isWeak);
7187
+ });
6844
7188
  }
6845
7189
  /**
6846
7190
  * Inject a CSS @function rule (custom function).
@@ -6859,13 +7203,17 @@ var StyleInjector = class {
6859
7203
  const existingIsStrong = registry.injectedFunctions.get(cssName);
6860
7204
  if (existingIsStrong !== void 0) {
6861
7205
  if (isWeak || existingIsStrong === true) return;
6862
- this.sheetManager.deleteGlobalRule(registry, `function:${cssName}`);
7206
+ this.writeSheet(() => {
7207
+ this.sheetManager.deleteGlobalRule(registry, `function:${cssName}`);
7208
+ });
6863
7209
  }
6864
7210
  const rule = {
6865
7211
  selector: formatFunctionPrelude(name, definition.args, definition.returns),
6866
7212
  declarations: formatFunctionDeclarations(definition)
6867
7213
  };
6868
- if (this.sheetManager.insertGlobalRule(registry, [rule], `function:${cssName}`, root)) registry.injectedFunctions.set(cssName, !isWeak);
7214
+ this.writeGlobalRule(registry, [rule], `function:${cssName}`, root, () => {
7215
+ registry.injectedFunctions.set(cssName, !isWeak);
7216
+ });
6869
7217
  }
6870
7218
  /**
6871
7219
  * Inject keyframes and return object with toString() and dispose()
@@ -6903,29 +7251,53 @@ var StyleInjector = class {
6903
7251
  registry.keyframesNameToContent.set(providedName, contentHash);
6904
7252
  }
6905
7253
  } else actualName = makeKeyframeName(this.namePrefix, String(registry.keyframesCounter++));
6906
- const result = this.sheetManager.insertKeyframes(registry, steps, actualName, root);
6907
- if (!result) return {
6908
- toString: () => "",
6909
- dispose: () => {}
7254
+ const applyWrite = () => {
7255
+ const result = this.sheetManager.insertKeyframes(registry, steps, actualName, root);
7256
+ if (!result) return false;
7257
+ const { info, declarations } = result;
7258
+ if (this.config.autoPropertyTypes !== false && declarations) registry.propertyTypeResolver.scanDeclarations(declarations, (name) => registry.injectedProperties.has(name), (name, syntax, initialValue) => {
7259
+ this.property(name, {
7260
+ syntax,
7261
+ inherits: true,
7262
+ initialValue,
7263
+ root
7264
+ });
7265
+ });
7266
+ const entry = registry.keyframesCache.get(contentHash);
7267
+ if (entry) {
7268
+ entry.info = info;
7269
+ entry.pending = void 0;
7270
+ } else registry.keyframesCache.set(contentHash, {
7271
+ name: actualName,
7272
+ refCount: 1,
7273
+ info
7274
+ });
7275
+ if (registry.metrics) {
7276
+ registry.metrics.totalInsertions++;
7277
+ registry.metrics.misses++;
7278
+ }
7279
+ return true;
6910
7280
  };
6911
- const { info, declarations } = result;
6912
- if (this.config.autoPropertyTypes !== false && declarations) registry.propertyTypeResolver.scanDeclarations(declarations, (name) => registry.injectedProperties.has(name), (name, syntax, initialValue) => {
6913
- this.property(name, {
6914
- syntax,
6915
- inherits: true,
6916
- initialValue,
6917
- root
7281
+ if (this.batching) {
7282
+ const entry = {
7283
+ name: actualName,
7284
+ refCount: 1,
7285
+ info: EMPTY_KEYFRAMES_INFO
7286
+ };
7287
+ registry.keyframesCache.set(contentHash, entry);
7288
+ entry.pending = enqueueStyleWrite(() => {
7289
+ if (applyWrite()) return;
7290
+ if (registry.keyframesCache.get(contentHash) === entry) registry.keyframesCache.delete(contentHash);
6918
7291
  });
6919
- });
6920
- registry.keyframesCache.set(contentHash, {
6921
- name: actualName,
6922
- refCount: 1,
6923
- info
6924
- });
6925
- if (registry.metrics) {
6926
- registry.metrics.totalInsertions++;
6927
- registry.metrics.misses++;
7292
+ return {
7293
+ toString: () => actualName,
7294
+ dispose: () => this.disposeKeyframes(contentHash, registry)
7295
+ };
6928
7296
  }
7297
+ if (!applyWrite()) return {
7298
+ toString: () => "",
7299
+ dispose: () => {}
7300
+ };
6929
7301
  return {
6930
7302
  toString: () => actualName,
6931
7303
  dispose: () => this.disposeKeyframes(contentHash, registry)
@@ -6939,7 +7311,8 @@ var StyleInjector = class {
6939
7311
  if (!entry) return;
6940
7312
  entry.refCount--;
6941
7313
  if (entry.refCount <= 0) {
6942
- this.sheetManager.deleteKeyframes(registry, entry.info);
7314
+ if (entry.pending && !entry.pending.done) entry.pending.cancelled = true;
7315
+ else this.sheetManager.deleteKeyframes(registry, entry.info);
6943
7316
  registry.keyframesCache.delete(contentHash);
6944
7317
  for (const [name, hash] of registry.keyframesNameToContent.entries()) if (hash === contentHash) {
6945
7318
  registry.keyframesNameToContent.delete(name);
@@ -6964,6 +7337,11 @@ var StyleInjector = class {
6964
7337
  const root = options?.root || document;
6965
7338
  const registry = this.sheetManager.getRegistry(root);
6966
7339
  const now = Date.now();
7340
+ if (registry.touchTick !== now) {
7341
+ registry.touchTick = now;
7342
+ registry.touchedTick.clear();
7343
+ } else if (registry.touchedTick.has(className)) return;
7344
+ registry.touchedTick.add(className);
6967
7345
  const parts = className.indexOf(" ") === -1 ? [className] : className.split(" ");
6968
7346
  for (const cls of parts) {
6969
7347
  if (!this.classRegex.test(cls)) continue;
@@ -7004,6 +7382,7 @@ var StyleInjector = class {
7004
7382
  * @returns Number of styles evicted.
7005
7383
  */
7006
7384
  gc(options) {
7385
+ flushStyles();
7007
7386
  if (typeof document === "undefined") return 0;
7008
7387
  if (this.pendingGCHandle != null) {
7009
7388
  if (typeof cancelIdleCallback !== "undefined") cancelIdleCallback(this.pendingGCHandle);
@@ -7053,6 +7432,7 @@ var StyleInjector = class {
7053
7432
  * Destroy all resources for a root
7054
7433
  */
7055
7434
  destroy(root) {
7435
+ flushStyles();
7056
7436
  const targetRoot = root || document;
7057
7437
  this.sheetManager.cleanup(targetRoot);
7058
7438
  if (this.pendingGCHandle != null && !this.sheetManager.hasActiveRoots()) {
@@ -12501,6 +12881,6 @@ function resetConfig() {
12501
12881
  delete storage[GLOBAL_INJECTOR_KEY];
12502
12882
  }
12503
12883
  //#endregion
12504
- export { SheetManager as $, overrideColorAlpha as $t, FLOW_STYLES as A, registerFunctionPolyfill as At, createStateParserContext as B, stringifyStyles as Bt, BASE_STYLES as C, LAYOUT_CHUNK_STYLES as Ct, COLOR_STYLES as D, formatFunctionRule as Dt, BLOCK_STYLES as E, extractLocalFunctions as Et, hasPipelineCacheEntry as F, getGlobalParser as Ft, StyleInjector as G, createColorFunc as Gt, extractPredefinedStateRefs as H, okhstPlugin as Ht, isSelector as I, getGlobalPredefinedTokens as It, hasLocalCounterStyle as J, colorInitialValueToComponents as Jt, extractLocalCounterStyle as K, isDevEnv as Kt, renderStyles as L, normalizeColorTokenValue as Lt, OUTER_STYLES as M, CUSTOM_UNITS as Mt, POSITION_STYLES as N, DIRECTIONS as Nt, CONTAINER_STYLES as O, hasLocalFunctions as Ot, TEXT_STYLES as P, filterMods as Pt, hasLocalFontFace as Q, getComponentPropertySyntax as Qt, parseStateKey as R, parseColor as Rt, baseStylePropsRegistry as S, FONT_CHUNK_STYLES as St, BLOCK_OUTER_STYLES as T, STYLE_TO_CHUNK as Tt, getGlobalPredefinedStates as U, okhslFunction as Ut, extractLocalPredefinedStates as V, okhstFunction as Vt, setGlobalPredefinedStates as W, okhslPlugin as Wt, fontFaceContentHash as X, getColorSpaceComponents as Xt, extractLocalFontFace as Y, convertColorChainToComponentChain as Yt, formatFontFaceRule as Z, getColorSpaceSuffix as Zt, isFunctionsPolyfillEnabled as _, propHandlerRegistry as _t, getGlobalCounterStyles as a, hslToRgbValues as an, DEFAULT_NAME_PREFIX as at, resetConfig as b, DIMENSION_CHUNK_STYLES as bt, getGlobalInjector as c, makeCounterStyleName as ct, getGlobalStyles as d, validateNamePrefix as dt, resolveFunctionColor as en, STYLE_HANDLER_MAP as et, getNamePrefix as f, hashString as ft, isConfigLocked as g, parsePropertyToken as gt, hasStylesGenerated as h, hasLocalProperties as ht, getGlobalConfigTokens as i, hexToRgb as in, PropertyTypeResolver as it, INNER_STYLES as j, registerLocalFunctionPolyfills as jt, DIMENSION_STYLES as k, parseFunctionName as kt, getGlobalKeyframes as l, makeKeyframeName as lt, hasGlobalRecipes as m, getEffectiveDefinition as mt, getConfig as n, getNamedColorHex as nn, styleHandlers as nt, getGlobalFontFaces as o, strToRgb as on, DEFAULT_ZERO_NAME_PREFIX as ot, hasGlobalKeyframes as p, extractLocalProperties as pt, formatCounterStyleRule as q, StyleParser as qt, getEffectiveProperties as r, getRgbValuesFromRgbaString as rn, createStyle as rt, getGlobalFunctions as s, normalizeDslName as sn, makeClassName as st, configure as t, Lru as tn, defineHandler as tt, getGlobalRecipes as u, tastyClassRegex as ut, isTestEnvironment as v, APPEARANCE_CHUNK_STYLES as vt, BLOCK_INNER_STYLES as w, POSITION_CHUNK_STYLES as wt, generateTypographyTokens as x, DISPLAY_CHUNK_STYLES as xt, markStylesGenerated as y, CHUNK_NAMES as yt, camelToKebab as z, parseStyle as zt };
12884
+ export { SheetManager as $, colorInitialValueToComponents as $t, FLOW_STYLES as A, STYLE_TO_CHUNK as At, createStateParserContext as B, getGlobalParser 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, stringifyStyles as Gt, extractPredefinedStateRefs as H, normalizeColorTokenValue as Ht, isSelector as I, registerLocalFunctionPolyfills as It, hasLocalCounterStyle as J, okhslFunction as Jt, extractLocalCounterStyle as K, okhstFunction 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, StyleParser 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, parseColor as Ut, extractLocalPredefinedStates as V, getGlobalPredefinedTokens as Vt, setGlobalPredefinedStates as W, parseStyle as Wt, fontFaceContentHash as X, createColorFunc as Xt, extractLocalFontFace as Y, okhslPlugin as Yt, formatFontFaceRule as Z, isDevEnv as Zt, isFunctionsPolyfillEnabled as _, hashString as _t, getGlobalCounterStyles as a, resolveFunctionColor as an, closeBatchWindow as at, resetConfig as b, hasLocalProperties as bt, getGlobalInjector as c, getRgbValuesFromRgbaString as cn, openBatchWindow as ct, getGlobalStyles as d, strToRgb as dn, DEFAULT_ZERO_NAME_PREFIX as dt, convertColorChainToComponentChain as en, STYLE_HANDLER_MAP as et, getNamePrefix as f, normalizeDslName as fn, makeClassName as ft, isConfigLocked as g, validateNamePrefix as gt, hasStylesGenerated as h, tastyClassRegex as ht, getGlobalConfigTokens as i, overrideColorAlpha as in, PropertyTypeResolver as it, INNER_STYLES as j, extractLocalFunctions as jt, DIMENSION_STYLES as k, POSITION_CHUNK_STYLES as kt, getGlobalKeyframes as l, hexToRgb as ln, resetStyleBatch as lt, hasGlobalRecipes as m, makeKeyframeName as mt, getConfig as n, getColorSpaceSuffix as nn, styleHandlers as nt, getGlobalFontFaces as o, Lru as on, flushStyles as ot, hasGlobalKeyframes as p, makeCounterStyleName as pt, formatCounterStyleRule as q, okhstPlugin as qt, getEffectiveProperties as r, getComponentPropertySyntax as rn, createStyle as rt, getGlobalFunctions as s, getNamedColorHex as sn, hasPendingStyleWrites as st, configure as t, getColorSpaceComponents as tn, defineHandler as tt, getGlobalRecipes as u, hslToRgbValues as un, 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 };
12505
12885
 
12506
- //# sourceMappingURL=config-CwQ-fAsp.js.map
12886
+ //# sourceMappingURL=config-BrDt11hO.js.map