@tenphi/tasty 3.7.0 → 3.9.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 (103) hide show
  1. package/dist/{babel-DWCsafYw.d.ts → babel-Zs1Q03qt.d.ts} +2 -2
  2. package/dist/chunks/async-storage-CG5HnUT5.js +20 -0
  3. package/dist/chunks/async-storage-CG5HnUT5.js.map +1 -0
  4. package/dist/chunks/build-config-CUQVwdWF.js +42 -0
  5. package/dist/chunks/build-config-CUQVwdWF.js.map +1 -0
  6. package/dist/{collector-B3OsM252.js → chunks/collector-B0LTHw6Z.js} +6 -125
  7. package/dist/chunks/collector-B0LTHw6Z.js.map +1 -0
  8. package/dist/chunks/config-engine-C3pF9EK9.js +267 -0
  9. package/dist/chunks/config-engine-C3pF9EK9.js.map +1 -0
  10. package/dist/chunks/css-definitions-D_it4XZH.js +875 -0
  11. package/dist/chunks/css-definitions-D_it4XZH.js.map +1 -0
  12. package/dist/{css-resources-Cyl_axbI.js → chunks/css-resources-BN8apgxt.js} +1 -8
  13. package/dist/chunks/css-resources-BN8apgxt.js.map +1 -0
  14. package/dist/chunks/debug-C9LeNVoJ.js +501 -0
  15. package/dist/chunks/debug-C9LeNVoJ.js.map +1 -0
  16. package/dist/chunks/dsl-C5yuAn41.js +1373 -0
  17. package/dist/chunks/dsl-C5yuAn41.js.map +1 -0
  18. package/dist/chunks/hydration-TRcz5vnk.js +41 -0
  19. package/dist/chunks/hydration-TRcz5vnk.js.map +1 -0
  20. package/dist/chunks/react-runtime-O-OUrKLH.js +557 -0
  21. package/dist/chunks/react-runtime-O-OUrKLH.js.map +1 -0
  22. package/dist/chunks/runtime-engine-DvnE2g-E.js +2437 -0
  23. package/dist/chunks/runtime-engine-DvnE2g-E.js.map +1 -0
  24. package/dist/chunks/runtime-state-BTDqSYBk.js +127 -0
  25. package/dist/chunks/runtime-state-BTDqSYBk.js.map +1 -0
  26. package/dist/{merge-styles-DuoZEsm9.js → chunks/shared-utils-DWA4LjIa.js} +55 -54
  27. package/dist/chunks/shared-utils-DWA4LjIa.js.map +1 -0
  28. package/dist/chunks/style-engine-C1ECBZxR.js +5131 -0
  29. package/dist/chunks/style-engine-C1ECBZxR.js.map +1 -0
  30. package/dist/{css-writer-Bgowobbx.js → chunks/zero-engine-B6EnYcXY.js} +3 -120
  31. package/dist/chunks/zero-engine-B6EnYcXY.js.map +1 -0
  32. package/dist/{collector-BTVXj2hS.d.ts → collector-hl5KNH7k.d.ts} +6 -4
  33. package/dist/{config-LfIDmVHx.d.ts → config-DWL1ZYue.d.ts} +20 -25
  34. package/dist/core/index.d.ts +5 -5
  35. package/dist/core/index.js +9 -6
  36. package/dist/{index-Bm9ltvdH.d.ts → index-D9N9GV24.d.ts} +96 -82
  37. package/dist/index.d.ts +5 -5
  38. package/dist/index.js +11 -922
  39. package/dist/{merge-styles-BcLl1u_d.d.ts → merge-styles-C_oMoJVd.d.ts} +2 -2
  40. package/dist/ssr/astro-client.js +1 -14
  41. package/dist/ssr/astro-client.js.map +1 -1
  42. package/dist/ssr/astro-middleware-extract-static.js +1 -1
  43. package/dist/ssr/astro-middleware-extract.js +1 -1
  44. package/dist/ssr/astro-middleware-static.js +1 -12
  45. package/dist/ssr/astro-middleware-static.js.map +1 -1
  46. package/dist/ssr/astro-middleware.js +1 -13
  47. package/dist/ssr/astro-middleware.js.map +1 -1
  48. package/dist/ssr/astro.js +219 -1
  49. package/dist/ssr/astro.js.map +1 -0
  50. package/dist/ssr/index.d.ts +6 -6
  51. package/dist/ssr/index.js +4 -4
  52. package/dist/ssr/next-config.d.ts +1 -1
  53. package/dist/ssr/next-config.js +29 -20
  54. package/dist/ssr/next-config.js.map +1 -1
  55. package/dist/ssr/next.d.ts +1 -1
  56. package/dist/ssr/next.js +5 -37
  57. package/dist/ssr/next.js.map +1 -1
  58. package/dist/static/index.d.ts +2 -2
  59. package/dist/static/index.js +1 -19
  60. package/dist/static/index.js.map +1 -1
  61. package/dist/{index-BmogEzTo.d.ts → types-jKZNpias.d.ts} +845 -804
  62. package/dist/zero/babel.d.ts +1 -1
  63. package/dist/zero/babel.js +25 -96
  64. package/dist/zero/babel.js.map +1 -1
  65. package/dist/zero/index.d.ts +1 -1
  66. package/dist/zero/index.js +1 -1
  67. package/dist/zero/next.d.ts +1 -1
  68. package/dist/zero/next.js +0 -31
  69. package/dist/zero/next.js.map +1 -1
  70. package/docs/ai-agents.md +8 -3
  71. package/docs/debug.md +2 -5
  72. package/docs/methodology.md +3 -3
  73. package/docs/pipeline.md +3 -0
  74. package/docs/runtime-benchmarks.md +105 -68
  75. package/docs/styles.md +43 -11
  76. package/package.json +48 -5
  77. package/dist/astro-CeYENy2x.js +0 -301
  78. package/dist/astro-CeYENy2x.js.map +0 -1
  79. package/dist/async-storage-DKK-wTD4.js +0 -44
  80. package/dist/async-storage-DKK-wTD4.js.map +0 -1
  81. package/dist/collector-B3OsM252.js.map +0 -1
  82. package/dist/config-B3gPdCqd.js +0 -12421
  83. package/dist/config-B3gPdCqd.js.map +0 -1
  84. package/dist/context-CA8YKeMn.js +0 -24
  85. package/dist/context-CA8YKeMn.js.map +0 -1
  86. package/dist/core-DGm0CFHP.js +0 -1732
  87. package/dist/core-DGm0CFHP.js.map +0 -1
  88. package/dist/css-resources-Cyl_axbI.js.map +0 -1
  89. package/dist/css-writer-Bgowobbx.js.map +0 -1
  90. package/dist/format-global-rules-DklyaXv-.js +0 -22
  91. package/dist/format-global-rules-DklyaXv-.js.map +0 -1
  92. package/dist/format-rules-XRw9u7d4.js +0 -104
  93. package/dist/format-rules-XRw9u7d4.js.map +0 -1
  94. package/dist/hydrate-CNOmZprz.js +0 -37
  95. package/dist/hydrate-CNOmZprz.js.map +0 -1
  96. package/dist/index.js.map +0 -1
  97. package/dist/keyframes-DE-OE76F.js +0 -535
  98. package/dist/keyframes-DE-OE76F.js.map +0 -1
  99. package/dist/merge-styles-DuoZEsm9.js.map +0 -1
  100. package/dist/resolve-recipes-H9NqOQuP.js +0 -144
  101. package/dist/resolve-recipes-H9NqOQuP.js.map +0 -1
  102. package/dist/ssr-collector-ref-COs_ioWl.js +0 -29
  103. package/dist/ssr-collector-ref-COs_ioWl.js.map +0 -1
@@ -1,599 +1,105 @@
1
1
  import { Properties } from "csstype";
2
2
 
3
- //#region src/properties/property-type-resolver.d.ts
4
- /**
5
- * PropertyTypeResolver
6
- *
7
- * Automatically infers CSS @property types from custom property values.
8
- * Supports deferred resolution for var() reference chains of arbitrary depth.
9
- */
10
- declare class PropertyTypeResolver {
11
- /** propName → the prop it depends on */
12
- private pendingDeps;
13
- /** propName → list of props waiting on it */
14
- private reverseDeps;
15
- /**
16
- * Scan CSS declarations and auto-register @property for custom properties
17
- * whose types can be inferred from their values.
18
- */
19
- scanDeclarations(declarations: string, isPropertyDefined: (name: string) => boolean, registerProperty: (name: string, syntax: string, initialValue: string) => void): void;
20
- private addDependency;
21
- private resolve;
22
- private isComplexValue;
23
- }
3
+ //#region src/utils/css-types.d.ts
4
+ interface CSSProperties extends Properties<string | number> {}
24
5
  //#endregion
25
- //#region src/injector/batch.d.ts
6
+ //#region src/parser/types.d.ts
26
7
  /**
27
- * Deferred CSSOM writes ("batched injection").
28
- *
29
- * Every `insertRule()` on a live stylesheet invalidates style for the sheet's
30
- * scope, so Blink recalculates style the next time anything reads layout or
31
- * computed style. When components inject during React's render phase and other
32
- * components read layout in the same pass, the two interleave:
33
- *
34
- * inject -> read (forced recalc) -> inject -> read (forced recalc) -> ...
35
- *
36
- * Batching moves every sheet write out from between those reads. Writes are
37
- * queued in FIFO order and drained in one go, so the tree is invalidated once
38
- * per flush instead of once per component.
39
- *
40
- * ## Ordering
41
- *
42
- * A single queue holds *all* writes — component rules, global rules, keyframes,
43
- * `@property`, `@font-face`, `@counter-style`, `@function` and raw CSS. Draining
44
- * it in insertion order keeps the sheet byte-identical to unbatched output,
45
- * which matters because equal-specificity rules resolve by document order.
46
- *
47
- * ## Batch windows — why queuing is safe
48
- *
49
- * Deferring a write past React's layout phase would let a `useLayoutEffect`
50
- * measure an element whose rules are not in the sheet yet, reading the unstyled
51
- * box. `<TastyBatchProvider>` closes that hole by opening a *window* during its
52
- * render and closing it — flushing — in its `useInsertionEffect`, which React
53
- * runs in the mutation phase, before any layout effect:
54
- *
55
- * provider renders -> window OPEN
56
- * children render -> injections queued
57
- * provider insertionEffect -> FLUSH, window CLOSED
58
- * layout effects run -> rules are in the sheet
59
- *
60
- * So in the default (`batchInjection: true`) mode a write is only ever queued
61
- * inside a commit whose flush is already guaranteed by that same commit. Every
62
- * injection outside a window — a deep update the provider did not re-render
63
- * for, a `useLayoutEffect` that injects, an event handler, an async callback —
64
- * is written straight through, exactly as with batching off.
65
- *
66
- * `batchInjection: 'always'` opts out of the gate and queues unconditionally.
67
- * That wins on more commits, at the cost of the measurement hazard above.
68
- *
69
- * ## Flush points (earliest wins)
70
- *
71
- * 1. `<TastyBatchProvider>`'s `useInsertionEffect` — closes the window.
72
- * 2. A microtask — a backstop for a render that was aborted or suspended and
73
- * therefore never reached its insertion effect. An aborted render mounts
74
- * nothing, so nothing can measure what it queued. Microtasks also always
75
- * drain before paint, so styles are never visually missing.
76
- * 3. `flushStyles()` — explicit, and called internally by every injector read
77
- * API (`getCSSText`, `cleanup`, `gc`, `destroy`, ...).
8
+ * A part within a group, representing a slash-separated segment.
9
+ * For example, in `'2px solid #red / 4px'`, there are two parts:
10
+ * - Part 0: `2px solid #red`
11
+ * - Part 1: `4px`
78
12
  */
