@tenphi/tasty 0.13.0 → 0.14.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 (92) hide show
  1. package/README.md +117 -28
  2. package/dist/chunks/cacheKey.js +16 -8
  3. package/dist/chunks/cacheKey.js.map +1 -1
  4. package/dist/chunks/renderChunk.js +31 -32
  5. package/dist/chunks/renderChunk.js.map +1 -1
  6. package/dist/config.d.ts +14 -2
  7. package/dist/config.js +11 -4
  8. package/dist/config.js.map +1 -1
  9. package/dist/core/index.d.ts +6 -4
  10. package/dist/core/index.js +5 -4
  11. package/dist/debug.d.ts +26 -141
  12. package/dist/debug.js +356 -635
  13. package/dist/debug.js.map +1 -1
  14. package/dist/hooks/useStyles.js +4 -3
  15. package/dist/hooks/useStyles.js.map +1 -1
  16. package/dist/index.d.ts +6 -4
  17. package/dist/index.js +5 -4
  18. package/dist/parser/classify.js +2 -1
  19. package/dist/parser/classify.js.map +1 -1
  20. package/dist/parser/parser.js +1 -1
  21. package/dist/pipeline/index.d.ts +1 -1
  22. package/dist/pipeline/index.js +24 -14
  23. package/dist/pipeline/index.js.map +1 -1
  24. package/dist/pipeline/materialize.js +328 -79
  25. package/dist/pipeline/materialize.js.map +1 -1
  26. package/dist/pipeline/parseStateKey.d.ts +1 -1
  27. package/dist/pipeline/parseStateKey.js +2 -6
  28. package/dist/pipeline/parseStateKey.js.map +1 -1
  29. package/dist/plugins/okhsl-plugin.js +2 -275
  30. package/dist/plugins/okhsl-plugin.js.map +1 -1
  31. package/dist/plugins/types.d.ts +1 -1
  32. package/dist/properties/index.js +2 -15
  33. package/dist/properties/index.js.map +1 -1
  34. package/dist/ssr/format-property.js +9 -7
  35. package/dist/ssr/format-property.js.map +1 -1
  36. package/dist/states/index.js +10 -257
  37. package/dist/states/index.js.map +1 -1
  38. package/dist/styles/color.js +9 -5
  39. package/dist/styles/color.js.map +1 -1
  40. package/dist/styles/createStyle.js +24 -21
  41. package/dist/styles/createStyle.js.map +1 -1
  42. package/dist/styles/index.js +1 -1
  43. package/dist/styles/predefined.js +1 -1
  44. package/dist/styles/predefined.js.map +1 -1
  45. package/dist/styles/types.d.ts +1 -1
  46. package/dist/tasty.d.ts +6 -6
  47. package/dist/tasty.js +24 -11
  48. package/dist/tasty.js.map +1 -1
  49. package/dist/types.d.ts +1 -1
  50. package/dist/utils/cache-wrapper.js +4 -8
  51. package/dist/utils/cache-wrapper.js.map +1 -1
  52. package/dist/utils/color-math.d.ts +46 -0
  53. package/dist/utils/color-math.js +749 -0
  54. package/dist/utils/color-math.js.map +1 -0
  55. package/dist/utils/color-space.d.ts +5 -0
  56. package/dist/utils/color-space.js +229 -0
  57. package/dist/utils/color-space.js.map +1 -0
  58. package/dist/utils/colors.js +3 -1
  59. package/dist/utils/colors.js.map +1 -1
  60. package/dist/utils/has-keys.js +13 -0
  61. package/dist/utils/has-keys.js.map +1 -0
  62. package/dist/utils/mod-attrs.js +2 -2
  63. package/dist/utils/mod-attrs.js.map +1 -1
  64. package/dist/utils/process-tokens.d.ts +3 -13
  65. package/dist/utils/process-tokens.js +18 -98
  66. package/dist/utils/process-tokens.js.map +1 -1
  67. package/dist/utils/styles.d.ts +2 -78
  68. package/dist/utils/styles.js +28 -535
  69. package/dist/utils/styles.js.map +1 -1
  70. package/dist/zero/babel.d.ts +8 -0
  71. package/dist/zero/babel.js +18 -3
  72. package/dist/zero/babel.js.map +1 -1
  73. package/dist/zero/next.js +9 -1
  74. package/dist/zero/next.js.map +1 -1
  75. package/docs/PIPELINE.md +519 -0
  76. package/docs/README.md +30 -0
  77. package/docs/adoption.md +10 -2
  78. package/docs/comparison.md +11 -6
  79. package/docs/configuration.md +26 -3
  80. package/docs/debug.md +152 -339
  81. package/docs/dsl.md +3 -1
  82. package/docs/getting-started.md +21 -7
  83. package/docs/injector.md +2 -2
  84. package/docs/runtime.md +59 -9
  85. package/docs/ssr.md +2 -2
  86. package/docs/styles.md +1 -1
  87. package/docs/tasty-static.md +19 -9
  88. package/package.json +4 -3
  89. package/dist/utils/hsl-to-rgb.js +0 -38
  90. package/dist/utils/hsl-to-rgb.js.map +0 -1
  91. package/dist/utils/okhsl-to-rgb.js +0 -296
  92. package/dist/utils/okhsl-to-rgb.js.map +0 -1
