@tenphi/tasty 0.0.0-snapshot.002b1b3

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 (82) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +637 -0
  3. package/dist/async-storage-B7_o6FKt.js +44 -0
  4. package/dist/async-storage-B7_o6FKt.js.map +1 -0
  5. package/dist/collector-LuU1vZ68.d.ts +98 -0
  6. package/dist/collector-MOYY2SOr.js +230 -0
  7. package/dist/collector-MOYY2SOr.js.map +1 -0
  8. package/dist/config-A237aY9H.js +10235 -0
  9. package/dist/config-A237aY9H.js.map +1 -0
  10. package/dist/config-vuCRkBWX.d.ts +884 -0
  11. package/dist/context-CkSg-kDT.js +24 -0
  12. package/dist/context-CkSg-kDT.js.map +1 -0
  13. package/dist/core/index.d.ts +5 -0
  14. package/dist/core/index.js +6 -0
  15. package/dist/core-BkKav78f.js +1592 -0
  16. package/dist/core-BkKav78f.js.map +1 -0
  17. package/dist/css-writer-Cos9tQRM.js +329 -0
  18. package/dist/css-writer-Cos9tQRM.js.map +1 -0
  19. package/dist/format-global-rules-Dbc_1tc3.js +22 -0
  20. package/dist/format-global-rules-Dbc_1tc3.js.map +1 -0
  21. package/dist/format-rules-C2oiTsEO.js +143 -0
  22. package/dist/format-rules-C2oiTsEO.js.map +1 -0
  23. package/dist/hydrate-miFzWIKR.js +45 -0
  24. package/dist/hydrate-miFzWIKR.js.map +1 -0
  25. package/dist/index-CJMXAAO5.d.ts +1602 -0
  26. package/dist/index-dUtwpOux.d.ts +1266 -0
  27. package/dist/index.d.ts +5 -0
  28. package/dist/index.js +732 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/keyframes-DDtNo_hl.js +587 -0
  31. package/dist/keyframes-DDtNo_hl.js.map +1 -0
  32. package/dist/merge-styles-CtDJMhpJ.d.ts +7 -0
  33. package/dist/merge-styles-D_HbBOlq.js +144 -0
  34. package/dist/merge-styles-D_HbBOlq.js.map +1 -0
  35. package/dist/resolve-recipes-B7-823LL.js +144 -0
  36. package/dist/resolve-recipes-B7-823LL.js.map +1 -0
  37. package/dist/ssr/astro-client.d.ts +1 -0
  38. package/dist/ssr/astro-client.js +19 -0
  39. package/dist/ssr/astro-client.js.map +1 -0
  40. package/dist/ssr/astro-middleware.d.ts +15 -0
  41. package/dist/ssr/astro-middleware.js +19 -0
  42. package/dist/ssr/astro-middleware.js.map +1 -0
  43. package/dist/ssr/astro.d.ts +97 -0
  44. package/dist/ssr/astro.js +149 -0
  45. package/dist/ssr/astro.js.map +1 -0
  46. package/dist/ssr/index.d.ts +44 -0
  47. package/dist/ssr/index.js +10 -0
  48. package/dist/ssr/index.js.map +1 -0
  49. package/dist/ssr/next.d.ts +46 -0
  50. package/dist/ssr/next.js +75 -0
  51. package/dist/ssr/next.js.map +1 -0
  52. package/dist/static/index.d.ts +91 -0
  53. package/dist/static/index.js +50 -0
  54. package/dist/static/index.js.map +1 -0
  55. package/dist/static/inject.d.ts +5 -0
  56. package/dist/static/inject.js +17 -0
  57. package/dist/static/inject.js.map +1 -0
  58. package/dist/zero/babel.d.ts +81 -0
  59. package/dist/zero/babel.js +466 -0
  60. package/dist/zero/babel.js.map +1 -0
  61. package/dist/zero/index.d.ts +67 -0
  62. package/dist/zero/index.js +2 -0
  63. package/dist/zero/next.d.ts +86 -0
  64. package/dist/zero/next.js +143 -0
  65. package/dist/zero/next.js.map +1 -0
  66. package/docs/README.md +31 -0
  67. package/docs/adoption.md +298 -0
  68. package/docs/comparison.md +419 -0
  69. package/docs/configuration.md +394 -0
  70. package/docs/debug.md +320 -0
  71. package/docs/design-system.md +436 -0
  72. package/docs/dsl.md +688 -0
  73. package/docs/getting-started.md +217 -0
  74. package/docs/injector.md +544 -0
  75. package/docs/methodology.md +616 -0
  76. package/docs/pipeline.md +673 -0
  77. package/docs/react-api.md +557 -0
  78. package/docs/ssr.md +442 -0
  79. package/docs/styles.md +596 -0
  80. package/docs/tasty-static.md +532 -0
  81. package/package.json +222 -0
  82. package/tasty.config.ts +15 -0