79
- interface QueuedWrite {
80
- /** Perform the deferred sheet write. */
81
- run: () => void;
82
- /** Set when the owner disposed before the write happened. */
83
- cancelled: boolean;
84
- /** Set once the write has been applied (or skipped as cancelled). */
85
- done: boolean;
13
+ interface StyleDetailsPart {
14
+ mods: string[];
15
+ values: string[];
16
+ colors: string[];
17
+ all: string[];
18
+ output: string;
86
19
  }
87
- /** Whether any write is still waiting to hit a stylesheet. */
88
- declare function hasPendingStyleWrites(): boolean;
89
- /**
90
- * Drain every pending sheet write, in insertion order.
91
- *
92
- * Safe to call when the queue is empty (the common case, so the guard comes
93
- * first) and safe to call re-entrantly: a nested `flushStyles()` is a no-op,
94
- * and work a draining write triggers is written in place by
95
- * `enqueueStyleWrite` rather than queued behind the rest of the batch.
96
- */
97
- declare function flushStyles(): void;
98
20
  /**
99
- * Drop every pending write without applying it. Test helper — production code
100
- * should call `flushStyles()` instead.
21
+ * A group of style details, representing a comma-separated segment.
22
+ * Contains aggregated values from all parts for backward compatibility,
23
+ * plus the structured `parts` array for handlers that need slash separation.
101
24
  */
102
- declare function resetStyleBatch(): void;
103
- //#endregion
104
- //#region src/injector/types.d.ts
105
- declare global {
106
- interface Window {
107
- __TASTY__?: string[];
108
- }
25
+ interface StyleDetails {
26
+ input: string;
27
+ output: string;
28
+ /** Aggregated mods from all parts (backward compatible) */
29
+ mods: string[];
30
+ /** Aggregated values from all parts (backward compatible) */
31
+ values: string[];
32
+ /** Aggregated colors from all parts (backward compatible) */
33
+ colors: string[];
34
+ /** Aggregated all tokens from all parts (backward compatible) */
35
+ all: string[];
36
+ /** Slash-separated parts within this group */
37
+ parts: StyleDetailsPart[];
109
38
  }
110
- interface InjectResult {
111
- className: string;
112
- dispose: () => void;
39
+ interface ProcessedStyle {
40
+ output: string;
41
+ groups: StyleDetails[];
113
42
  }
114
- interface GlobalInjectResult {
115
- dispose: () => void;
43
+ type UnitHandler = (scalar: number) => string;
44
+ interface ParserOptions {
45
+ functions?: Record<string, (parsed: StyleDetails[]) => string>;
46
+ units?: Record<string, string | UnitHandler>;
47
+ cacheSize?: number;
116
48
  }
117
- type DisposeFunction = () => void;
118
- interface StyleInjectorConfig {
119
- nonce?: string;
120
- maxRulesPerSheet?: number;
121
- forceTextInjection?: boolean;
122
- /** Enable development mode features: performance metrics and debug information storage */
123
- devMode?: boolean;
124
- /**
125
- * Global predefined states for advanced state mapping.
126
- * These are state aliases that can be used in any component.
127
- * Example: { '@mobile': '@media(w < 920px)', '@dark': '@root(theme=dark)' }
128
- */
129
- states?: Record<string, string>;
130
- /**
131
- * Automatically infer and register CSS @property declarations
132
- * from custom property values. When false, only explicit @property are used.
133
- * @default true
134
- */
135
- autoPropertyTypes?: boolean;
136
- /** Garbage collection configuration for unused styles */
137
- gc?: GCConfig;
49
+ //#endregion
50
+ //#region src/parser/parser.d.ts
51
+ declare class StyleParser {
52
+ private opts;
53
+ private cache;
54
+ constructor(opts?: ParserOptions);
55
+ process(src: string): ProcessedStyle;
56
+ setFunctions(functions: Required<ParserOptions>['functions']): void;
57
+ setUnits(units: Required<ParserOptions>['units']): void;
58
+ updateOptions(patch: Partial<ParserOptions>): void;
138
59
  /**
139
- * Prefix prepended to every generated identifier.
140
- * Mirrors the `namePrefix` field on the public `TastyConfig` so that
141
- * standalone injector consumers can configure it directly.
142
- * @default 't'
60
+ * Clear the parser cache.
61
+ * Call this when external state that affects parsing results has changed
62
+ * (e.g., predefined tokens).
143
63
  */
144
- namePrefix?: string;
64
+ clearCache(): void;
145
65
  /**
146
- * Defer stylesheet writes and apply them in one batch instead of one
147
- * `insertRule()` per component. Mirrors `batchInjection` on the public
148
- * `TastyConfig`.
149
- * @default false
66
+ * Get the current units configuration.
150
67
  */
151
- batchInjection?: boolean | 'always';
68
+ getUnits(): ParserOptions['units'];
152
69
  }
70
+ //#endregion
71
+ //#region src/utils/color-math.d.ts
153
72
  /**
154
- * Per-className usage tracking for GC.
73
+ * Consolidated color conversion math.
74
+ *
75
+ * Single source of truth for all color space conversions used across the
76
+ * library: sRGB gamma, HSL, OKLab, OKLCH, OKHSL, hex parsing, named
77
+ * colors, and CSS string converters.
78
+ *
79
+ * This module has zero internal imports — it is a leaf dependency.
80
+ *
81
+ * Reference: https://bottosson.github.io/posts/oklab/
155
82
  */
83
+ type Vec3 = [number, number, number];
156
84
  /**
157
- * @deprecated Nothing reads this any more. Collection asks the DOM what is
158
- * rendered rather than tracking usage per class, so there is no usage record
159
- * to describe. Kept so existing imports keep type-checking.
85
+ * sRGB gamma to linear. Only the sRGB-to-OKLab direction needs it, so this is
86
+ * test-only for the same reason as {@link srgbToOkhsl} the forward path goes
87
+ * through {@link srgbLinearToGamma} instead.
160
88
  */
161
- interface StyleUsage {
162
- lastTouchedAt: number;
163
- }
164
89
  /**
165
- * Configuration for the style garbage collector.
90
+ * HSL to RGB.
91
+ * Algorithm from CSS Color 4 spec.
166
92
  *
167
- * GC is triggered by touch count rather than timers: every `touchInterval`
168
- * touches, an idle callback is scheduled to evict unused styles above
169
- * `capacity`, oldest first.
93
+ * @param h - Hue in degrees (0-360)
94
+ * @param s - Saturation (0-1)
95
+ * @param l - Lightness (0-1)
96
+ * @returns RGB values in 0-255 range (may have fractional values)
170
97
  */
171
- interface GCConfig {
172
- /**
173
- * How long a class is left alone after collection first notices nothing is
174
- * carrying it, in milliseconds (default 10,000).
175
- *
176
- * Rendering is not commit-aware: a render can resolve a class and commit it a
177
- * little later, and in between nothing on the page carries it. Rather than
178
- * try to tell that apart from a class that is finished — which cannot be done
179
- * from outside React — collection simply does not touch anything that was in
180
- * use recently. A render would have to stay pending for the whole window to
181
- * lose its rules, and it gets them back on its next render.
182
- */
183
- grace?: number;
184
- /**
185
- * Number of touch events between automatic GC cycles.
186
- * @default 1000
187
- */
188
- touchInterval?: number;
189
- /**
190
- * Maximum number of unused styles to retain.
191
- * GC evicts the oldest unused styles when this limit is exceeded.
192
- * Pinned styles and DOM-live styles
193
- * do not count against this limit.
194
- * @default 1000
195
- */
196
- capacity?: number;
197
- }
98
+ declare function hslToRgbValues(h: number, s: number, l: number): Vec3;
99
+ declare function getNamedColorHex(): Map<string, string>;
198
100
  /**
199
- * Per-call options for inject().
200
- */
201
- interface InjectOptions {
202
- root?: Document | ShadowRoot;
203
- /** Reuse the class already injected for this key instead of writing again. */
204
- cacheKey?: string;
205
- /**
206
- * Pin the injected class (default `true`). A pinned class is never evicted by
207
- * `gc()`, and the returned `dispose()` releases the pin. Pass `false` when the
208
- * caller keeps no handle and the DOM is the only record that the class is in
209
- * use — the render path does this, because a hook-free render has no unmount
210
- * signal to dispose on.
211
- */
212
- pin?: boolean;
213
- }
214
- /**
215
- * Per-call options for gc().
216
- */
217
- interface GCOptions {
218
- root?: Document | ShadowRoot;
219
- /** Bypass capacity threshold and remove ALL unused styles. */
220
- force?: boolean;
221
- }
222
- interface RuleInfo {
223
- className: string;
224
- ruleIndex: number;
225
- sheetIndex: number;
226
- /** Dev-only: full CSS texts inserted for this class; omitted in production */
227
- cssText?: string[];
228
- /** Inclusive end index of the contiguous block of inserted rules for this className */
229
- endRuleIndex?: number;
230
- /** NEW: exact indices of all inserted rules for this className */
231
- indices?: number[];
232
- }
233
- type InjectionMode = 'style-element' | 'adopted';
234
- interface SheetInfo {
235
- /** HTMLStyleElement used in style-element mode; null in adopted mode. */
236
- sheet: HTMLStyleElement | null;
237
- /** Constructable CSSStyleSheet used in adopted mode (ShadowRoot targets) */
238
- constructableSheet?: CSSStyleSheet;
239
- ruleCount: number;
240
- holes: number[];
241
- /**
242
- * True when this sheet is written through `textContent` instead of CSSOM.
243
- * Decided once at sheet creation so a sheet is never half CSSOM / half text.
244
- */
245
- textMode?: boolean;
246
- /**
247
- * Inserted rule texts in rule-index order. Maintained only in text mode —
248
- * it is what makes deletion possible there, since `textContent` cannot be
249
- * edited rule-by-rule and has to be rebuilt.
250
- */
251
- textRules?: string[];
252
- }
253
- interface CleanupStats {
254
- timestamp: number;
255
- classesDeleted: number;
256
- cssSize: number;
257
- rulesDeleted: number;
258
- }
259
- interface CacheMetrics {
260
- hits: number;
261
- misses: number;
262
- bulkCleanups: number;
263
- totalInsertions: number;
264
- totalUnused: number;
265
- stylesCleanedUp: number;
266
- cleanupHistory: CleanupStats[];
267
- startTime: number;
268
- unusedHits?: number;
269
- }
270
- interface RootRegistry {
271
- sheets: SheetInfo[];
272
- /** className -> outstanding `inject()` references; 0 means nobody holds a handle */
273
- pinCounts: Map<string, number>;
274
- rules: Map<string, RuleInfo>;
275
- /** Cache key to className mapping to avoid dual storage of RuleInfo objects */
276
- cacheKeyToClassName: Map<string, string>;
277
- /** Deduplication set of fully materialized CSS rules inserted into sheets */
278
- ruleTextSet: Set<string>;
279
- /** Performance metrics (optional) */
280
- metrics?: CacheMetrics;
281
- /** Keyframes cache by content hash -> entry */
282
- keyframesCache: Map<string, KeyframesCacheEntry>;
283
- /** Keyframes name to content hash mapping for collision detection */
284
- keyframesNameToContent: Map<string, string>;
285
- /** Counter for generating keyframes names like k0, k1, k2... */
286
- keyframesCounter: number;
287
- /** Map of injected @property names to their normalized declarations for tracking */
288
- injectedProperties: Map<string, string>;
289
- /** Content hashes of injected @font-face rules for deduplication */
290
- injectedFontFaces: Set<string>;
291
- /**
292
- * Injected @counter-style rules. Maps the name to whether it was injected
293
- * "strong" (`true`, the default — overrides) or "weak" (`false`, global
294
- * `configure()` definitions that never clobber an existing rule).
295
- */
296
- injectedCounterStyles: Map<string, boolean>;
297
- /**
298
- * Injected @function rules. Maps the CSS function name to whether it was
299
- * injected "strong" (`true`, the default — overrides) or "weak" (`false`,
300
- * global `configure()` definitions that never clobber an existing rule).
301
- */
302
- injectedFunctions: Map<string, boolean>;
303
- /** Global rules tracking for index adjustment */
304
- globalRules: Map<string, RuleInfo>;
305
- /** Resolver for auto-inferring @property types from declaration values */
306
- propertyTypeResolver: PropertyTypeResolver;
307
- /**
308
- * className -> when the class was first noticed to be carrying nothing:
309
- * injection, or the first sweep that looked and did not find it on an
310
- * element. Cleared the moment a sweep finds it rendered again.
311
- *
312
- * Deliberately "when it was noticed", not "when it stopped being rendered".
313
- * Nothing observes the moment an element leaves, so a class that unmounted
314
- * just before a sweep and one that unmounted just after the previous sweep
315
- * would otherwise be treated differently — and the first would lose its
316
- * grace window entirely. Starting the clock at the sighting gives every
317
- * class the same full window, whenever it actually went.
318
- *
319
- * Written only by the sweep's own DOM scan and at injection, so rendering
320
- * never pays for it.
321
- */
322
- unusedSince: Map<string, number>;
323
- /**
324
- * Local `@keyframes` a class animates, by the name they were authored under.
325
- *
326
- * One reference is held per distinct set of steps, however many renders ask
327
- * for it, and the classes that animate it own that reference between them.
328
- * The last of them to be deleted releases it, so keyframes cannot outlive
329
- * every rule that referred to them, and repeat renders cannot pile up
330
- * references nobody gives back.
331
- */
332
- localKeyframes: Map<string, {
333
- name: string;
334
- dispose: () => void;
335
- owners: Set<string>;
336
- }>;
337
- /** Renders since the last scheduled sweep (per-root) */
338
- touchCount: number;
339
- /** How many entries from `window.__TASTY__` have been synced into this registry */
340
- serverClassSyncIndex: number;
341
- /** Whether `<style data-tasty-rsc>` tags have been scanned for class names */
342
- rscStylesScanned: boolean;
343
- /** Whether this root uses adoptedStyleSheets or <style> elements */
344
- injectionMode: InjectionMode;
345
- /**
346
- * Lazy feature-test for `@property` support, cached per registry.
347
- * - `undefined`: not yet probed.
348
- * - `true`: engine supports `@property`; rejections indicate user-authored
349
- * invalid rules and should warn.
350
- * - `false`: engine doesn't support `@property` (e.g., jsdom); rejections
351
- * are expected and warnings are suppressed.
352
- */
353
- atPropertySupported?: boolean;
354
- }
355
- type StyleRule = StyleResult;
356
- interface KeyframesInfo {
357
- name: string;
358
- sheetIndex: number;
359
- ruleIndex: number;
360
- /** Dev-only: full CSS text of the @keyframes rule; omitted in production */
361
- cssText?: string;
362
- }
363
- type KeyframeStep = string | Record<string, string | number>;
364
- type KeyframesSteps = Record<string, KeyframeStep>;
365
- interface KeyframesResult {
366
- toString(): string;
367
- dispose: () => void;
368
- }
369
- interface KeyframesCacheEntry {
370
- name: string;
371
- refCount: number;
372
- info: KeyframesInfo;
373
- /**
374
- * Queued sheet write, when `batchInjection` deferred the insertion. Present
375
- * only between `keyframes()` and the flush; disposing in that window cancels
376
- * the write instead of deleting a rule that was never inserted.
377
- */
378
- pending?: QueuedWrite;
379
- }
380
- /**
381
- * Definition for a CSS @property at-rule.
382
- * Used to define custom property syntax, inheritance, and initial value.
383
- */
384
- interface PropertyDefinition {
385
- /** CSS syntax string (e.g., '<color>', '<angle>', '<number>') */
386
- syntax?: string;
387
- /** Whether the property inherits (default: true) */
388
- inherits?: boolean;
389
- /** Initial value for the property */
390
- initialValue?: string | number;
391
- }
392
- /**
393
- * Options for registering a CSS `@property`.
394
- * Extends {@link PropertyDefinition} with an optional injection root.
395
- */
396
- interface PropertyOptions extends PropertyDefinition {
397
- /** Shadow root or document to inject into */
398
- root?: Document | ShadowRoot;
399
- }
400
- /**
401
- * A single parameter for a CSS @function at-rule.
402
- *
403
- * - `true` — a bare parameter with no type or default.
404
- * - `string` — a CSS type shorthand (e.g. `'<length>'`, `'<color>'`).
405
- * - object — full form with optional `syntax` (type) and `default` value.
406
- */
407
- type FunctionParameter = true | string | {
408
- syntax?: string;
409
- default?: string | number;
410
- };
411
- /**
412
- * Definition for a CSS @function at-rule (custom function).
413
- *
414
- * The descriptor body reads like a mini styles object: any `$name` key declares
415
- * a local variable (`--name`) whose value is parsed through the Tasty DSL.
416
- * `result` is the only required field.
417
- *
418
- * @example
419
- * ```ts
420
- * // @function --negative(--value) { result: calc(-1 * var(--value)); }
421
- * { args: ['$value'], result: '(-1 * $value)' }
422
- * ```
423
- */
424
- interface FunctionDefinition {
425
- /**
426
- * Ordered parameters. Array form lists bare parameter names (`['$value']`);
427
- * object form maps each parameter name to its type/default.
428
- */
429
- args?: string[] | Record<string, FunctionParameter>;
430
- /** Optional return type, e.g. `'<color>'`. */
431
- returns?: string;
432
- /** The `result:` descriptor value (parsed through the Tasty DSL). Required. */
433
- result: string;
434
- /** Local variables: any `$name` key declares `--name` in the body. */
435
- [localVar: `$${string}`]: string | number | undefined;
436
- }
437
- /**
438
- * Descriptors for a CSS @font-face at-rule.
439
- */
440
- interface FontFaceDescriptors {
441
- /** Required. URL(s) to the font file(s). */
442
- src: string;
443
- /** Font weight or range. Default: 'normal'. */
444
- fontWeight?: string | number;
445
- /** Font style. Default: 'normal'. */
446
- fontStyle?: 'normal' | 'italic' | 'oblique' | (string & {});
447
- /** Font stretch. Default: 'normal'. */
448
- fontStretch?: string;
449
- /** Loading behavior. Default: 'auto'. */
450
- fontDisplay?: 'auto' | 'block' | 'swap' | 'fallback' | 'optional';
451
- /** Unicode range to cover. */
452
- unicodeRange?: string;
453
- /** Ascent metric override. */
454
- ascentOverride?: string;
455
- /** Descent metric override. */
456
- descentOverride?: string;
457
- /** Line gap metric override. */
458
- lineGapOverride?: string;
459
- /** Size adjustment factor. */
460
- sizeAdjust?: string;
461
- /** OpenType feature settings. */
462
- fontFeatureSettings?: string;
463
- /** Font variation axis settings. */
464
- fontVariationSettings?: string;
465
- }
466
- /** Single descriptor or array of descriptors for multiple weights/styles. */
467
- type FontFaceInput = FontFaceDescriptors | FontFaceDescriptors[];
468
- /**
469
- * Descriptors for a CSS @counter-style at-rule.
470
- */
471
- interface CounterStyleDescriptors {
472
- /** Required. Numbering algorithm. */
473
- system: 'cyclic' | 'numeric' | 'alphabetic' | 'symbolic' | 'additive' | 'fixed' | (string & {});
474
- /** Symbols for non-additive systems. */
475
- symbols?: string;
476
- /** Symbol-value pairs for additive system. */
477
- additiveSymbols?: string;
478
- /** String prepended to the marker. Default: "". */
479
- prefix?: string;
480
- /** String appended to the marker. Default: ". ". */
481
- suffix?: string;
482
- /** Negative-value wrapping (e.g., '"(" ")"'). */
483
- negative?: string;
484
- /** Counter range (e.g., 'infinite infinite'). */
485
- range?: string;
486
- /** Minimum marker width and pad symbol (e.g., '3 "0"'). */
487
- pad?: string;
488
- /** Fallback counter style name. */
489
- fallback?: string;
490
- /** Speech synthesis hint. */
491
- speakAs?: string;
492
- }
493
- interface RawCSSResult {
494
- dispose: () => void;
495
- }
496
- //#endregion
497
- //#region src/utils/css-types.d.ts
498
- interface CSSProperties extends Properties<string | number> {}
499
- //#endregion
500
- //#region src/parser/types.d.ts
501
- /**
502
- * A part within a group, representing a slash-separated segment.
503
- * For example, in `'2px solid #red / 4px'`, there are two parts:
504
- * - Part 0: `2px solid #red`
505
- * - Part 1: `4px`
506
- */
507
- interface StyleDetailsPart {
508
- mods: string[];
509
- values: string[];
510
- colors: string[];
511
- all: string[];
512
- output: string;
513
- }
514
- /**
515
- * A group of style details, representing a comma-separated segment.
516
- * Contains aggregated values from all parts for backward compatibility,
517
- * plus the structured `parts` array for handlers that need slash separation.
518
- */
519
- interface StyleDetails {
520
- input: string;
521
- output: string;
522
- /** Aggregated mods from all parts (backward compatible) */
523
- mods: string[];
524
- /** Aggregated values from all parts (backward compatible) */
525
- values: string[];
526
- /** Aggregated colors from all parts (backward compatible) */
527
- colors: string[];
528
- /** Aggregated all tokens from all parts (backward compatible) */
529
- all: string[];
530
- /** Slash-separated parts within this group */
531
- parts: StyleDetailsPart[];
532
- }
533
- interface ProcessedStyle {
534
- output: string;
535
- groups: StyleDetails[];
536
- }
537
- type UnitHandler = (scalar: number) => string;
538
- interface ParserOptions {
539
- functions?: Record<string, (parsed: StyleDetails[]) => string>;
540
- units?: Record<string, string | UnitHandler>;
541
- cacheSize?: number;
542
- }
543
- //#endregion
544
- //#region src/parser/parser.d.ts
545
- declare class StyleParser {
546
- private opts;
547
- private cache;
548
- constructor(opts?: ParserOptions);
549
- process(src: string): ProcessedStyle;
550
- setFunctions(functions: Required<ParserOptions>['functions']): void;
551
- setUnits(units: Required<ParserOptions>['units']): void;
552
- updateOptions(patch: Partial<ParserOptions>): void;
553
- /**
554
- * Clear the parser cache.
555
- * Call this when external state that affects parsing results has changed
556
- * (e.g., predefined tokens).
557
- */
558
- clearCache(): void;
559
- /**
560
- * Get the current units configuration.
561
- */
562
- getUnits(): ParserOptions['units'];
563
- }
564
- //#endregion
565
- //#region src/utils/color-math.d.ts
566
- /**
567
- * Consolidated color conversion math.
568
- *
569
- * Single source of truth for all color space conversions used across the
570
- * library: sRGB gamma, HSL, OKLab, OKLCH, OKHSL, hex parsing, named
571
- * colors, and CSS string converters.
572
- *
573
- * This module has zero internal imports — it is a leaf dependency.
574
- *
575
- * Reference: https://bottosson.github.io/posts/oklab/
576
- */
577
- type Vec3 = [number, number, number];
578
- /**
579
- * sRGB gamma to linear. Only the sRGB-to-OKLab direction needs it, so this is
580
- * test-only for the same reason as {@link srgbToOkhsl} — the forward path goes
581
- * through {@link srgbLinearToGamma} instead.
582
- */
583
- /**
584
- * HSL to RGB.
585
- * Algorithm from CSS Color 4 spec.
586
- *
587
- * @param h - Hue in degrees (0-360)
588
- * @param s - Saturation (0-1)
589
- * @param l - Lightness (0-1)
590
- * @returns RGB values in 0-255 range (may have fractional values)
591
- */
592
- declare function hslToRgbValues(h: number, s: number, l: number): Vec3;
593
- declare function getNamedColorHex(): Map<string, string>;
594
- /**
595
- * Convert hex color string to `rgb()` CSS string.
596
- * Supports 3, 4, 6, and 8 character hex values (with or without `#`).
101
+ * Convert hex color string to `rgb()` CSS string.
102
+ * Supports 3, 4, 6, and 8 character hex values (with or without `#`).
597
103
  */
598
104
  declare function hexToRgb(hex: string): string | null;
599
105
  /**
@@ -716,7 +222,7 @@ declare function parseStyle(value: StyleValue): ProcessedStyle;
716
222
  * Optimized to avoid heavy parseStyle calls for simple color patterns.
717
223
  */
718
224
  declare function parseColor(val: string, ignoreError?: boolean): ParsedColor;
719
- declare function filterMods(mods: string[], allowedMods: string[]): string[];
225
+ declare function filterMods(mods: string[], allowedMods: readonly string[]): string[];
720
226
  declare function stringifyStyles(styles: unknown): string;
721
227
  //#endregion
722
228
  //#region src/styles/types.d.ts
@@ -759,7 +265,7 @@ type Digit = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
759
265
  type OpaquePercentage = '' | `.${Digit}` | `.${Digit}${Digit}` | '.100';
760
266
  type ColorValue = `#${NamedColor}${OpaquePercentage}` | `rgb(${string})` | `hsl(${string})` | `okhsl(${string})` | `oklch(${string})` | (string & {});
761
267
  type NoType = false | null | undefined;
762
- interface StylesInterface extends Omit<CSSProperties, 'color' | 'fill' | 'font' | 'outline' | 'type' | 'gap' | 'padding' | 'margin' | 'width' | 'height' | 'border' | 'transition' | 'placeContent' | 'placeItems' | 'scrollMargin' | 'scrollMarginTop' | 'scrollMarginRight' | 'scrollMarginBottom' | 'scrollMarginLeft' | 'scrollMarginBlock' | 'scrollMarginInline'> {
268
+ interface StylesInterface extends Omit<CSSProperties, 'color' | 'fill' | 'font' | 'outline' | 'type' | 'gap' | 'padding' | 'margin' | 'width' | 'height' | 'blockSize' | 'inlineSize' | 'border' | 'transition' | 'placeContent' | 'placeItems' | 'scrollMargin' | 'scrollMarginTop' | 'scrollMarginRight' | 'scrollMarginBottom' | 'scrollMarginLeft' | 'scrollPadding' | 'scrollPaddingTop' | 'scrollPaddingRight' | 'scrollPaddingBottom' | 'scrollPaddingLeft'> {
763
269
  /**
764
270
  * @deprecated Use `flow` style instead.
765
271
  */
@@ -911,6 +417,10 @@ interface StylesInterface extends Omit<CSSProperties, 'color' | 'fill' | 'font'
911
417
  * - `padding={true}` // default padding on all sides
912
418
  */
913
419
  padding?: CSSProperties['padding'] | string | boolean;
420
+ /** Logical block-axis padding with `start`/`end` modifiers. */
421
+ blockPadding?: CSSProperties['paddingBlock'] | string | boolean;
422
+ /** Logical inline-axis padding with `start`/`end` modifiers. */
423
+ inlinePadding?: CSSProperties['paddingInline'] | string | boolean;
914
424
  /**
915
425
  * Shorthand for element margin. Supports custom units, directional modifiers, and design-system-driven defaults.
916
426
  *
@@ -925,6 +435,10 @@ interface StylesInterface extends Omit<CSSProperties, 'color' | 'fill' | 'font'
925
435
  * - `margin={true}` // default margin on all sides
926
436
  */
927
437
  margin?: CSSProperties['margin'] | string | boolean;
438
+ /** Logical block-axis margin with `start`/`end` modifiers. */
439
+ blockMargin?: CSSProperties['marginBlock'] | string | boolean;
440
+ /** Logical inline-axis margin with `start`/`end` modifiers. */
441
+ inlineMargin?: CSSProperties['marginInline'] | string | boolean;
928
442
  /**
929
443
  * Concise shorthand for setting element width, including min-width and max-width. Supports custom units and advanced sizing keywords.
930
444
  *
@@ -956,6 +470,16 @@ interface StylesInterface extends Omit<CSSProperties, 'color' | 'fill' | 'font'
956
470
  * - `height={true}` // height: auto
957
471
  */
958
472
  height?: CSSProperties['height'] | string | boolean;
473
+ /**
474
+ * Logical block size with the same enhanced min/max/fixed syntax as `width`.
475
+ * Emits native `block-size`, `min-block-size`, and `max-block-size` declarations.
476
+ */
477
+ blockSize?: CSSProperties['blockSize'] | string | boolean;
478
+ /**
479
+ * Logical inline size with the same enhanced min/max/fixed syntax as `width`.
480
+ * Emits native `inline-size`, `min-inline-size`, and `max-inline-size` declarations.
481
+ */
482
+ inlineSize?: CSSProperties['inlineSize'] | string | boolean;
959
483
  /**
960
484
  * Shorthand for border width, style, and color. Supports directional modifiers and design-system defaults.
961
485
  *
@@ -977,6 +501,10 @@ interface StylesInterface extends Omit<CSSProperties, 'color' | 'fill' | 'font'
977
501
  * custom property directly, name it `$name-color`.
978
502
  */
979
503
  border?: CSSProperties['border'] | string | boolean;
504
+ /** Logical block-axis border with `start`/`end` modifiers. */
505
+ blockBorder?: CSSProperties['borderBlock'] | string | boolean;
506
+ /** Logical inline-axis border with `start`/`end` modifiers. */
507
+ inlineBorder?: CSSProperties['borderInline'] | string | boolean;
980
508
  /**
981
509
  * Powerful shorthand for CSS transitions using semantic names and design tokens. Supports grouped transitions for common UI effects.
982
510
  *
@@ -1182,8 +710,23 @@ interface StylesInterface extends Omit<CSSProperties, 'color' | 'fill' | 'font'
1182
710
  scrollMarginRight?: string | number | boolean;
1183
711
  scrollMarginBottom?: string | number | boolean;
1184
712
  scrollMarginLeft?: string | number | boolean;
1185
- scrollMarginBlock?: string | number | boolean;
1186
- scrollMarginInline?: string | number | boolean;
713
+ /** Logical block-axis scroll margin with `start`/`end` modifiers. */
714
+ blockScrollMargin?: CSSProperties['scrollMarginBlock'] | string | boolean;
715
+ /** Logical inline-axis scroll margin with `start`/`end` modifiers. */
716
+ inlineScrollMargin?: CSSProperties['scrollMarginInline'] | string | boolean;
717
+ /**
718
+ * Shorthand for physical scroll padding. Supports custom units and the same
719
+ * physical direction modifiers as `padding`.
720
+ */
721
+ scrollPadding?: CSSProperties['scrollPadding'] | string | boolean;
722
+ scrollPaddingTop?: string | number | boolean;
723
+ scrollPaddingRight?: string | number | boolean;
724
+ scrollPaddingBottom?: string | number | boolean;
725
+ scrollPaddingLeft?: string | number | boolean;
726
+ /** Logical block-axis scroll padding with `start`/`end` modifiers. */
727
+ blockScrollPadding?: CSSProperties['scrollPaddingBlock'] | string | boolean;
728
+ /** Logical inline-axis scroll padding with `start`/`end` modifiers. */
729
+ inlineScrollPadding?: CSSProperties['scrollPaddingInline'] | string | boolean;
1187
730
  /**
1188
731
  * Shorthand for `top`, `right`, `bottom`, and `left` offsets. Supports custom units, directional modifiers, and positioning.
1189
732
  *
@@ -1205,6 +748,10 @@ interface StylesInterface extends Omit<CSSProperties, 'color' | 'fill' | 'font'
1205
748
  * insets the sides by `4x`. Without `dock` a second value is ignored.
1206
749
  */
1207
750
  inset?: 'top' | 'right' | 'bottom' | 'left' | 'dock' | string | CSSProperties['inset'];
751
+ /** Logical block-axis inset with `start`/`end` modifiers. */
752
+ blockInset?: CSSProperties['insetBlock'] | string | boolean;
753
+ /** Logical inline-axis inset with `start`/`end` modifiers. */
754
+ inlineInset?: CSSProperties['insetInline'] | string | boolean;
1208
755
  /**
1209
756
  * Local keyframes definitions for this component.
1210
757
  * Keys are animation names, values are keyframes step definitions.
@@ -1276,300 +823,794 @@ interface StylesInterface extends Omit<CSSProperties, 'color' | 'fill' | 'font'
1276
823
  */
1277
824
  recipe?: string;
1278
825
  }
1279
- type SuffixForSelector = '&' | '.' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z';
1280
- type Selector = `${SuffixForSelector}${string}`;
1281
- type NotSelector = Exclude<string, Selector | keyof StylesInterface>;
1282
- /** Special style keys that should not be wrapped in StyleValue/StyleValueStateMap */
1283
- type SpecialStyleKeys = '@keyframes' | '@property' | '@font-face' | '@counter-style' | '@function' | 'recipe';
1284
- type StylesWithoutSelectors = { [key in keyof StylesInterface as key extends SpecialStyleKeys ? never : key]?: StyleValue<StylesInterface[key]> | StyleValueStateMap<StylesInterface[key]> };
826
+ type SuffixForSelector = '&' | '.' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T' | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z';
827
+ type Selector = `${SuffixForSelector}${string}`;
828
+ type NotSelector = Exclude<string, Selector | keyof StylesInterface>;
829
+ /** Special style keys that should not be wrapped in StyleValue/StyleValueStateMap */
830
+ type SpecialStyleKeys = '@keyframes' | '@property' | '@font-face' | '@counter-style' | '@function' | 'recipe';
831
+ type StylesWithoutSelectors = { [key in keyof StylesInterface as key extends SpecialStyleKeys ? never : key]?: StyleValue<StylesInterface[key]> | StyleValueStateMap<StylesInterface[key]> };
832
+ /**
833
+ * Index signature for recipe-specific arbitrary keys.
834
+ * Supports local predefined states (`@name`), vendor-prefixed CSS properties (`-webkit-*`),
835
+ * CSS custom properties (`$name`), and color tokens (`#name`).
836
+ * Unlike StylesIndexSignature, does NOT allow sub-element selectors (recipes are flat).
837
+ */
838
+ type RecipeIndexSignature = Record<string, StyleValue<string | number | boolean | undefined> | StyleValueStateMap<string | number | boolean | undefined>>;
839
+ /**
840
+ * Style type for recipe definitions.
841
+ * Like StylesWithoutSelectors but also allows `@keyframes`, `@property`,
842
+ * local predefined states, and vendor-prefixed CSS properties.
843
+ * Excludes `recipe` to prevent recursive references.
844
+ */
845
+ type RecipeStyles = StylesWithoutSelectors & RecipeIndexSignature & {
846
+ '@keyframes'?: StylesInterface['@keyframes'];
847
+ '@property'?: StylesInterface['@property'];
848
+ '@font-face'?: StylesInterface['@font-face'];
849
+ '@counter-style'?: StylesInterface['@counter-style'];
850
+ '@function'?: StylesInterface['@function'];
851
+ };
852
+ /** Special properties that are not regular style values */
853
+ interface SpecialStyleProperties {
854
+ '@keyframes'?: StylesInterface['@keyframes'];
855
+ '@property'?: StylesInterface['@property'];
856
+ '@font-face'?: StylesInterface['@font-face'];
857
+ '@counter-style'?: StylesInterface['@counter-style'];
858
+ '@function'?: StylesInterface['@function'];
859
+ recipe?: StylesInterface['recipe'];
860
+ }
861
+ /** Index signature for arbitrary style keys (sub-elements, CSS variables, etc.) */
862
+ interface StylesIndexSignature {
863
+ [key: string]: StyleValue<string | number | boolean | undefined> | StyleValueStateMap<string | number | boolean | undefined> | Styles | false | StylesInterface['@keyframes'] | StylesInterface['@property'] | StylesInterface['@font-face'] | StylesInterface['@counter-style'] | StylesInterface['@function'];
864
+ /**
865
+ * Selector combinator: `undefined` (descendant, default), `'>'` (child), `'+'` (adjacent), `'~'` (sibling).
866
+ * Can chain with capitalized names: `'> Body > Row >'`. Spaces required around combinators.
867
+ */
868
+ $?: string;
869
+ }
870
+ type Styles = StylesWithoutSelectors & SpecialStyleProperties & StylesIndexSignature;
871
+ /**
872
+ * Value type for design tokens passed to `configure({ tokens })`.
873
+ * Can be a direct value or a state map for responsive/theme-aware tokens.
874
+ */
875
+ type ConfigTokenValue = string | number | boolean | Record<string, string | number | boolean | undefined | null | '@inherit'>;
876
+ /**
877
+ * Design tokens injected as CSS custom properties on `:root`.
878
+ * Keys must start with `$` (value tokens) or `#` (color tokens).
879
+ *
880
+ * - `$name` keys become `--name` CSS custom properties
881
+ * - `#name` keys become `--name-color` properties
882
+ */
883
+ type ConfigTokens = Record<`$${string}` | `#${string}`, ConfigTokenValue>;
884
+ //#endregion
885
+ //#region src/utils/is-selector.d.ts
886
+ /** Check whether a style-object key identifies a nested CSS selector. */
887
+ declare function isSelector(key: string): boolean;
888
+ //#endregion
889
+ //#region src/pipeline/conditions.d.ts
890
+ /**
891
+ * ConditionNode Types and Helpers
892
+ *
893
+ * Core data structures for representing style conditions as an abstract syntax tree.
894
+ * Used throughout the pipeline for parsing, simplification, and CSS generation.
895
+ */
896
+ /**
897
+ * Base interface for all state conditions (leaf nodes)
898
+ */
899
+ interface BaseStateCondition {
900
+ kind: 'state';
901
+ negated: boolean;
902
+ raw: string;
903
+ uniqueId: string;
904
+ }
905
+ /**
906
+ * Modifier condition: [data-attr] or [data-attr="value"]
907
+ */
908
+ interface ModifierCondition extends BaseStateCondition {
909
+ type: 'modifier';
910
+ attribute: string;
911
+ value?: string;
912
+ operator?: '=' | '^=' | '$=' | '*=';
913
+ }
914
+ /**
915
+ * Pseudo-class condition: :hover, :focus-visible
916
+ */
917
+ interface PseudoCondition extends BaseStateCondition {
918
+ type: 'pseudo';
919
+ pseudo: string;
920
+ }
921
+ /**
922
+ * Numeric bound for dimension queries
923
+ */
924
+ interface NumericBound {
925
+ value: string;
926
+ valueNumeric: number | null;
927
+ inclusive: boolean;
928
+ }
929
+ /**
930
+ * Media query condition
931
+ */
932
+ interface MediaCondition extends BaseStateCondition {
933
+ type: 'media';
934
+ subtype: 'dimension' | 'feature' | 'type';
935
+ dimension?: 'width' | 'height' | 'inline-size' | 'block-size';
936
+ lowerBound?: NumericBound;
937
+ upperBound?: NumericBound;
938
+ feature?: string;
939
+ featureValue?: string;
940
+ mediaType?: 'print' | 'screen' | 'all' | 'speech';
941
+ }
942
+ /**
943
+ * Container query condition
944
+ */
945
+ interface ContainerCondition extends BaseStateCondition {
946
+ type: 'container';
947
+ subtype: 'dimension' | 'style' | 'raw';
948
+ containerName?: string;
949
+ dimension?: 'width' | 'height' | 'inline-size' | 'block-size';
950
+ lowerBound?: NumericBound;
951
+ upperBound?: NumericBound;
952
+ property?: string;
953
+ propertyValue?: string;
954
+ rawCondition?: string;
955
+ }
956
+ /**
957
+ * Root state condition: @root(theme=dark)
958
+ */
959
+ interface RootCondition extends BaseStateCondition {
960
+ type: 'root';
961
+ innerCondition: ConditionNode;
962
+ }
963
+ /**
964
+ * Parent state condition: @parent(hovered), @parent(theme=dark, >)
965
+ */
966
+ interface ParentCondition extends BaseStateCondition {
967
+ type: 'parent';
968
+ innerCondition: ConditionNode;
969
+ direct: boolean;
970
+ }
971
+ /**
972
+ * Own state condition: @own(hovered)
973
+ */
974
+ interface OwnCondition extends BaseStateCondition {
975
+ type: 'own';
976
+ innerCondition: ConditionNode;
977
+ }
978
+ /**
979
+ * Starting style condition: @starting
980
+ */
981
+ interface StartingCondition extends BaseStateCondition {
982
+ type: 'starting';
983
+ }
984
+ /**
985
+ * Supports query condition: @supports(display: grid), @supports($, :has(*))
986
+ */
987
+ interface SupportsCondition extends BaseStateCondition {
988
+ type: 'supports';
989
+ subtype: 'feature' | 'selector';
990
+ condition: string;
991
+ }
992
+ /**
993
+ * Union of all state condition types
994
+ */
995
+ type StateCondition = ModifierCondition | PseudoCondition | MediaCondition | ContainerCondition | RootCondition | ParentCondition | OwnCondition | StartingCondition | SupportsCondition;
996
+ /**
997
+ * Compound node: combines conditions with AND/OR
998
+ */
999
+ interface CompoundCondition {
1000
+ kind: 'compound';
1001
+ operator: 'AND' | 'OR';
1002
+ children: ConditionNode[];
1003
+ }
1285
1004
  /**
1286
- * Index signature for recipe-specific arbitrary keys.
1287
- * Supports local predefined states (`@name`), vendor-prefixed CSS properties (`-webkit-*`),
1288
- * CSS custom properties (`$name`), and color tokens (`#name`).
1289
- * Unlike StylesIndexSignature, does NOT allow sub-element selectors (recipes are flat).
1005
+ * True condition (matches everything)
1290
1006
  */
1291
- type RecipeIndexSignature = Record<string, StyleValue<string | number | boolean | undefined> | StyleValueStateMap<string | number | boolean | undefined>>;
1007
+ interface TrueCondition {
1008
+ kind: 'true';
1009
+ }
1292
1010
  /**
1293
- * Style type for recipe definitions.
1294
- * Like StylesWithoutSelectors but also allows `@keyframes`, `@property`,
1295
- * local predefined states, and vendor-prefixed CSS properties.
1296
- * Excludes `recipe` to prevent recursive references.
1011
+ * False condition (matches nothing - skip this rule)
1297
1012
  */
1298
- type RecipeStyles = StylesWithoutSelectors & RecipeIndexSignature & {
1299
- '@keyframes'?: StylesInterface['@keyframes'];
1300
- '@property'?: StylesInterface['@property'];
1301
- '@font-face'?: StylesInterface['@font-face'];
1302
- '@counter-style'?: StylesInterface['@counter-style'];
1303
- '@function'?: StylesInterface['@function'];
1304
- };
1305
- /** Special properties that are not regular style values */
1306
- interface SpecialStyleProperties {
1307
- '@keyframes'?: StylesInterface['@keyframes'];
1308
- '@property'?: StylesInterface['@property'];
1309
- '@font-face'?: StylesInterface['@font-face'];
1310
- '@counter-style'?: StylesInterface['@counter-style'];
1311
- '@function'?: StylesInterface['@function'];
1312
- recipe?: StylesInterface['recipe'];
1013
+ interface FalseCondition {
1014
+ kind: 'false';
1313
1015
  }
1314
- /** Index signature for arbitrary style keys (sub-elements, CSS variables, etc.) */
1315
- interface StylesIndexSignature {
1316
- [key: string]: StyleValue<string | number | boolean | undefined> | StyleValueStateMap<string | number | boolean | undefined> | Styles | false | StylesInterface['@keyframes'] | StylesInterface['@property'] | StylesInterface['@font-face'] | StylesInterface['@counter-style'] | StylesInterface['@function'];
1317
- /**
1318
- * Selector combinator: `undefined` (descendant, default), `'>'` (child), `'+'` (adjacent), `'~'` (sibling).
1319
- * Can chain with capitalized names: `'> Body > Row >'`. Spaces required around combinators.
1320
- */
1321
- $?: string;
1016
+ /**
1017
+ * Union of all condition node types
1018
+ */
1019
+ type ConditionNode = StateCondition | CompoundCondition | TrueCondition | FalseCondition;
1020
+ //#endregion
1021
+ //#region src/states/index.d.ts
1022
+ /**
1023
+ * Parsed advanced state information
1024
+ */
1025
+ interface ParsedAdvancedState {
1026
+ type: 'media' | 'container' | 'root' | 'parent' | 'own' | 'starting' | 'predefined' | 'modifier';
1027
+ condition: string;
1028
+ containerName?: string;
1029
+ raw: string;
1030
+ mediaType?: string;
1322
1031
  }
1323
- type Styles = StylesWithoutSelectors & SpecialStyleProperties & StylesIndexSignature;
1324
1032
  /**
1325
- * Value type for design tokens passed to `configure({ tokens })`.
1326
- * Can be a direct value or a state map for responsive/theme-aware tokens.
1033
+ * Context for state parsing operations
1327
1034
  */
1328
- type ConfigTokenValue = string | number | boolean | Record<string, string | number | boolean | undefined | null | '@inherit'>;
1035
+ interface StateParserContext {
1036
+ localPredefinedStates: Record<string, string>;
1037
+ globalPredefinedStates: Record<string, string>;
1038
+ isSubElement?: boolean;
1039
+ }
1329
1040
  /**
1330
- * Design tokens injected as CSS custom properties on `:root`.
1331
- * Keys must start with `$` (value tokens) or `#` (color tokens).
1332
- *
1333
- * - `$name` keys become `--name` CSS custom properties
1334
- * - `#name` keys become `--name-color` properties
1041
+ * At-rule context for CSS generation
1335
1042
  */
1336
- type ConfigTokens = Record<`$${string}` | `#${string}`, ConfigTokenValue>;
1043
+ interface AtRuleContext {
1044
+ media?: string[];
1045
+ container?: {
1046
+ name?: string;
1047
+ condition: string;
1048
+ }[];
1049
+ startingStyle?: boolean;
1050
+ rootStates?: string[];
1051
+ negatedRootStates?: string[];
1052
+ }
1053
+ /**
1054
+ * Configure global predefined states
1055
+ */
1056
+ declare function setGlobalPredefinedStates(states: Record<string, string>): void;
1057
+ /**
1058
+ * Get global predefined states
1059
+ */
1060
+ declare function getGlobalPredefinedStates(): Record<string, string>;
1061
+ /**
1062
+ * Create a state parser context from styles
1063
+ */
1064
+ declare function createStateParserContext(styles?: Styles, isSubElement?: boolean): StateParserContext;
1337
1065
  //#endregion
1338
- //#region src/pipeline/conditions.d.ts
1066
+ //#region src/pipeline/parseStateKey.d.ts
1067
+ interface ParseStateKeyOptions {
1068
+ context?: StateParserContext;
1069
+ isSubElement?: boolean;
1070
+ }
1339
1071
  /**
1340
- * ConditionNode Types and Helpers
1341
- *
1342
- * Core data structures for representing style conditions as an abstract syntax tree.
1343
- * Used throughout the pipeline for parsing, simplification, and CSS generation.
1072
+ * Parse a state key string into a ConditionNode
1344
1073
  */
1074
+ declare function parseStateKey(stateKey: string, options?: ParseStateKeyOptions): ConditionNode;
1075
+ //#endregion
1076
+ //#region src/pipeline/index.d.ts
1345
1077
  /**
1346
- * Base interface for all state conditions (leaf nodes)
1078
+ * Matches the old StyleResult interface for backward compatibility
1347
1079
  */
1348
- interface BaseStateCondition {
1349
- kind: 'state';
1350
- negated: boolean;
1351
- raw: string;
1352
- uniqueId: string;
1080
+ interface StyleResult {
1081
+ selector: string;
1082
+ declarations: string;
1083
+ atRules?: string[];
1084
+ needsClassName?: boolean;
1085
+ rootPrefix?: string;
1086
+ /** When true, declarations are wrapped in @starting-style { ... } inside the selector rule */
1087
+ startingStyle?: boolean;
1353
1088
  }
1354
1089
  /**
1355
- * Modifier condition: [data-attr] or [data-attr="value"]
1090
+ * Matches the old RenderResult interface for backward compatibility
1356
1091
  */
1357
- interface ModifierCondition extends BaseStateCondition {
1358
- type: 'modifier';
1359
- attribute: string;
1360
- value?: string;
1361
- operator?: '=' | '^=' | '$=' | '*=';
1092
+ interface RenderResult {
1093
+ rules: StyleResult[];
1094
+ className?: string;
1362
1095
  }
1363
1096
  /**
1364
- * Pseudo-class condition: :hover, :focus-visible
1097
+ * Options for renderStyles when using direct selector mode.
1365
1098
  */
1366
- interface PseudoCondition extends BaseStateCondition {
1367
- type: 'pseudo';
1368
- pseudo: string;
1099
+ interface RenderStylesOptions {
1100
+ /**
1101
+ * Whether to double the class selector for increased specificity.
1102
+ * When true, `.myClass` becomes `.myClass.myClass` for higher specificity.
1103
+ *
1104
+ * @default false - User-provided selectors are not doubled.
1105
+ *
1106
+ * Note: This only applies when a classNameOrSelector is provided.
1107
+ * When renderStyles returns RenderResult with needsClassName=true,
1108
+ * the injector handles doubling automatically.
1109
+ */
1110
+ doubleSelector?: boolean;
1369
1111
  }
1370
1112
  /**
1371
- * Numeric bound for dimension queries
1113
+ * Render styles to CSS rules.
1114
+ *
1115
+ * When called without classNameOrSelector, returns RenderResult with needsClassName=true.
1116
+ * When called with a selector/className string, returns StyleResult[] for direct injection.
1372
1117
  */
1373
- interface NumericBound {
1374
- value: string;
1375
- valueNumeric: number | null;
1376
- inclusive: boolean;
1118
+ declare function renderStyles(styles?: Styles, classNameOrSelector?: undefined, options?: undefined, pipelineCacheKey?: string): RenderResult;
1119
+ declare function renderStyles(styles: Styles | undefined, classNameOrSelector: string, options?: RenderStylesOptions): StyleResult[];
1120
+ //#endregion
1121
+ //#region src/properties/property-type-resolver.d.ts
1122
+ /**
1123
+ * PropertyTypeResolver
1124
+ *
1125
+ * Automatically infers CSS @property types from custom property values.
1126
+ * Supports deferred resolution for var() reference chains of arbitrary depth.
1127
+ */
1128
+ declare class PropertyTypeResolver {
1129
+ /** propName → the prop it depends on */
1130
+ private pendingDeps;
1131
+ /** propName → list of props waiting on it */
1132
+ private reverseDeps;
1133
+ /**
1134
+ * Scan CSS declarations and auto-register @property for custom properties
1135
+ * whose types can be inferred from their values.
1136
+ */
1137
+ scanDeclarations(declarations: string, isPropertyDefined: (name: string) => boolean, registerProperty: (name: string, syntax: string, initialValue: string) => void): void;
1138
+ private addDependency;
1139
+ private resolve;
1140
+ private isComplexValue;
1377
1141
  }
1142
+ //#endregion
1143
+ //#region src/injector/batch.d.ts
1378
1144
  /**
1379
- * Media query condition
1145
+ * Deferred CSSOM writes ("batched injection").
1146
+ *
1147
+ * Every `insertRule()` on a live stylesheet invalidates style for the sheet's
1148
+ * scope, so Blink recalculates style the next time anything reads layout or
1149
+ * computed style. When components inject during React's render phase and other
1150
+ * components read layout in the same pass, the two interleave:
1151
+ *
1152
+ * inject -> read (forced recalc) -> inject -> read (forced recalc) -> ...
1153
+ *
1154
+ * Batching moves every sheet write out from between those reads. Writes are
1155
+ * queued in FIFO order and drained in one go, so the tree is invalidated once
1156
+ * per flush instead of once per component.
1157
+ *
1158
+ * ## Ordering
1159
+ *
1160
+ * A single queue holds *all* writes — component rules, global rules, keyframes,
1161
+ * `@property`, `@font-face`, `@counter-style`, `@function` and raw CSS. Draining
1162
+ * it in insertion order keeps the sheet byte-identical to unbatched output,
1163
+ * which matters because equal-specificity rules resolve by document order.
1164
+ *
1165
+ * ## Batch windows — why queuing is safe
1166
+ *
1167
+ * Deferring a write past React's layout phase would let a `useLayoutEffect`
1168
+ * measure an element whose rules are not in the sheet yet, reading the unstyled
1169
+ * box. `<TastyBatchProvider>` closes that hole by opening a *window* during its
1170
+ * render and closing it — flushing — in its `useInsertionEffect`, which React
1171
+ * runs in the mutation phase, before any layout effect:
1172
+ *
1173
+ * provider renders -> window OPEN
1174
+ * children render -> injections queued
1175
+ * provider insertionEffect -> FLUSH, window CLOSED
1176
+ * layout effects run -> rules are in the sheet
1177
+ *
1178
+ * So in the default (`batchInjection: true`) mode a write is only ever queued
1179
+ * inside a commit whose flush is already guaranteed by that same commit. Every
1180
+ * injection outside a window — a deep update the provider did not re-render
1181
+ * for, a `useLayoutEffect` that injects, an event handler, an async callback —
1182
+ * is written straight through, exactly as with batching off.
1183
+ *
1184
+ * `batchInjection: 'always'` opts out of the gate and queues unconditionally.
1185
+ * That wins on more commits, at the cost of the measurement hazard above.
1186
+ *
1187
+ * ## Flush points (earliest wins)
1188
+ *
1189
+ * 1. `<TastyBatchProvider>`'s `useInsertionEffect` — closes the window.
1190
+ * 2. A microtask — a backstop for a render that was aborted or suspended and
1191
+ * therefore never reached its insertion effect. An aborted render mounts
1192
+ * nothing, so nothing can measure what it queued. Microtasks also always
1193
+ * drain before paint, so styles are never visually missing.
1194
+ * 3. `flushStyles()` — explicit, and called internally by every injector read
1195
+ * API (`getCSSText`, `cleanup`, `gc`, `destroy`, ...).
1380
1196
  */
1381
- interface MediaCondition extends BaseStateCondition {
1382
- type: 'media';
1383
- subtype: 'dimension' | 'feature' | 'type';
1384
- dimension?: 'width' | 'height' | 'inline-size' | 'block-size';
1385
- lowerBound?: NumericBound;
1386
- upperBound?: NumericBound;
1387
- feature?: string;
1388
- featureValue?: string;
1389
- mediaType?: 'print' | 'screen' | 'all' | 'speech';
1197
+ interface QueuedWrite {
1198
+ /** Perform the deferred sheet write. */
1199
+ run: () => void;
1200
+ /** Set when the owner disposed before the write happened. */
1201
+ cancelled: boolean;
1202
+ /** Set once the write has been applied (or skipped as cancelled). */
1203
+ done: boolean;
1390
1204
  }
1205
+ /** Whether any write is still waiting to hit a stylesheet. */
1206
+ declare function hasPendingStyleWrites(): boolean;
1391
1207
  /**
1392
- * Container query condition
1208
+ * Drain every pending sheet write, in insertion order.
1209
+ *
1210
+ * Safe to call when the queue is empty (the common case, so the guard comes
1211
+ * first) and safe to call re-entrantly: a nested `flushStyles()` is a no-op,
1212
+ * and work a draining write triggers is written in place by
1213
+ * `enqueueStyleWrite` rather than queued behind the rest of the batch.
1393
1214
  */
1394
- interface ContainerCondition extends BaseStateCondition {
1395
- type: 'container';
1396
- subtype: 'dimension' | 'style' | 'raw';
1397
- containerName?: string;
1398
- dimension?: 'width' | 'height' | 'inline-size' | 'block-size';
1399
- lowerBound?: NumericBound;
1400
- upperBound?: NumericBound;
1401
- property?: string;
1402
- propertyValue?: string;
1403
- rawCondition?: string;
1404
- }
1215
+ declare function flushStyles(): void;
1405
1216
  /**
1406
- * Root state condition: @root(theme=dark)
1217
+ * Drop every pending write without applying it. Test helper — production code
1218
+ * should call `flushStyles()` instead.
1407
1219
  */
1408
- interface RootCondition extends BaseStateCondition {
1409
- type: 'root';
1410
- innerCondition: ConditionNode;
1220
+ declare function resetStyleBatch(): void;
1221
+ //#endregion
1222
+ //#region src/injector/types.d.ts
1223
+ declare global {
1224
+ interface Window {
1225
+ __TASTY__?: string[];
1226
+ }
1411
1227
  }
1412
- /**
1413
- * Parent state condition: @parent(hovered), @parent(theme=dark, >)
1414
- */
1415
- interface ParentCondition extends BaseStateCondition {
1416
- type: 'parent';
1417
- innerCondition: ConditionNode;
1418
- direct: boolean;
1228
+ interface InjectResult {
1229
+ className: string;
1230
+ dispose: () => void;
1231
+ }
1232
+ interface GlobalInjectResult {
1233
+ dispose: () => void;
1234
+ }
1235
+ type DisposeFunction = () => void;
1236
+ interface StyleInjectorConfig {
1237
+ nonce?: string;
1238
+ maxRulesPerSheet?: number;
1239
+ forceTextInjection?: boolean;
1240
+ /** Enable development mode features: performance metrics and debug information storage */
1241
+ devMode?: boolean;
1242
+ /**
1243
+ * Global predefined states for advanced state mapping.
1244
+ * These are state aliases that can be used in any component.
1245
+ * Example: { '@mobile': '@media(w < 920px)', '@dark': '@root(theme=dark)' }
1246
+ */
1247
+ states?: Record<string, string>;
1248
+ /**
1249
+ * Automatically infer and register CSS @property declarations
1250
+ * from custom property values. When false, only explicit @property are used.
1251
+ * @default true
1252
+ */
1253
+ autoPropertyTypes?: boolean;
1254
+ /** Garbage collection configuration for unused styles */
1255
+ gc?: GCConfig;
1256
+ /**
1257
+ * Prefix prepended to every generated identifier.
1258
+ * Mirrors the `namePrefix` field on the public `TastyConfig` so that
1259
+ * standalone injector consumers can configure it directly.
1260
+ * @default 't'
1261
+ */
1262
+ namePrefix?: string;
1263
+ /**
1264
+ * Defer stylesheet writes and apply them in one batch instead of one
1265
+ * `insertRule()` per component. Mirrors `batchInjection` on the public
1266
+ * `TastyConfig`.
1267
+ * @default false
1268
+ */
1269
+ batchInjection?: boolean | 'always';
1419
1270
  }
1420
1271
  /**
1421
- * Own state condition: @own(hovered)
1272
+ * Per-className usage tracking for GC.
1422
1273
  */
1423
- interface OwnCondition extends BaseStateCondition {
1424
- type: 'own';
1425
- innerCondition: ConditionNode;
1426
- }
1427
1274
  /**
1428
- * Starting style condition: @starting
1275
+ * @deprecated Nothing reads this any more. Collection asks the DOM what is
1276
+ * rendered rather than tracking usage per class, so there is no usage record
1277
+ * to describe. Kept so existing imports keep type-checking.
1429
1278
  */
1430
- interface StartingCondition extends BaseStateCondition {
1431
- type: 'starting';
1279
+ interface StyleUsage {
1280
+ lastTouchedAt: number;
1432
1281
  }
1433
1282
  /**
1434
- * Supports query condition: @supports(display: grid), @supports($, :has(*))
1283
+ * Configuration for the style garbage collector.
1284
+ *
1285
+ * GC is triggered by touch count rather than timers: every `touchInterval`
1286
+ * touches, an idle callback is scheduled to evict unused styles above
1287
+ * `capacity`, oldest first.
1435
1288
  */
1436
- interface SupportsCondition extends BaseStateCondition {
1437
- type: 'supports';
1438
- subtype: 'feature' | 'selector';
1439
- condition: string;
1289
+ interface GCConfig {
1290
+ /**
1291
+ * How long a class is left alone after collection first notices nothing is
1292
+ * carrying it, in milliseconds (default 10,000).
1293
+ *
1294
+ * Rendering is not commit-aware: a render can resolve a class and commit it a
1295
+ * little later, and in between nothing on the page carries it. Rather than
1296
+ * try to tell that apart from a class that is finished — which cannot be done
1297
+ * from outside React — collection simply does not touch anything that was in
1298
+ * use recently. A render would have to stay pending for the whole window to
1299
+ * lose its rules, and it gets them back on its next render.
1300
+ */
1301
+ grace?: number;
1302
+ /**
1303
+ * Number of touch events between automatic GC cycles.
1304
+ * @default 1000
1305
+ */
1306
+ touchInterval?: number;
1307
+ /**
1308
+ * Maximum number of unused styles to retain.
1309
+ * GC evicts the oldest unused styles when this limit is exceeded.
1310
+ * Pinned styles and DOM-live styles
1311
+ * do not count against this limit.
1312
+ * @default 1000
1313
+ */
1314
+ capacity?: number;
1440
1315
  }
1441
1316
  /**
1442
- * Union of all state condition types
1317
+ * Per-call options for inject().
1443
1318
  */
1444
- type StateCondition = ModifierCondition | PseudoCondition | MediaCondition | ContainerCondition | RootCondition | ParentCondition | OwnCondition | StartingCondition | SupportsCondition;
1319
+ interface InjectOptions {
1320
+ root?: Document | ShadowRoot;
1321
+ /** Reuse the class already injected for this key instead of writing again. */
1322
+ cacheKey?: string;
1323
+ /**
1324
+ * Pin the injected class (default `true`). A pinned class is never evicted by
1325
+ * `gc()`, and the returned `dispose()` releases the pin. Pass `false` when the
1326
+ * caller keeps no handle and the DOM is the only record that the class is in
1327
+ * use — the render path does this, because a hook-free render has no unmount
1328
+ * signal to dispose on.
1329
+ */
1330
+ pin?: boolean;
1331
+ }
1445
1332
  /**
1446
- * Compound node: combines conditions with AND/OR
1333
+ * Per-call options for gc().
1447
1334
  */
1448
- interface CompoundCondition {
1449
- kind: 'compound';
1450
- operator: 'AND' | 'OR';
1451
- children: ConditionNode[];
1335
+ interface GCOptions {
1336
+ root?: Document | ShadowRoot;
1337
+ /** Bypass capacity threshold and remove ALL unused styles. */
1338
+ force?: boolean;
1339
+ }
1340
+ interface RuleInfo {
1341
+ className: string;
1342
+ ruleIndex: number;
1343
+ sheetIndex: number;
1344
+ /** Dev-only: full CSS texts inserted for this class; omitted in production */
1345
+ cssText?: string[];
1346
+ /** Inclusive end index of the contiguous block of inserted rules for this className */
1347
+ endRuleIndex?: number;
1348
+ /** NEW: exact indices of all inserted rules for this className */
1349
+ indices?: number[];
1350
+ }
1351
+ type InjectionMode = 'style-element' | 'adopted';
1352
+ interface SheetInfo {
1353
+ /** HTMLStyleElement used in style-element mode; null in adopted mode. */
1354
+ sheet: HTMLStyleElement | null;
1355
+ /** Constructable CSSStyleSheet used in adopted mode (ShadowRoot targets) */
1356
+ constructableSheet?: CSSStyleSheet;
1357
+ ruleCount: number;
1358
+ holes: number[];
1359
+ /**
1360
+ * True when this sheet is written through `textContent` instead of CSSOM.
1361
+ * Decided once at sheet creation so a sheet is never half CSSOM / half text.
1362
+ */
1363
+ textMode?: boolean;
1364
+ /**
1365
+ * Inserted rule texts in rule-index order. Maintained only in text mode —
1366
+ * it is what makes deletion possible there, since `textContent` cannot be
1367
+ * edited rule-by-rule and has to be rebuilt.
1368
+ */
1369
+ textRules?: string[];
1370
+ }
1371
+ interface CleanupStats {
1372
+ timestamp: number;
1373
+ classesDeleted: number;
1374
+ cssSize: number;
1375
+ rulesDeleted: number;
1376
+ }
1377
+ interface CacheMetrics {
1378
+ hits: number;
1379
+ misses: number;
1380
+ bulkCleanups: number;
1381
+ totalInsertions: number;
1382
+ totalUnused: number;
1383
+ stylesCleanedUp: number;
1384
+ cleanupHistory: CleanupStats[];
1385
+ startTime: number;
1386
+ unusedHits?: number;
1387
+ }
1388
+ interface RootRegistry {
1389
+ sheets: SheetInfo[];
1390
+ /** className -> outstanding `inject()` references; 0 means nobody holds a handle */
1391
+ pinCounts: Map<string, number>;
1392
+ rules: Map<string, RuleInfo>;
1393
+ /** Cache key to className mapping to avoid dual storage of RuleInfo objects */
1394
+ cacheKeyToClassName: Map<string, string>;
1395
+ /** Deduplication set of fully materialized CSS rules inserted into sheets */
1396
+ ruleTextSet: Set<string>;
1397
+ /** Performance metrics (optional) */
1398
+ metrics?: CacheMetrics;
1399
+ /** Keyframes cache by content hash -> entry */
1400
+ keyframesCache: Map<string, KeyframesCacheEntry>;
1401
+ /** Keyframes name to content hash mapping for collision detection */
1402
+ keyframesNameToContent: Map<string, string>;
1403
+ /** Counter for generating keyframes names like k0, k1, k2... */
1404
+ keyframesCounter: number;
1405
+ /** Map of injected @property names to their normalized declarations for tracking */
1406
+ injectedProperties: Map<string, string>;
1407
+ /** Content hashes of injected @font-face rules for deduplication */
1408
+ injectedFontFaces: Set<string>;
1409
+ /**
1410
+ * Injected @counter-style rules. Maps the name to whether it was injected
1411
+ * "strong" (`true`, the default — overrides) or "weak" (`false`, global
1412
+ * `configure()` definitions that never clobber an existing rule).
1413
+ */
1414
+ injectedCounterStyles: Map<string, boolean>;
1415
+ /**
1416
+ * Injected @function rules. Maps the CSS function name to whether it was
1417
+ * injected "strong" (`true`, the default — overrides) or "weak" (`false`,
1418
+ * global `configure()` definitions that never clobber an existing rule).
1419
+ */
1420
+ injectedFunctions: Map<string, boolean>;
1421
+ /** Global rules tracking for index adjustment */
1422
+ globalRules: Map<string, RuleInfo>;
1423
+ /** Resolver for auto-inferring @property types from declaration values */
1424
+ propertyTypeResolver: PropertyTypeResolver;
1425
+ /**
1426
+ * className -> when the class was first noticed to be carrying nothing:
1427
+ * injection, or the first sweep that looked and did not find it on an
1428
+ * element. Cleared the moment a sweep finds it rendered again.
1429
+ *
1430
+ * Deliberately "when it was noticed", not "when it stopped being rendered".
1431
+ * Nothing observes the moment an element leaves, so a class that unmounted
1432
+ * just before a sweep and one that unmounted just after the previous sweep
1433
+ * would otherwise be treated differently — and the first would lose its
1434
+ * grace window entirely. Starting the clock at the sighting gives every
1435
+ * class the same full window, whenever it actually went.
1436
+ *
1437
+ * Written only by the sweep's own DOM scan and at injection, so rendering
1438
+ * never pays for it.
1439
+ */
1440
+ unusedSince: Map<string, number>;
1441
+ /**
1442
+ * Local `@keyframes` a class animates, by the name they were authored under.
1443
+ *
1444
+ * One reference is held per distinct set of steps, however many renders ask
1445
+ * for it, and the classes that animate it own that reference between them.
1446
+ * The last of them to be deleted releases it, so keyframes cannot outlive
1447
+ * every rule that referred to them, and repeat renders cannot pile up
1448
+ * references nobody gives back.
1449
+ */
1450
+ localKeyframes: Map<string, {
1451
+ name: string;
1452
+ dispose: () => void;
1453
+ owners: Set<string>;
1454
+ }>;
1455
+ /** Renders since the last scheduled sweep (per-root) */
1456
+ touchCount: number;
1457
+ /** How many entries from `window.__TASTY__` have been synced into this registry */
1458
+ serverClassSyncIndex: number;
1459
+ /** Whether `<style data-tasty-rsc>` tags have been scanned for class names */
1460
+ rscStylesScanned: boolean;
1461
+ /** Whether this root uses adoptedStyleSheets or <style> elements */
1462
+ injectionMode: InjectionMode;
1463
+ /**
1464
+ * Lazy feature-test for `@property` support, cached per registry.
1465
+ * - `undefined`: not yet probed.
1466
+ * - `true`: engine supports `@property`; rejections indicate user-authored
1467
+ * invalid rules and should warn.
1468
+ * - `false`: engine doesn't support `@property` (e.g., jsdom); rejections
1469
+ * are expected and warnings are suppressed.
1470
+ */
1471
+ atPropertySupported?: boolean;
1452
1472
  }
1453
- /**
1454
- * True condition (matches everything)
1455
- */
1456
- interface TrueCondition {
1457
- kind: 'true';
1473
+ type StyleRule = StyleResult;
1474
+ interface KeyframesInfo {
1475
+ name: string;
1476
+ sheetIndex: number;
1477
+ ruleIndex: number;
1478
+ /** Dev-only: full CSS text of the @keyframes rule; omitted in production */
1479
+ cssText?: string;
1458
1480
  }
1459
- /**
1460
- * False condition (matches nothing - skip this rule)
1461
- */
1462
- interface FalseCondition {
1463
- kind: 'false';
1481
+ type KeyframeStep = string | Record<string, string | number>;
1482
+ type KeyframesSteps = Record<string, KeyframeStep>;
1483
+ interface KeyframesResult {
1484
+ toString(): string;
1485
+ dispose: () => void;
1464
1486
  }
1465
- /**
1466
- * Union of all condition node types
1467
- */
1468
- type ConditionNode = StateCondition | CompoundCondition | TrueCondition | FalseCondition;
1469
- //#endregion
1470
- //#region src/states/index.d.ts
1471
- /**
1472
- * Parsed advanced state information
1473
- */
1474
- interface ParsedAdvancedState {
1475
- type: 'media' | 'container' | 'root' | 'parent' | 'own' | 'starting' | 'predefined' | 'modifier';
1476
- condition: string;
1477
- containerName?: string;
1478
- raw: string;
1479
- mediaType?: string;
1487
+ interface KeyframesCacheEntry {
1488
+ name: string;
1489
+ refCount: number;
1490
+ info: KeyframesInfo;
1491
+ /**
1492
+ * Queued sheet write, when `batchInjection` deferred the insertion. Present
1493
+ * only between `keyframes()` and the flush; disposing in that window cancels
1494
+ * the write instead of deleting a rule that was never inserted.
1495
+ */
1496
+ pending?: QueuedWrite;
1480
1497
  }
1481
1498
  /**
1482
- * Context for state parsing operations
1499
+ * Definition for a CSS @property at-rule.
1500
+ * Used to define custom property syntax, inheritance, and initial value.
1483
1501
  */
1484
- interface StateParserContext {
1485
- localPredefinedStates: Record<string, string>;
1486
- globalPredefinedStates: Record<string, string>;
1487
- isSubElement?: boolean;
1502
+ interface PropertyDefinition {
1503
+ /** CSS syntax string (e.g., '<color>', '<angle>', '<number>') */
1504
+ syntax?: string;
1505
+ /** Whether the property inherits (default: true) */
1506
+ inherits?: boolean;
1507
+ /** Initial value for the property */
1508
+ initialValue?: string | number;
1488
1509
  }
1489
1510
  /**
1490
- * At-rule context for CSS generation
1511
+ * Options for registering a CSS `@property`.
1512
+ * Extends {@link PropertyDefinition} with an optional injection root.
1491
1513
  */
1492
- interface AtRuleContext {
1493
- media?: string[];
1494
- container?: {
1495
- name?: string;
1496
- condition: string;
1497
- }[];
1498
- startingStyle?: boolean;
1499
- rootStates?: string[];
1500
- negatedRootStates?: string[];
1514
+ interface PropertyOptions extends PropertyDefinition {
1515
+ /** Shadow root or document to inject into */
1516
+ root?: Document | ShadowRoot;
1501
1517
  }
1502
1518
  /**
1503
- * Configure global predefined states
1504
- */
1505
- declare function setGlobalPredefinedStates(states: Record<string, string>): void;
1506
- /**
1507
- * Get global predefined states
1519
+ * A single parameter for a CSS @function at-rule.
1520
+ *
1521
+ * - `true` a bare parameter with no type or default.
1522
+ * - `string` — a CSS type shorthand (e.g. `'<length>'`, `'<color>'`).
1523
+ * - object full form with optional `syntax` (type) and `default` value.
1508
1524
  */
1509
- declare function getGlobalPredefinedStates(): Record<string, string>;
1525
+ type FunctionParameter = true | string | {
1526
+ syntax?: string;
1527
+ default?: string | number;
1528
+ };
1510
1529
  /**
1511
- * Create a state parser context from styles
1530
+ * Definition for a CSS @function at-rule (custom function).
1531
+ *
1532
+ * The descriptor body reads like a mini styles object: any `$name` key declares
1533
+ * a local variable (`--name`) whose value is parsed through the Tasty DSL.
1534
+ * `result` is the only required field.
1535
+ *
1536
+ * @example
1537
+ * ```ts
1538
+ * // @function --negative(--value) { result: calc(-1 * var(--value)); }
1539
+ * { args: ['$value'], result: '(-1 * $value)' }
1540
+ * ```
1512
1541
  */
1513
- declare function createStateParserContext(styles?: Styles, isSubElement?: boolean): StateParserContext;
1514
- //#endregion
1515
- //#region src/pipeline/parseStateKey.d.ts
1516
- interface ParseStateKeyOptions {
1517
- context?: StateParserContext;
1518
- isSubElement?: boolean;
1542
+ interface FunctionDefinition {
1543
+ /**
1544
+ * Ordered parameters. Array form lists bare parameter names (`['$value']`);
1545
+ * object form maps each parameter name to its type/default.
1546
+ */
1547
+ args?: string[] | Record<string, FunctionParameter>;
1548
+ /** Optional return type, e.g. `'<color>'`. */
1549
+ returns?: string;
1550
+ /** The `result:` descriptor value (parsed through the Tasty DSL). Required. */
1551
+ result: string;
1552
+ /** Local variables: any `$name` key declares `--name` in the body. */
1553
+ [localVar: `$${string}`]: string | number | undefined;
1519
1554
  }
1520
1555
  /**
1521
- * Parse a state key string into a ConditionNode
1522
- */
1523
- declare function parseStateKey(stateKey: string, options?: ParseStateKeyOptions): ConditionNode;
1524
- //#endregion
1525
- //#region src/pipeline/index.d.ts
1526
- /**
1527
- * Matches the old StyleResult interface for backward compatibility
1556
+ * Descriptors for a CSS @font-face at-rule.
1528
1557
  */
1529
- interface StyleResult {
1530
- selector: string;
1531
- declarations: string;
1532
- atRules?: string[];
1533
- needsClassName?: boolean;
1534
- rootPrefix?: string;
1535
- /** When true, declarations are wrapped in @starting-style { ... } inside the selector rule */
1536
- startingStyle?: boolean;
1558
+ interface FontFaceDescriptors {
1559
+ /** Required. URL(s) to the font file(s). */
1560
+ src: string;
1561
+ /** Font weight or range. Default: 'normal'. */
1562
+ fontWeight?: string | number;
1563
+ /** Font style. Default: 'normal'. */
1564
+ fontStyle?: 'normal' | 'italic' | 'oblique' | (string & {});
1565
+ /** Font stretch. Default: 'normal'. */
1566
+ fontStretch?: string;
1567
+ /** Loading behavior. Default: 'auto'. */
1568
+ fontDisplay?: 'auto' | 'block' | 'swap' | 'fallback' | 'optional';
1569
+ /** Unicode range to cover. */
1570
+ unicodeRange?: string;
1571
+ /** Ascent metric override. */
1572
+ ascentOverride?: string;
1573
+ /** Descent metric override. */
1574
+ descentOverride?: string;
1575
+ /** Line gap metric override. */
1576
+ lineGapOverride?: string;
1577
+ /** Size adjustment factor. */
1578
+ sizeAdjust?: string;
1579
+ /** OpenType feature settings. */
1580
+ fontFeatureSettings?: string;
1581
+ /** Font variation axis settings. */
1582
+ fontVariationSettings?: string;
1537
1583
  }
1584
+ /** Single descriptor or array of descriptors for multiple weights/styles. */
1585
+ type FontFaceInput = FontFaceDescriptors | FontFaceDescriptors[];
1538
1586
  /**
1539
- * Matches the old RenderResult interface for backward compatibility
1587
+ * Descriptors for a CSS @counter-style at-rule.
1540
1588
  */
1541
- interface RenderResult {
1542
- rules: StyleResult[];
1543
- className?: string;
1589
+ interface CounterStyleDescriptors {
1590
+ /** Required. Numbering algorithm. */
1591
+ system: 'cyclic' | 'numeric' | 'alphabetic' | 'symbolic' | 'additive' | 'fixed' | (string & {});
1592
+ /** Symbols for non-additive systems. */
1593
+ symbols?: string;
1594
+ /** Symbol-value pairs for additive system. */
1595
+ additiveSymbols?: string;
1596
+ /** String prepended to the marker. Default: "". */
1597
+ prefix?: string;
1598
+ /** String appended to the marker. Default: ". ". */
1599
+ suffix?: string;
1600
+ /** Negative-value wrapping (e.g., '"(" ")"'). */
1601
+ negative?: string;
1602
+ /** Counter range (e.g., 'infinite infinite'). */
1603
+ range?: string;
1604
+ /** Minimum marker width and pad symbol (e.g., '3 "0"'). */
1605
+ pad?: string;
1606
+ /** Fallback counter style name. */
1607
+ fallback?: string;
1608
+ /** Speech synthesis hint. */
1609
+ speakAs?: string;
1544
1610
  }
1545
- /**
1546
- * Check if a key is a CSS selector
1547
- */
1548
- declare function isSelector(key: string): boolean;
1549
- /**
1550
- * Options for renderStyles when using direct selector mode.
1551
- */
1552
- interface RenderStylesOptions {
1553
- /**
1554
- * Whether to double the class selector for increased specificity.
1555
- * When true, `.myClass` becomes `.myClass.myClass` for higher specificity.
1556
- *
1557
- * @default false - User-provided selectors are not doubled.
1558
- *
1559
- * Note: This only applies when a classNameOrSelector is provided.
1560
- * When renderStyles returns RenderResult with needsClassName=true,
1561
- * the injector handles doubling automatically.
1562
- */
1563
- doubleSelector?: boolean;
1611
+ interface RawCSSResult {
1612
+ dispose: () => void;
1564
1613
  }
1565
- /**
1566
- * Render styles to CSS rules.
1567
- *
1568
- * When called without classNameOrSelector, returns RenderResult with needsClassName=true.
1569
- * When called with a selector/className string, returns StyleResult[] for direct injection.
1570
- */
1571
- declare function renderStyles(styles?: Styles, classNameOrSelector?: undefined, options?: undefined, pipelineCacheKey?: string): RenderResult;
1572
- declare function renderStyles(styles: Styles | undefined, classNameOrSelector: string, options?: RenderStylesOptions): StyleResult[];
1573
1614
  //#endregion
1574
- export { StyleParser as $, ParsedColor as A, StyleRule as At, StyleValueStateMap as B, SuffixForSelector as C, PropertyDefinition as Ct, CSSMap as D, RuleInfo as Dt, AnyStyleHandler as E, RootRegistry as Et, StyleHandlerProps as F, resetStyleBatch as Ft, parseColor as G, getGlobalParser as H, StyleHandlerResult as I, getNamedColorHex as J, parseStyle as K, StyleMap as L, ResolvedStyleValue as M, QueuedWrite as Mt, StyleHandler as N, flushStyles as Nt, CUSTOM_UNITS as O, SheetInfo as Ot, StyleHandlerDefinition as P, hasPendingStyleWrites as Pt, strToRgb as Q, StylePropValue as R, StylesWithoutSelectors as S, KeyframesSteps as St, TastyPresetNames as T, RawCSSResult as Tt, getGlobalPredefinedTokens as U, filterMods as V, normalizeColorTokenValue as W, hexToRgb as X, getRgbValuesFromRgbaString as Y, hslToRgbValues as Z, NotSelector as _, InjectResult as _t, ParseStateKeyOptions as a, CSSProperties as at, Styles as b, KeyframesInfo as bt, ParsedAdvancedState as c, DisposeFunction as ct, getGlobalPredefinedStates as d, FunctionDefinition as dt, ParserOptions as et, setGlobalPredefinedStates as f, FunctionParameter as ft, NoType as g, InjectOptions as gt, ConfigTokens as h, GlobalInjectResult as ht, renderStyles as i, UnitHandler as it, RawStyleHandler as j, StyleUsage as jt, DIRECTIONS as k, StyleInjectorConfig as kt, StateParserContext as l, FontFaceDescriptors as lt, ConfigTokenValue as m, GCOptions as mt, StyleResult as n, StyleDetails as nt, parseStateKey as o, CacheMetrics as ot, ConditionNode as p, GCConfig as pt, stringifyStyles as q, isSelector as r, StyleDetailsPart as rt, AtRuleContext as s, CounterStyleDescriptors as st, RenderResult as t, ProcessedStyle as tt, createStateParserContext as u, FontFaceInput as ut, RecipeStyles as v, InjectionMode as vt, TastyNamedColors as w, PropertyOptions as wt, StylesInterface as x, KeyframesResult as xt, Selector as y, KeyframesCacheEntry as yt, StyleValue as z };
1575
- //# sourceMappingURL=index-BmogEzTo.d.ts.map
1615
+ export { SuffixForSelector as $, resetStyleBatch as A, ParserOptions as At, getGlobalPredefinedStates as B, SheetInfo as C, stringifyStyles as Ct, QueuedWrite as D, hslToRgbValues as Dt, StyleUsage as E, hexToRgb as Et, parseStateKey as F, CSSProperties as Ft, ConfigTokens as G, ConditionNode as H, AtRuleContext as I, RecipeStyles as J, NoType as K, ParsedAdvancedState as L, StyleResult as M, StyleDetails as Mt, renderStyles as N, StyleDetailsPart as Nt, flushStyles as O, strToRgb as Ot, ParseStateKeyOptions as P, UnitHandler as Pt, StylesWithoutSelectors as Q, StateParserContext as R, RuleInfo as S, parseStyle as St, StyleRule as T, getRgbValuesFromRgbaString as Tt, isSelector as U, setGlobalPredefinedStates as V, ConfigTokenValue as W, Styles as X, Selector as Y, StylesInterface as Z, KeyframesSteps as _, filterMods as _t, FontFaceInput as a, DIRECTIONS as at, RawCSSResult as b, normalizeColorTokenValue as bt, GCConfig as c, ResolvedStyleValue as ct, InjectOptions as d, StyleHandlerProps as dt, TastyNamedColors as et, InjectResult as f, StyleHandlerResult as ft, KeyframesResult as g, StyleValueStateMap as gt, KeyframesInfo as h, StyleValue as ht, FontFaceDescriptors as i, CUSTOM_UNITS as it, RenderResult as j, ProcessedStyle as jt, hasPendingStyleWrites as k, StyleParser as kt, GCOptions as l, StyleHandler as lt, KeyframesCacheEntry as m, StylePropValue as mt, CounterStyleDescriptors as n, AnyStyleHandler as nt, FunctionDefinition as o, ParsedColor as ot, InjectionMode as p, StyleMap as pt, NotSelector as q, DisposeFunction as r, CSSMap as rt, FunctionParameter as s, RawStyleHandler as st, CacheMetrics as t, TastyPresetNames as tt, GlobalInjectResult as u, StyleHandlerDefinition as ut, PropertyDefinition as v, getGlobalParser as vt, StyleInjectorConfig as w, getNamedColorHex as wt, RootRegistry as x, parseColor as xt, PropertyOptions as y, getGlobalPredefinedTokens as yt, createStateParserContext as z };
1616
+ //# sourceMappingURL=types-jKZNpias.d.ts.map