package/docs/debug.md CHANGED
@@ -6,11 +6,11 @@ Runtime CSS inspection and diagnostics for the Tasty styling system. Inspect inj
6
6
 
7
7
  ## Overview
8
8
 
9
- `tastyDebug` is a diagnostic object that exposes every aspect of Tasty's runtime CSS state. It is designed for development use: inspecting which CSS is active, what's cached, how chunks are distributed, and whether cleanup is working as expected.
9
+ `tastyDebug` is a diagnostic object that exposes Tasty's runtime CSS state. It is designed for development use but can be manually installed in production for debugging.
10
10
 
11
- In development mode (`isDevEnv()` returns `true`), `tastyDebug` is automatically installed on `window.tastyDebug`. In production, you can install it manually when needed.
11
+ In development mode (`isDevEnv()` returns `true`), `tastyDebug` is automatically installed on `window.tastyDebug`. In production, install it manually when needed.
12
12
 
13
- > **Note:** This is a development/debugging tool. It does not affect style generation or application behavior.
13
+ All methods **log to the console by default**. Pass `{ raw: true }` to suppress logging and only return data.
14
14
 
15
15
  ---
16
16
 
@@ -24,96 +24,82 @@ tastyDebug.install();
24
24
  // Print a quick-start guide
25
25
  tastyDebug.help();
26
26
 
27
- // Get a comprehensive overview logged to the console
28
- tastyDebug.summary({ log: true });
27
+ // Get a comprehensive overview (logged automatically)
28
+ tastyDebug.summary();
29
29
 
30
- // See all active CSS (for components currently in the DOM)
31
- tastyDebug.log('active');
30
+ // See all active CSS
31
+ tastyDebug.css('active');
32
32
 
33
33
  // Inspect a specific element
34
34
  tastyDebug.inspect('.my-button');
35
35
 
36
- // Check cache hit rates
37
- tastyDebug.metrics();
36
+ // Silent mode return data only, no console output
37
+ const data = tastyDebug.summary({ raw: true });
38
38
  ```
39
39
 
40
40
  ---
41
41
 
42
- ## Core Types
43
-
44
- ### `CSSTarget`
45
-
46
- The `target` parameter accepted by `css()`, `log()`, and related methods:
47
-
48
- ```typescript
49
- type CSSTarget =
50
- | 'all' // All tasty CSS (component + global + raw)
51
- | 'global' // Only global CSS (from injectGlobal)
52
- | 'active' // CSS for classes currently present in the DOM
53
- | 'unused' // CSS with refCount = 0 (cached but not actively used)
54
- | 'page' // ALL CSS on the page, including non-tasty stylesheets
55
- | string // A tasty class ('t123') or a CSS selector ('.my-class')
56
- | string[] // Array of tasty classes (['t0', 't5', 't12'])
57
- | Element; // A DOM element
58
- ```
59
-
60
- ### `CssOptions`
42
+ ## Options
61
43
 
62
- Common options for CSS retrieval methods:
44
+ All methods accept a shared options object:
63
45
 
64
46
  ```typescript