@@ -0,0 +1,544 @@
1
+ # Tasty Style Injector
2
+
3
+ A high-performance CSS-in-JS solution that powers the Tasty design system with efficient style injection, automatic cleanup, and first-class SSR support.
4
+
5
+ ---
6
+
7
+ ## Overview
8
+
9
+ The Style Injector is the core engine behind Tasty's styling system, providing:
10
+
11
+ - **Hash-based deduplication** - Identical CSS gets the same className
12
+ - **Reference counting** - Automatic cleanup when components unmount (refCount = 0)
13
+ - **CSS nesting flattening** - Handles `&`, `.Class`, `SubElement` patterns
14
+ - **Keyframes injection** - First-class `@keyframes` support with immediate disposal
15
+ - **Smart cleanup** - CSS rules batched cleanup, keyframes disposed immediately
16
+ - **SSR support** - Deterministic class names and CSS extraction
17
+ - **Multiple roots** - Works with Document and ShadowRoot
18
+ - **Non-stacking cleanups** - Prevents timeout accumulation for better performance
19
+
20
+ > **Note:** This is internal infrastructure that powers Tasty components. Most developers will interact with the higher-level `tasty()` API instead.
21
+
22
+ ---
23
+
24
+ ## Architecture
25
+
26
+ ```
27
+ ┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
28
+ │ tasty() │────│ Style Injector │────│ Sheet Manager │
29
+ │ components │ │ │ │ │
30
+ └─────────────────┘ └──────────────────┘ └─────────────────┘
31
+ │ │ │
32
+ │ │ │
33
+ ▼ ▼ ▼
34
+ ┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
35
+ │ Style Results │ │ Keyframes Manager│ │ Root Registry │
36
+ │ (CSS rules) │ │ │ │ │
37
+ └─────────────────┘ └──────────────────┘ └─────────────────┘
38
+ │ │
39
+ │ │
40
+ ▼ ▼
41
+ ┌─────────────────┐ ┌─────────────────┐
42
+ │ Hash Cache │ │ <style> elements│
43
+ │ Deduplication │ │ CSSStyleSheet │
44
+ └─────────────────┘ └─────────────────┘
45
+ ```
46
+
47
+ ---
48
+
49
+ ## Core API
50
+
51
+ ### `inject(rules, options?): InjectResult`
52
+
53
+ Injects CSS rules and returns a className with dispose function.
54
+
55
+ ```typescript
56
+ import { inject } from '@tenphi/tasty';
57
+
58
+ // Component styling - generates tasty class names
59
+ const result = inject([{
60
+ selector: '.t-abc123',
61
+ declarations: 'color: red; padding: 10px;',
62
+ }]);
63
+
64
+ console.log(result.className); // 't-abc123'
65
+
66
+ // Cleanup when component unmounts (refCount decremented)
67
+ result.dispose();
68
+ ```
69
+
70
+ ### `injectGlobal(rules, options?): { dispose: () => void }`
71
+
72
+ Injects global styles that don't reserve tasty class names.
73
+
74
+ ```typescript
75
+ // Global styles - for body, resets, etc.
76
+ const globalResult = injectGlobal([
77
+ {
78
+ selector: 'body',
79
+ declarations: 'margin: 0; font-family: Arial;',
80
+ },
81
+ {
82
+ selector: '.header',
83
+ declarations: 'background: blue; color: white;',
84
+ atRules: ['@media (min-width: 768px)'],
85
+ }
86
+ ]);
87
+
88
+ // Only returns dispose function - no className needed for global styles
89
+ globalResult.dispose();
90
+ ```
91
+
92
+ ### `injectRawCSS(css, options?): { dispose: () => void }`
93
+
94
+ Injects raw CSS text directly without parsing. This is a low-overhead method for injecting CSS that doesn't need tasty processing.
95
+
96
+ ```typescript
97
+ import { injectRawCSS } from '@tenphi/tasty';
98
+
99
+ // Inject raw CSS
100
+ const { dispose } = injectRawCSS(`
101
+ body {
102
+ margin: 0;
103
+ padding: 0;
104
+ font-family: sans-serif;
105
+ }
106
+
107
+ .my-class {
108
+ color: red;
109
+ }
110
+ `);
111
+
112
+ // Later, remove the injected CSS
113
+ dispose();
114
+ ```
115
+
116
+ ### `useRawCSS(css, options?)` or `useRawCSS(factory, deps, options?)`
117
+
118
+ Inject raw CSS without parsing. Hook-free — works in client components, SSR, and React Server Components.
119
+
120
+ Supports two overloads:
121
+ - **Static CSS**: `useRawCSS(cssString, options?)` — content-based deduplication
122
+ - **Factory function**: `useRawCSS(() => cssString, deps, options?)` — factory called on every invocation, dedup handled internally
123
+
124
+ Use the `id` option for update tracking — when the CSS changes for the same id, the previous injection is replaced:
125
+
126
+ ```tsx
127
+ import { useRawCSS } from '@tenphi/tasty';
128
+
129
+ // Static CSS
130
+ function GlobalReset() {
131
+ useRawCSS(`
132
+ body { margin: 0; padding: 0; }
133
+ `);
134
+ return null;
135
+ }
136
+
137
+ // Dynamic CSS with factory function and update tracking
138
+ function ThemeStyles({ theme }: { theme: 'dark' | 'light' }) {
139
+ useRawCSS(() => `
140
+ body {
141
+ margin: 0;
142
+ background: ${theme === 'dark' ? '#000' : '#fff'};
143
+ color: ${theme === 'dark' ? '#fff' : '#000'};
144
+ }
145
+ `, [theme], { id: 'theme-body' });
146
+
147
+ return null;
148
+ }
149
+ ```
150
+
151
+ ### `createInjector(config?): StyleInjector`
152
+
153
+ Creates an isolated injector instance with custom configuration.
154
+
155
+ ```typescript
156
+ import { createInjector } from '@tenphi/tasty';
157
+
158
+ // Create isolated instance for testing
159
+ const testInjector = createInjector({
160
+ devMode: true,
161
+ forceTextInjection: true,
162
+ });
163
+
164
+ const result = testInjector.inject(rules);
165
+ ```
166
+
167
+ ### `keyframes(steps, nameOrOptions?): KeyframesResult`
168
+
169
+ Injects CSS keyframes with automatic deduplication.
170
+
171
+ ```typescript
172
+ // Generated name (k0, k1, k2...)
173
+ const fadeIn = keyframes({
174
+ from: { opacity: 0 },
175
+ to: { opacity: 1 },
176
+ });
177
+
178
+ // Custom name
179
+ const slideIn = keyframes({
180
+ '0%': { transform: 'translateX(-100%)' },
181
+ '100%': { transform: 'translateX(0)' },
182
+ }, 'slideInAnimation');
183
+
184
+ // Use in tasty styles (recommended)
185
+ const AnimatedBox = tasty({
186
+ styles: {
187
+ animation: `${fadeIn} 300ms ease-in`,
188
+ },
189
+ });
190
+
191
+ // Or use with injectGlobal for fixed selectors
192
+ injectGlobal([{
193
+ selector: '.my-animated-class',
194
+ declarations: `animation: ${slideIn} 500ms ease-out;`
195
+ }]);
196
+
197
+ // Cleanup keyframes (if needed)
198
+ fadeIn.dispose(); // Immediate keyframes deletion from DOM
199
+ slideIn.dispose(); // Immediate keyframes deletion from DOM
200
+ ```
201
+
202
+ ### `configure(config): void`
203
+
204
+ Configures the Tasty style system. `configure()` is optional, but if you use it, it must be called **before** any styles are generated (before first render).
205
+
206
+ ```typescript
207
+ import { configure } from '@tenphi/tasty';
208
+
209
+ configure({
210
+ devMode: true, // Enable development features (auto-detected)
211
+ maxRulesPerSheet: 8192, // Cap rules per stylesheet (default: 8192)
212
+ forceTextInjection: false, // Force textContent insertion (auto-detected for tests)
213
+ nonce: 'csp-nonce', // CSP nonce for security
214
+ gc: { // Garbage collection for unused styles
215
+ touchInterval: 1000, // Touch events between GC cycles (default: 1000)
216
+ capacity: 1000, // Max unused styles to retain (default: 1000)
217
+ },
218
+ states: { // Global predefined states for advanced state mapping
219
+ '@mobile': '@media(w < 768px)',
220
+ '@dark': '@root(schema=dark)',
221
+ },
222
+ });
223
+ ```
224
+
225
+ **Auto-Detection Features:**
226
+ - `devMode`: Automatically enabled in development environments (detected via `isDevEnv()`)
227
+ - `forceTextInjection`: Automatically enabled in test environments (Jest, Vitest, Mocha, happy-dom, jsdom)
228
+
229
+ **Configuration Notes:**
230
+ - Most options have sensible defaults and auto-detection
231
+ - `configure()` is optional - the injector works with defaults
232
+ - **Configuration is locked after styles are generated** - calling `configure()` after first render will emit a warning and be ignored
233
+ - `gc.touchInterval`: Number of touch events between GC cycles. Each style render counts as a touch. When the counter reaches this value, GC is scheduled via `requestIdleCallback`.
234
+ - `gc.capacity`: Maximum number of unused styles (refCount = 0, not in DOM) to retain. When exceeded, the oldest are evicted first. Actively referenced styles don't count against this limit.
235
+
236
+ ---
237
+
238
+ ## Advanced Features
239
+
240
+ ### Style Result Format
241
+
242
+ The injector works with `StyleResult` objects from the tasty parser:
243
+
244
+ ```typescript
245
+ interface StyleResult {
246
+ selector: string; // CSS selector
247
+ declarations: string; // CSS declarations
248
+ atRules?: string[]; // @media, @supports, etc.
249
+ nestingLevel?: number; // Nesting depth for specificity
250
+ }
251
+
252
+ // Example StyleResult
253
+ const styleRule: StyleResult = {
254
+ selector: '.t-button',
255
+ declarations: 'padding: 8px 16px; background: blue; color: white;',
256
+ atRules: ['@media (min-width: 768px)'],
257
+ nestingLevel: 0,
258
+ };
259
+ ```
260
+
261
+ ### Deduplication & Performance
262
+
263
+ ```typescript
264
+ // Identical CSS rules get the same className
265
+ const button1 = inject([{
266
+ selector: '.t-btn1',
267
+ declarations: 'padding: 8px; color: red;'
268
+ }]);
269
+
270
+ const button2 = inject([{
271
+ selector: '.t-btn2',
272
+ declarations: 'padding: 8px; color: red;' // Same declarations
273
+ }]);
274
+
275
+ // Both get the same className due to deduplication
276
+ console.log(button1.className === button2.className); // true
277
+ ```
278
+
279
+ ### Reference Counting
280
+
281
+ ```typescript
282
+ // Multiple components using the same styles
283
+ const comp1 = inject([commonStyle]);
284
+ const comp2 = inject([commonStyle]);
285
+ const comp3 = inject([commonStyle]);
286
+
287
+ // Style is kept alive while any component uses it
288
+ comp1.dispose(); // refCount: 3 → 2
289
+ comp2.dispose(); // refCount: 2 → 1
290
+ comp3.dispose(); // refCount: 1 → 0, eligible for bulk cleanup
291
+
292
+ // Rule exists but refCount = 0 means unused
293
+ // Next inject() with same styles will increment refCount and reuse immediately
294
+ ```
295
+
296
+ ### Garbage Collection
297
+
298
+ ```typescript
299
+ import { configure, gc } from '@tenphi/tasty';
300
+
301
+ // Keyframes: Disposed immediately when refCount = 0 (safer for global scope)
302
+ // CSS rules: Tracked by touch count and cleaned up via gc()
303
+
304
+ configure({
305
+ gc: {
306
+ touchInterval: 1000, // Schedule GC every 1000 touches
307
+ capacity: 1000, // Max unused styles to retain
308
+ },
309
+ });
310
+
311
+ // Manual GC (synchronous, returns number of swept styles):
312
+ gc();
313
+
314
+ // Force-remove ALL unused styles (e.g. on route change or test teardown):
315
+ gc({ force: true });
316
+
317
+ // GC is also triggered automatically by touch count during rendering.
318
+ // Every `touchInterval` touches, GC is scheduled via requestIdleCallback.
319
+
320
+ // Benefits:
321
+ // - Activity-proportional: busy apps trigger GC more often
322
+ // - DOM-safe: styles currently in the DOM are never evicted
323
+ // - Oldest-first: least recently used styles are evicted first
324
+ // - Keyframes: Immediate cleanup prevents global namespace pollution
325
+ // - Unused styles can be instantly reactivated (just increment refCount)
326
+ ```
327
+
328
+ ### Shadow DOM Support
329
+
330
+ ```typescript
331
+ // Works with Shadow DOM
332
+ const shadowRoot = document.createElement('div').attachShadow({ mode: 'open' });
333
+
334
+ const shadowStyles = inject([{
335
+ selector: '.shadow-component',
336
+ declarations: 'color: purple;'
337
+ }], { root: shadowRoot });
338
+
339
+ // Keyframes in Shadow DOM
340
+ const shadowAnimation = keyframes({
341
+ from: { opacity: 0 },
342
+ to: { opacity: 1 }
343
+ }, { root: shadowRoot, name: 'shadowFade' });
344
+ ```
345
+
346
+ ---
347
+
348
+ ## SSR & Testing
349
+
350
+ ### Server-Side Rendering
351
+
352
+ ```typescript
353
+ import { getCssText, getCssTextForNode } from '@tenphi/tasty';
354
+
355
+ // Extract all CSS for SSR
356
+ const cssText = getCssText();
357
+
358
+ // Extract CSS for specific DOM subtree (like jest-styled-components)
359
+ const container = render(<MyComponent />);
360
+ const componentCSS = getCssTextForNode(container);
361
+ ```
362
+
363
+ ### Test Environment Detection
364
+
365
+ ```typescript
366
+ // Automatically detected test environments:
367
+ // - NODE_ENV === 'test'
368
+ // - Jest globals (jest, describe, it, expect)
369
+ // - jsdom / HappyDOM user agent
370
+ // - Vitest globals (vitest)
371
+ // - Mocha globals (mocha)
372
+
373
+ import { configure, isTestEnvironment, resetConfig } from '@tenphi/tasty';
374
+
375
+ const isTest = isTestEnvironment();
376
+
377
+ // Reset config between tests to allow reconfiguration
378
+ beforeEach(() => {
379
+ resetConfig();
380
+ configure({
381
+ forceTextInjection: isTest, // More reliable in test environments
382
+ devMode: true, // Always enable dev features in tests
383
+ });
384
+ });
385
+ ```
386
+
387
+ ### Memory Management in Tests
388
+
389
+ ```typescript
390
+ // Clean up between tests
391
+ afterEach(() => {
392
+ cleanup(); // Force cleanup of unused styles
393
+ });
394
+
395
+ // Full cleanup after test suite
396
+ afterAll(() => {
397
+ destroy(); // Destroy all stylesheets and reset state
398
+ });
399
+ ```
400
+
401
+ ---
402
+
403
+ ## Development Features
404
+
405
+ ### Performance Metrics
406
+
407
+ When `devMode` is enabled, the injector tracks comprehensive metrics:
408
+
409
+ ```typescript
410
+ import { configure, injector } from '@tenphi/tasty';
411
+
412
+ configure({ devMode: true });
413
+
414
+ // Access metrics through the global injector
415
+ const metrics = injector.instance.getMetrics();
416
+
417
+ console.log({
418
+ cacheHits: metrics.hits, // Successful cache hits
419
+ cacheMisses: metrics.misses, // New styles injected
420
+ unusedHits: metrics.unusedHits, // Current unused styles (calculated on demand)
421
+ bulkCleanups: metrics.bulkCleanups, // Number of bulk cleanup operations
422
+ stylesCleanedUp: metrics.stylesCleanedUp, // Total styles removed in bulk cleanups
423
+ totalInsertions: metrics.totalInsertions, // Lifetime insertions
424
+ totalUnused: metrics.totalUnused, // Total styles marked as unused (refCount = 0)
425
+ startTime: metrics.startTime, // Metrics collection start timestamp
426
+ cleanupHistory: metrics.cleanupHistory, // Detailed cleanup operation history
427
+ });
428
+ ```
429
+
430
+ ### Debug Information
431
+
432
+ ```typescript
433
+ // Get detailed information about injected styles
434
+ const debugInfo = injector.instance.getDebugInfo();
435
+
436
+ console.log({
437
+ activeStyles: debugInfo.activeStyles, // Currently active styles
438
+ unusedStyles: debugInfo.unusedStyles, // Styles marked for cleanup
439
+ totalSheets: debugInfo.totalSheets, // Number of stylesheets
440
+ totalRules: debugInfo.totalRules, // Total CSS rules
441
+ });
442
+ ```
443
+
444
+ ### Cleanup History
445
+
446
+ ```typescript
447
+ // Track cleanup operations over time
448
+ const metrics = injector.instance.getMetrics();
449
+
450
+ metrics.cleanupHistory.forEach(cleanup => {
451
+ console.log({
452
+ timestamp: new Date(cleanup.timestamp),
453
+ classesDeleted: cleanup.classesDeleted,
454
+ rulesDeleted: cleanup.rulesDeleted,
455
+ cssSize: cleanup.cssSize, // Total CSS size removed (bytes)
456
+ });
457
+ });
458
+ ```
459
+
460
+ ---
461
+
462
+ ## Performance Optimizations
463
+
464
+ ### Best Practices
465
+
466
+ ```typescript
467
+ // ✅ Reuse styles - identical CSS gets deduplicated
468
+ const buttonBase = { padding: '8px 16px', borderRadius: '4px' };
469
+
470
+ // ✅ Avoid frequent disposal and re-injection
471
+ // Let the reference counting system handle cleanup
472
+
473
+ // ✅ Use bulk operations for global styles
474
+ injectGlobal([
475
+ { selector: 'body', declarations: 'margin: 0;' },
476
+ { selector: '*', declarations: 'box-sizing: border-box;' },
477
+ { selector: '.container', declarations: 'max-width: 1200px;' }
478
+ ]);
479
+
480
+ // ✅ Configure GC for your app (BEFORE first render!)
481
+ import { configure } from '@tenphi/tasty';
482
+
483
+ configure({
484
+ gc: {
485
+ touchInterval: 1000, // Schedule GC every 1000 style touches
486
+ capacity: 1000, // Max unused styles to retain
487
+ },
488
+ });
489
+ ```
490
+
491
+ ### Memory Management
492
+
493
+ ```typescript
494
+ // The injector automatically manages memory through:
495
+
496
+ // 1. Hash-based deduplication - same CSS = same className
497
+ // 2. Reference counting - styles stay alive while in use (refCount > 0)
498
+ // 3. Immediate keyframes cleanup - disposed instantly when refCount = 0
499
+ // 4. Touch-count GC - unused CSS rules are evicted oldest-first when over capacity
500
+ // 5. DOM safety guard - styles visible in the DOM are never evicted
501
+
502
+ // Manual cleanup is rarely needed but available:
503
+ cleanup(); // Force immediate cleanup of all unused CSS rules (refCount = 0)
504
+ destroy(); // Nuclear option: remove all stylesheets and reset
505
+ ```
506
+
507
+ ---
508
+
509
+ ## Integration with Tasty
510
+
511
+ The Style Injector is seamlessly integrated with the higher-level Tasty API:
512
+
513
+ ```jsx
514
+ // High-level tasty() API
515
+ const StyledButton = tasty({
516
+ styles: {
517
+ padding: '2x 4x',
518
+ fill: '#purple',
519
+ color: '#white',
520
+ }
521
+ });
522
+
523
+ // Internally uses the injector:
524
+ // 1. Styles are parsed into StyleResult objects
525
+ // 2. inject() is called with the parsed results
526
+ // 3. Component gets the returned className
527
+ // 4. dispose() is called when component unmounts
528
+ ```
529
+
530
+ For most development, you'll use the [React API](./react-api.md) rather than the injector directly. The injector provides the high-performance foundation that makes Tasty's declarative styling possible.
531
+
532
+ ---
533
+
534
+ ## When to Use Direct Injection
535
+
536
+ Direct injector usage is recommended for:
537
+
538
+ - **Custom CSS-in-JS libraries** built on top of Tasty
539
+ - **Global styles** that don't fit the component model
540
+ - **Third-party integration** where you need low-level CSS control
541
+ - **Performance-critical scenarios** where you need direct control
542
+ - **Testing utilities** that need to inject or extract CSS
543
+
544
+ For regular component styling, prefer the [`tasty()` API](./react-api.md) which provides a more developer-friendly interface.