@tenphi/tasty 0.0.0-snapshot.1d29633 → 0.0.0-snapshot.1f1c00a

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