65
- interface CssOptions {
66
- root?: Document | ShadowRoot; // Target root (default: document)
67
- prettify?: boolean; // Format CSS output (default: true)
68
- log?: boolean; // Auto-log to console (default: false)
47
+ interface DebugOptions {
48
+ root?: Document | ShadowRoot; // Target root (default: document)
49
+ raw?: boolean; // Suppress console logging (default: false)
69
50
  }
70
51
  ```
71
52
 
53
+ When `raw` is `false` (the default), results are logged to the console **and** returned. When `raw` is `true`, results are returned silently.
54
+
72
55
  ---
73
56
 
74
57
  ## API Reference
75
58
 
76
59
  ### `css(target, opts?): string`
77
60
 
78
- Retrieves CSS text for a given target. This is the primary method for extracting CSS from the runtime.
61
+ Retrieves CSS text for a given target. Logs the result with rule count and size.
79
62
 
80
- ```typescript
81
- // All tasty CSS
82
- tastyDebug.css('all');
63
+ **Targets:**
83
64
 
84
- // Only CSS for classes currently in the DOM
85
- tastyDebug.css('active');
65
+ | Target | Description |
66
+ |---|---|
67
+ | `'all'` | All tasty CSS (component + global + raw) |
68
+ | `'active'` | CSS for classes currently in the DOM |
69
+ | `'unused'` | CSS with refCount = 0 (cached but not used) |
70
+ | `'global'` | Only global CSS (from `injectGlobal`) |
71
+ | `'page'` | All CSS on the page (including non-tasty) |
72
+ | `'t42'` | CSS for a specific tasty class |
73
+ | `['t0', 't5']` | CSS for multiple tasty classes |
74
+ | `'.my-button'` | CSS affecting a DOM element (by selector) |
75
+ | `element` | CSS affecting a DOM element (by reference) |
86
76
 
87
- // CSS for unused classes (refCount = 0, still in cache)
88
- tastyDebug.css('unused');
77
+ **Extra options:**
89
78
 
90
- // Only global CSS (injected via injectGlobal)
91
- tastyDebug.css('global');
92
-
93
- // ALL CSS on the page (including non-tasty stylesheets)
94
- tastyDebug.css('page');
95
-
96
- // CSS for a specific tasty class
97
- tastyDebug.css('t42');
98
-
99
- // CSS for multiple tasty classes
100
- tastyDebug.css(['t0', 't5', 't12']);
79
+ ```typescript
80
+ interface CssOptions extends DebugOptions {
81
+ prettify?: boolean; // Format output (default: true)
82
+ source?: boolean; // Read original CSS instead of live CSSOM (default: false, dev-mode only)
83
+ }
84
+ ```
101
85
 
102
- // CSS affecting a DOM element (by selector)
103
- tastyDebug.css('.my-button');
86
+ ```typescript
87
+ // Active CSS with stats
88
+ tastyDebug.css('active');
104
89
 
105
- // CSS affecting a DOM element (by reference)
106
- const el = document.querySelector('.my-button');
107
- tastyDebug.css(el);
90
+ // Specific class, silent
91
+ const css = tastyDebug.css('t42', { raw: true });
108
92
 
109
- // With options
110
- tastyDebug.css('active', { prettify: false, log: true });
93
+ // Compare original vs browser-parsed CSS (dev mode only)
94
+ tastyDebug.css('t42'); // live CSSOM
95
+ tastyDebug.css('t42', { source: true }); // original output
111
96
 
112
97
  // Shadow DOM
113
- const shadowRoot = host.shadowRoot;
114
98
  tastyDebug.css('all', { root: shadowRoot });
115
99
  ```
116
100
 
101
+ The `source` option reads from `RuleInfo.cssText`, which is only populated when `devMode` is active (development environment or `localStorage.TASTY_DEBUG = 'true'`). In production without debug mode, it falls back to the live CSSOM with a warning.
102
+
117
103
  ---
118
104
 
119
105
  ### `inspect(target, opts?): InspectResult`
@@ -123,309 +109,175 @@ Inspects a DOM element and returns detailed information about its tasty styles,
123
109
  ```typescript
124
110
  interface InspectResult {
125
111
  element?: Element | null;
126
- classes: string[]; // Tasty classes found on the element (e.g., ['t0', 't5'])
112
+ classes: string[]; // Tasty classes on the element
127
113
  chunks: ChunkInfo[]; // Chunk assignment per class
128
- css: string; // Prettified CSS affecting the element
114
+ css: string; // Prettified CSS
129
115
  size: number; // CSS size in characters
130
116
  rules: number; // Number of CSS rule blocks
131
117
  }
132
118
 
133
119
  interface ChunkInfo {
134
- className: string; // e.g., 't0'
120
+ className: string;
135
121
  chunkName: string | null; // e.g., 'appearance', 'font', 'dimension'
136
122
  }
137
123
  ```
138
124
 
139
125
  ```typescript
140
- // By CSS selector
141
- const result = tastyDebug.inspect('.my-card');
126
+ tastyDebug.inspect('.my-card');
127
+ // Logs: inspect div — 3 classes, 5 rules, 1.2KB
128
+ // Chunks: t3→appearance, t7→font, t12→dimension
129
+
130
+ // Silent
131
+ const result = tastyDebug.inspect('.my-card', { raw: true });
142
132
  console.log(result.classes); // ['t3', 't7', 't12']
143
- console.log(result.chunks); // [{className: 't3', chunkName: 'appearance'}, ...]
144
133
  console.log(result.rules); // 5
145
- console.log(result.css); // prettified CSS
146
-
147
- // By element reference
148
- const el = document.querySelector('[data-element="Title"]');
149
- tastyDebug.inspect(el);
150
-
151
- // Shadow DOM
152
- tastyDebug.inspect('.shadow-component', { root: shadowRoot });
153
134
  ```
154
135
 
155
136
  ---
156
137
 
157
- ### `cache(opts?): CacheStatus`
138
+ ### `summary(opts?): Summary`
158
139
 
159
- Returns the current state of the style cache: which classes are active, which are unused, and performance metrics.
140
+ One-shot overview of the entire Tasty CSS state. Logs a compact report.
160
141
 
161
142
  ```typescript
162
- interface CacheStatus {
163
- classes: {
164
- active: string[]; // Classes with refCount > 0 and present in DOM
165
- unused: string[]; // Classes with refCount = 0 but still in cache
166
- all: string[]; // Union of active and unused
167
- };
143
+ interface Summary {
144
+ activeClasses: string[];
145
+ unusedClasses: string[];
146
+ totalStyledClasses: string[];
147
+
148
+ activeCSSSize: number;
149
+ unusedCSSSize: number;
150
+ globalCSSSize: number;
151
+ rawCSSSize: number;
152
+ keyframesCSSSize: number;
153
+ propertyCSSSize: number;
154
+ totalCSSSize: number;
155
+
156
+ activeRuleCount: number;
157
+ unusedRuleCount: number;
158
+ globalRuleCount: number;
159
+ rawRuleCount: number;
160
+ keyframesRuleCount: number;
161
+ propertyRuleCount: number;
162
+ totalRuleCount: number;
163
+
168
164
  metrics: CacheMetrics | null;
165
+ definedProperties: string[];
166
+ definedKeyframes: { name: string; refCount: number }[];
167
+ chunkBreakdown: ChunkBreakdown;
169
168
  }
170
169
  ```
171
170
 
172
171
  ```typescript
173
- const status = tastyDebug.cache();
174
-
175
- console.log(status.classes.active.length); // 42
176
- console.log(status.classes.unused.length); // 8
177
- console.log(status.metrics?.hits); // 156
178
- ```
179
-
180
- ---
181
-
182
- ### `cleanup(opts?): void`
183
-
184
- Forces immediate cleanup of all unused styles (those with `refCount = 0`).
185
-
186
- ```typescript
187
- tastyDebug.cleanup();
188
-
189
- // Shadow DOM
190
- tastyDebug.cleanup({ root: shadowRoot });
172
+ // Logged automatically
173
+ tastyDebug.summary();
174
+ // Output:
175
+ // Active: 42 classes, 186 rules, 12.4KB
176
+ // Unused: 3 classes, 8 rules, 0.5KB
177
+ // Global: 12 rules, 1.1KB
178
+ // Total: 45 classes, 206 rules, 14.0KB
179
+ // Cache: 94.2% hit rate (312 lookups)
180
+
181
+ // Silent
182
+ const s = tastyDebug.summary({ raw: true });
183
+ console.log(s.totalRuleCount); // 206
191
184
  ```
192
185
 
193
186
  ---
194
187
 
195
- ### `metrics(opts?): CacheMetrics | null`
188
+ ### `chunks(opts?): ChunkBreakdown`
196
189
 
197
- Returns performance metrics for the style cache. Only available when `devMode` is enabled.
190
+ Breakdown of styles by chunk type.
198
191
 
199
192
  ```typescript
200
- interface CacheMetrics {
201
- hits: number; // Successful cache hits
202
- misses: number; // New styles injected (cache misses)
203
- bulkCleanups: number; // Number of bulk cleanup operations
204
- totalInsertions: number; // Lifetime style insertions
205
- totalUnused: number; // Total styles marked as unused
206
- stylesCleanedUp: number; // Total styles removed by cleanup
207
- startTime: number; // Metrics collection start timestamp
208
- unusedHits?: number; // Reactivations of cached unused styles
209
- cleanupHistory: {
210
- timestamp: number;
211
- classesDeleted: number;
193
+ interface ChunkBreakdown {
194
+ byChunk: Record<string, {
195
+ classes: string[];
212
196
  cssSize: number;
213
- rulesDeleted: number;
214
- }[];
197
+ ruleCount: number;
198
+ }>;
199
+ totalChunkTypes: number;
200
+ totalClasses: number;
215
201
  }
216
202
  ```
217
203
 
218
204
  ```typescript
219
- const m = tastyDebug.metrics();
220
-
221
- if (m) {
222
- const hitRate = ((m.hits + (m.unusedHits || 0)) / (m.hits + m.misses)) * 100;
223
- console.log(`Cache hit rate: ${hitRate.toFixed(1)}%`);
224
- console.log(`Total insertions: ${m.totalInsertions}`);
225
- console.log(`Bulk cleanups: ${m.bulkCleanups}`);
226
- }
227
- ```
228
-
229
- ### `resetMetrics(opts?): void`
230
-
231
- Resets all performance metrics counters.
232
-
233
- ```typescript
234
- tastyDebug.resetMetrics();
235
- ```
236
-
237
- ---
238
-
239
- ### `chunks(opts?): ChunkBreakdown`
240
-
241
- Returns a breakdown of styles by chunk type. With style chunking enabled, styles are split into logical chunks (appearance, font, dimension, etc.) for better caching and CSS reuse.
242
-
243
- ```typescript
244
- const breakdown = tastyDebug.chunks();
245
-
246
- console.log(breakdown.totalChunkTypes); // 6
247
- console.log(breakdown.totalClasses); // 87
248
-
249
- for (const [chunkName, data] of Object.entries(breakdown.byChunk)) {
250
- console.log(`${chunkName}: ${data.classes.length} classes, ${data.cssSize}B`);
251
- }
252
-
253
- // Log a formatted breakdown to the console
254
- tastyDebug.chunks({ log: true });
205
+ tastyDebug.chunks();
206
+ // Output:
207
+ // appearance: 24 cls, 48 rules, 3.2KB
208
+ // font: 18 cls, 18 rules, 1.1KB
209
+ // dimension: 31 cls, 45 rules, 2.4KB
255
210
  ```
256
211
 
257
- Chunk types: `combined` (non-chunked), `appearance`, `font`, `dimension`, `display`, `layout`, `position`, `misc`, `subcomponents`.
258
-
259
- ---
260
-
261
- ### `getGlobalTypeCSS(type, opts?): { css: string; ruleCount: number; size: number }`
262
-
263
- Retrieves CSS for a specific global injection type.
264
-
265
- ```typescript
266
- // CSS injected via injectGlobal()
267
- const global = tastyDebug.getGlobalTypeCSS('global');
268
-
269
- // CSS injected via injectRawCSS() / useRawCSS()
270
- const raw = tastyDebug.getGlobalTypeCSS('raw');
271
-
272
- // @keyframes CSS
273
- const keyframes = tastyDebug.getGlobalTypeCSS('keyframes');
274
-
275
- // @property CSS
276
- const properties = tastyDebug.getGlobalTypeCSS('property');
277
-
278
- console.log(`Global: ${global.ruleCount} rules, ${global.size}B`);
279
- console.log(`Raw: ${raw.ruleCount} rules, ${raw.size}B`);
280
- console.log(`Keyframes: ${keyframes.ruleCount} rules, ${keyframes.size}B`);
281
- console.log(`Properties: ${properties.ruleCount} rules, ${properties.size}B`);
282
- ```
212
+ Chunk types: `combined`, `appearance`, `font`, `dimension`, `display`, `layout`, `position`, `misc`, `subcomponents`.
283
213
 
284
214
  ---
285
215
 
286
- ### `defs(opts?): Definitions`
216
+ ### `cache(opts?): CacheStatus`
287
217
 
288
- Returns all defined `@property` and `@keyframes` entries.
218
+ Cache state and performance metrics.
289
219
 
290
220
  ```typescript
291
- interface Definitions {
292
- properties: string[]; // Defined via @property (e.g., ['--primary-color', '--gap'])
293
- keyframes: { name: string; refCount: number }[];
221
+ interface CacheStatus {
222
+ classes: {
223
+ active: string[];
224
+ unused: string[];
225
+ all: string[];
226
+ };
227
+ metrics: CacheMetrics | null;
294
228
  }
295
229
  ```
296
230
 
297
231
  ```typescript
298
- const defs = tastyDebug.defs();
299
-
300
- console.log('Properties:', defs.properties);
301
- // ['--primary-color', '--surface-color', ...]
302
-
303
- console.log('Keyframes:', defs.keyframes);
304
- // [{ name: 'fadeIn', refCount: 2 }, { name: 'pulse', refCount: 1 }]
232
+ tastyDebug.cache();
233
+ // Output:
234
+ // Active: 42, Unused: 3
235
+ // Hits: 294, Misses: 18, Rate: 94.2%
305
236
  ```
306
237
 
307
238
  ---
308
239
 
309
- ### `summary(opts?): Summary`
310
-
311
- One-shot comprehensive overview of the entire Tasty CSS state. Returns detailed statistics and optionally logs a formatted report.
312
-
313
- ```typescript
314
- interface SummaryOptions {
315
- root?: Document | ShadowRoot;
316
- log?: boolean;
317
- includePageCSS?:
318
- | false // Do not include page-level CSS stats (default)
319
- | true // Include sizes/counts only
320
- | 'all'; // Include stats and return full page CSS string
321
- }
322
- ```
323
-
324
- The returned `Summary` object contains:
240
+ ### `cleanup(opts?): void`
325
241
 
326
- - **Classes**: `activeClasses`, `unusedClasses`, `totalStyledClasses`
327
- - **CSS sizes**: `activeCSSSize`, `unusedCSSSize`, `globalCSSSize`, `rawCSSSize`, `keyframesCSSSize`, `propertyCSSSize`, `totalCSSSize`
328
- - **CSS payloads**: `activeCSS`, `unusedCSS`, `globalCSS`, `rawCSS`, `keyframesCSS`, `propertyCSS`, `allCSS`
329
- - **Rule counts**: `globalRuleCount`, `rawRuleCount`, `keyframesRuleCount`, `propertyRuleCount`
330
- - **Page CSS** (when `includePageCSS` is set): `page.cssSize`, `page.ruleCount`, `page.stylesheetCount`, `page.skippedStylesheets`
331
- - **Metrics & definitions**: `metrics`, `definedProperties`, `definedKeyframes`, `propertyCount`, `keyframeCount`
332
- - **Cleanup summary**: `cleanupSummary.totalCleanups`, `cleanupSummary.totalClassesDeleted`, `cleanupSummary.lastCleanup`, etc.
333
- - **Chunk breakdown**: `chunkBreakdown.byChunk`, `chunkBreakdown.totalChunkTypes`
242
+ Forces immediate cleanup of all unused styles (those with `refCount = 0`).
334
243
 
335
244
  ```typescript
336
- // Log a formatted report
337
- tastyDebug.summary({ log: true });
338
-
339
- // Get the data programmatically
340
- const s = tastyDebug.summary();
341
- console.log(`Active: ${s.activeClasses.length} classes, ${s.activeCSSSize}B`);
342
- console.log(`Unused: ${s.unusedClasses.length} classes, ${s.unusedCSSSize}B`);
343
- console.log(`Total CSS: ${s.totalCSSSize}B`);
344
-
345
- // Include page-level CSS stats
346
- const withPage = tastyDebug.summary({ includePageCSS: true });
347
- console.log(`Page CSS: ${withPage.page?.cssSize}B across ${withPage.page?.stylesheetCount} stylesheets`);
245
+ tastyDebug.cleanup();
246
+ tastyDebug.cleanup({ root: shadowRoot });
348
247
  ```
349
248
 
350
249
  ---
351
250
 
352
- ### `pageCSS(opts?): string`
353
-
354
- Returns all CSS on the page across all stylesheets (not only tasty-generated CSS).
355
-
356
- ```typescript
357
- // Get all page CSS
358
- const css = tastyDebug.pageCSS();
359
-
360
- // Log it
361
- tastyDebug.pageCSS({ log: true });
362
-
363
- // Raw (unformatted)
364
- tastyDebug.pageCSS({ prettify: false });
365
-
366
- // Exclude cross-origin stylesheet placeholders
367
- tastyDebug.pageCSS({ includeCrossOrigin: false });
368
- ```
369
-
370
- ### `pageStats(opts?): PageStats`
251
+ ### `help(): void`
371
252
 
372
- Returns size and rule count statistics for all page CSS without extracting the full text.
253
+ Prints a quick-start guide to the console.
373
254
 
374
255
  ```typescript
375
- const stats = tastyDebug.pageStats();
376
- console.log(`${stats.cssSize}B across ${stats.stylesheetCount} stylesheets`);
377
- console.log(`${stats.ruleCount} rules, ${stats.skippedStylesheets} skipped (CORS)`);
256
+ tastyDebug.help();
378
257
  ```
379
258
 
380
259
  ---
381
260
 
382
- ### `log(target, opts?): void`
383
-
384
- Logs CSS for a target to the console with formatted output, collapsible groups, and sub-element detection.
385
-
386
- ```typescript
387
- // Log active CSS with stats header
388
- tastyDebug.log('active');
389
-
390
- // Log CSS for a specific class
391
- tastyDebug.log('t42');
392
-
393
- // Log with custom title
394
- tastyDebug.log('active', { title: 'Button styles' });
395
-
396
- // Log CSS for an element
397
- tastyDebug.log('.my-card');
398
- ```
399
-
400
- The output includes:
401
- - Rule count, line count, and byte size
402
- - Sub-element breakdown (detects `[data-element="..."]` selectors)
403
- - Full CSS in a collapsible group
404
-
405
- ---
406
-
407
- ### `help(): void`
261
+ ### `install(): void`
408
262
 
409
- Prints a quick-start guide to the console with available commands and common targets.
263
+ Attaches `tastyDebug` to `window.tastyDebug`. Called automatically in development mode.
410
264
 
411
265
  ```typescript
412
- tastyDebug.help();
266
+ import { tastyDebug } from '@tenphi/tasty';
267
+ tastyDebug.install();
413
268
  ```
414
269
 
415
270
  ---
416
271
 
417
- ### `install(): void`
272
+ ## Shadow DOM Support
418
273
 
419
- Attaches `tastyDebug` to `window.tastyDebug` for console access. Called automatically in development mode.
274
+ All methods accept a `root` option to target a Shadow DOM:
420
275
 
421
276
  ```typescript
422
- import { tastyDebug } from '@tenphi/tasty';
423
-
424
- // Manual install (e.g., in staging/production for debugging)
425
- tastyDebug.install();
426
-
427
- // Then use from the browser console:
428
- // > tastyDebug.summary({ log: true })
277
+ const shadowRoot = host.shadowRoot;
278
+ tastyDebug.css('all', { root: shadowRoot });
279
+ tastyDebug.inspect('.shadow-component', { root: shadowRoot });
280
+ tastyDebug.summary({ root: shadowRoot });
429
281
  ```
430
282
 
431
283
  ---
@@ -435,71 +287,32 @@ tastyDebug.install();
435
287
  ### Debugging a component's styles
436
288
 
437
289
  ```typescript
438
- // 1. Find the element
290
+ // 1. Inspect the element
439
291
  tastyDebug.inspect('.my-button');
440
- // → { classes: ['t3', 't7'], chunks: [...], css: '...', rules: 4 }
441
292
 
442
293
  // 2. See CSS for a specific class
443
- tastyDebug.log('t3');
294
+ tastyDebug.css('t3');
444
295
 
445
- // 3. Check which chunk it belongs to
446
- tastyDebug.inspect('.my-button').chunks;
447
- // → [{ className: 't3', chunkName: 'appearance' }, { className: 't7', chunkName: 'font' }]
296
+ // 3. Compare original vs browser-parsed (dev mode)
297
+ tastyDebug.css('t3', { source: true });
448
298
  ```
449
299
 
450
300
  ### Checking cache efficiency
451
301
 
452
302
  ```typescript
453
- const m = tastyDebug.metrics();
454
- const hitRate = m ? ((m.hits + (m.unusedHits || 0)) / (m.hits + m.misses)) * 100 : 0;
455
- console.log(`Hit rate: ${hitRate.toFixed(1)}%`);
456
- console.log(`Unused style reactivations: ${m?.unusedHits}`);
303
+ const { metrics } = tastyDebug.cache({ raw: true });
304
+ if (metrics) {
305
+ const total = metrics.hits + metrics.misses;
306
+ const rate = total > 0 ? ((metrics.hits / total) * 100).toFixed(1) : 0;
307
+ console.log(`Cache hit rate: ${rate}%`);
308
+ }
457
309
  ```
458
310
 
459
311
  ### Monitoring CSS growth
460
312
 
461
313
  ```typescript
462
- const s = tastyDebug.summary();
463
- console.log(`Total tasty CSS: ${(s.totalCSSSize / 1024).toFixed(1)}KB`);
464
- console.log(`Active: ${(s.activeCSSSize / 1024).toFixed(1)}KB`);
465
- console.log(`Unused (pending cleanup): ${(s.unusedCSSSize / 1024).toFixed(1)}KB`);
466
-
467
- // Compare with total page CSS
468
- const page = tastyDebug.pageStats();
469
- const ratio = ((s.totalCSSSize / page.cssSize) * 100).toFixed(1);
470
- console.log(`Tasty is ${ratio}% of total page CSS`);
314
+ const s = tastyDebug.summary({ raw: true });
315
+ console.log(`Total: ${s.totalRuleCount} rules, ${(s.totalCSSSize / 1024).toFixed(1)}KB`);
316
+ console.log(`Active: ${s.activeRuleCount} rules`);
317
+ console.log(`Unused: ${s.unusedRuleCount} rules`);
471
318
  ```
472
-
473
- ### Analyzing chunk distribution
474
-
475
- ```typescript
476
- tastyDebug.chunks({ log: true });
477
- // → Formatted breakdown:
478
- // • appearance: 24 classes, 3.2KB, 48 rules
479
- // • font: 18 classes, 1.1KB, 18 rules
480
- // • dimension: 31 classes, 2.4KB, 45 rules
481
- // • ...
482
- ```
483
-
484
- ---
485
-
486
- ## Shadow DOM Support
487
-
488
- All methods accept a `root` option to target a Shadow DOM instead of the main document:
489
-
490
- ```typescript
491
- const shadowRoot = host.shadowRoot;
492
-
493
- tastyDebug.css('all', { root: shadowRoot });
494
- tastyDebug.inspect('.shadow-component', { root: shadowRoot });
495
- tastyDebug.summary({ root: shadowRoot, log: true });
496
- tastyDebug.chunks({ root: shadowRoot, log: true });
497
- ```
498
-
499
- ---
500
-
501
- ## Integration with Tasty
502
-
503
- `tastyDebug` reads directly from the [Style Injector](./injector.md)'s internal registries. It does not inject, modify, or intercept any styles. The `cleanup()` method is the only method with side effects — it triggers the injector's garbage collection for unused styles.
504
-
505
- For most development, you'll use the [Runtime API](./runtime.md) to create components and the debug utilities to inspect the resulting CSS at runtime.
package/docs/dsl.md CHANGED
@@ -228,7 +228,7 @@ const SimpleButton = tasty(Button, {
228
228
  | `@media` | Media queries | `@media(w < 768px)` |
229
229
  | `@(...)` | Container queries | `@(panel, w >= 300px)` |
230
230
  | `@supports` | Feature/selector support | `@supports(display: grid)` |
231
- | `@root` | Root element states | `@root(theme=dark)` |
231
+ | `@root` | Root element states | `@root(schema=dark)` |
232
232
  | `@parent` | Parent/ancestor element states | `@parent(hovered)` |
233
233
  | `@own` | Sub-element's own state | `@own(hovered)` |
234
234
  | `@starting` | Entry animation | `@starting` |
@@ -322,6 +322,8 @@ display: {
322
322
 
323
323
  Root states generate selectors on the `:root` element. They are useful for theme modes, feature flags, and other page-level conditions:
324
324
 
325
+ These docs use `data-schema` in examples. If your app standardizes on a different root attribute, keep the same pattern and swap the attribute name consistently in your aliases and selectors.
326
+
325
327
  ```jsx
326
328
  color: {
327
329
  '': '#text',