@tenphi/tasty 1.2.0 → 1.4.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.
- package/dist/compute-styles.d.ts +31 -0
- package/dist/compute-styles.js +357 -0
- package/dist/compute-styles.js.map +1 -0
- package/dist/config.d.ts +19 -19
- package/dist/config.js +25 -26
- package/dist/config.js.map +1 -1
- package/dist/core/index.d.ts +5 -4
- package/dist/core/index.js +6 -5
- package/dist/hooks/useCounterStyle.js +3 -4
- package/dist/hooks/useCounterStyle.js.map +1 -1
- package/dist/hooks/useFontFace.js +3 -4
- package/dist/hooks/useFontFace.js.map +1 -1
- package/dist/hooks/useGlobalStyles.js +4 -5
- package/dist/hooks/useGlobalStyles.js.map +1 -1
- package/dist/hooks/useKeyframes.js +3 -4
- package/dist/hooks/useKeyframes.js.map +1 -1
- package/dist/hooks/useProperty.js +3 -4
- package/dist/hooks/useProperty.js.map +1 -1
- package/dist/hooks/useRawCSS.js +3 -4
- package/dist/hooks/useRawCSS.js.map +1 -1
- package/dist/hooks/useStyles.d.ts +4 -9
- package/dist/hooks/useStyles.js +6 -214
- package/dist/hooks/useStyles.js.map +1 -1
- package/dist/index.d.ts +6 -5
- package/dist/index.js +7 -6
- package/dist/injector/index.d.ts +23 -19
- package/dist/injector/index.js +29 -16
- package/dist/injector/index.js.map +1 -1
- package/dist/injector/injector.d.ts +32 -3
- package/dist/injector/injector.js +130 -7
- package/dist/injector/injector.js.map +1 -1
- package/dist/injector/sheet-manager.d.ts +9 -13
- package/dist/injector/sheet-manager.js +30 -66
- package/dist/injector/sheet-manager.js.map +1 -1
- package/dist/injector/types.d.ts +50 -19
- package/dist/ssr/collector.js +3 -10
- package/dist/ssr/collector.js.map +1 -1
- package/dist/ssr/index.d.ts +1 -2
- package/dist/ssr/index.js +1 -2
- package/dist/ssr/index.js.map +1 -1
- package/dist/ssr/next.d.ts +1 -3
- package/dist/ssr/next.js +8 -3
- package/dist/ssr/next.js.map +1 -1
- package/dist/tasty.d.ts +28 -13
- package/dist/tasty.js +72 -60
- package/dist/tasty.js.map +1 -1
- package/dist/utils/process-tokens.d.ts +1 -5
- package/dist/utils/process-tokens.js +1 -8
- package/dist/utils/process-tokens.js.map +1 -1
- package/docs/injector.md +33 -18
- package/docs/methodology.md +50 -1
- package/docs/runtime.md +90 -3
- package/docs/ssr.md +19 -49
- package/package.json +4 -4
- package/dist/hooks/resolve-ssr-collector.js +0 -14
- package/dist/hooks/resolve-ssr-collector.js.map +0 -1
- package/dist/ssr/context.d.ts +0 -8
- package/dist/ssr/context.js +0 -13
- package/dist/ssr/context.js.map +0 -1
|
@@ -12,10 +12,6 @@ import { Tokens } from "../types.js";
|
|
|
12
12
|
* @returns CSSProperties object or undefined if no tokens to process
|
|
13
13
|
*/
|
|
14
14
|
declare function processTokens(tokens: Tokens | undefined): CSSProperties | undefined;
|
|
15
|
-
/**
|
|
16
|
-
* Stringify tokens for memoization key.
|
|
17
|
-
*/
|
|
18
|
-
declare function stringifyTokens(tokens: Tokens | undefined): string;
|
|
19
15
|
//#endregion
|
|
20
|
-
export { processTokens
|
|
16
|
+
export { processTokens };
|
|
21
17
|
//# sourceMappingURL=process-tokens.d.ts.map
|
|
@@ -77,14 +77,7 @@ function processTokens(tokens) {
|
|
|
77
77
|
}
|
|
78
78
|
return result;
|
|
79
79
|
}
|
|
80
|
-
/**
|
|
81
|
-
* Stringify tokens for memoization key.
|
|
82
|
-
*/
|
|
83
|
-
function stringifyTokens(tokens) {
|
|
84
|
-
if (!tokens) return "";
|
|
85
|
-
return JSON.stringify(tokens);
|
|
86
|
-
}
|
|
87
80
|
//#endregion
|
|
88
|
-
export { processTokens
|
|
81
|
+
export { processTokens };
|
|
89
82
|
|
|
90
83
|
//# sourceMappingURL=process-tokens.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"process-tokens.js","names":[],"sources":["../../src/utils/process-tokens.ts"],"sourcesContent":["import type { Tokens, TokenValue } from '../types';\n\nimport type { CSSProperties } from './css-types';\n\nimport { getColorSpaceComponents, getColorSpaceSuffix } from './color-space';\nimport { normalizeColorTokenValue, parseStyle } from './styles';\n\nexport { hslToRgbValues } from './color-math';\n\nconst devMode = process.env.NODE_ENV !== 'production';\n\n/**\n * Extract color components in the configured color space.\n * Returns a CSS variable reference for token colors, or decomposed\n * components as a space-separated string.\n */\nfunction extractColorSpaceValue(\n colorValue: string,\n parsedOutput: string,\n): string {\n const suffix = getColorSpaceSuffix();\n\n // If the parsed output references a color variable, use the companion variant\n const varMatch = parsedOutput.match(/var\\(--([a-z0-9-]+)-color\\)/);\n if (varMatch) {\n return `var(--${varMatch[1]}-color-${suffix})`;\n }\n\n // Try the original color value first, then parsed output\n const components = getColorSpaceComponents(colorValue);\n if (components !== colorValue) return components;\n\n const componentsFromParsed = getColorSpaceComponents(parsedOutput);\n if (componentsFromParsed !== parsedOutput) return componentsFromParsed;\n\n // Fallback: return the parsed output\n return parsedOutput;\n}\n\n/**\n * Check if a value is a valid token value (string, number, or boolean - not object).\n * Returns false for `false` values (they mean \"skip this token\").\n */\nfunction isValidTokenValue(\n value: unknown,\n): value is Exclude<TokenValue, undefined | null | false> {\n if (value === undefined || value === null || value === false) {\n return false;\n }\n\n if (typeof value === 'object') {\n if (devMode) {\n console.warn(\n 'Tasty: Object values are not allowed in tokens prop. ' +\n 'Tokens do not support state-based styling. Use a primitive value instead.',\n );\n }\n return false;\n }\n\n return (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n );\n}\n\n/**\n * Process a single token value through the tasty parser.\n * Numbers are converted to strings; 0 stays as \"0\".\n */\nfunction processTokenValue(value: string | number): string {\n if (typeof value === 'number') {\n // 0 should remain as \"0\", not converted to any unit\n if (value === 0) {\n return '0';\n }\n return parseStyle(String(value)).output;\n }\n return parseStyle(value).output;\n}\n\n/**\n * Process tokens object into inline style properties.\n * - $name -> --name with parsed value\n * - #name -> --name-color AND --name-color-{colorSpace} with parsed values\n *\n * @param tokens - The tokens object to process\n * @returns CSSProperties object or undefined if no tokens to process\n */\nexport function processTokens(\n tokens: Tokens | undefined,\n): CSSProperties | undefined {\n if (!tokens) {\n return undefined;\n }\n\n const keys = Object.keys(tokens);\n if (keys.length === 0) {\n return undefined;\n }\n\n let result: Record<string, string> | undefined;\n\n for (const key of keys) {\n const value = tokens[key as keyof Tokens];\n\n // Skip undefined/null values\n if (!isValidTokenValue(value)) {\n continue;\n }\n\n if (key.startsWith('$')) {\n // Custom property token: $name -> --name\n const propName = `--${key.slice(1)}`;\n // Boolean true for custom properties converts to empty string (valid CSS value)\n const effectiveValue = value === true ? '' : value;\n const processedValue = processTokenValue(effectiveValue);\n\n if (!result) result = {};\n result[propName] = processedValue;\n } else if (key.startsWith('#')) {\n const colorName = key.slice(1);\n const suffix = getColorSpaceSuffix();\n\n // Normalize color token value (true → 'transparent', false is already filtered by isValidTokenValue)\n const effectiveValue = normalizeColorTokenValue(value);\n // Skip if normalized to null (shouldn't happen since false is filtered by isValidTokenValue)\n if (effectiveValue === null) continue;\n\n const originalValue =\n typeof effectiveValue === 'number'\n ? String(effectiveValue)\n : effectiveValue;\n const lowerValue = originalValue.toLowerCase();\n const processedValue = processTokenValue(effectiveValue);\n\n if (!result) result = {};\n result[`--${colorName}-color`] = processedValue;\n\n // Skip component generation for #current values (currentcolor is dynamic, cannot decompose)\n if (/^#current(?:\\.|$)/i.test(lowerValue)) {\n continue;\n }\n\n result[`--${colorName}-color-${suffix}`] = extractColorSpaceValue(\n originalValue,\n processedValue,\n );\n }\n }\n\n return result as CSSProperties | undefined;\n}\n
|
|
1
|
+
{"version":3,"file":"process-tokens.js","names":[],"sources":["../../src/utils/process-tokens.ts"],"sourcesContent":["import type { Tokens, TokenValue } from '../types';\n\nimport type { CSSProperties } from './css-types';\n\nimport { getColorSpaceComponents, getColorSpaceSuffix } from './color-space';\nimport { normalizeColorTokenValue, parseStyle } from './styles';\n\nexport { hslToRgbValues } from './color-math';\n\nconst devMode = process.env.NODE_ENV !== 'production';\n\n/**\n * Extract color components in the configured color space.\n * Returns a CSS variable reference for token colors, or decomposed\n * components as a space-separated string.\n */\nfunction extractColorSpaceValue(\n colorValue: string,\n parsedOutput: string,\n): string {\n const suffix = getColorSpaceSuffix();\n\n // If the parsed output references a color variable, use the companion variant\n const varMatch = parsedOutput.match(/var\\(--([a-z0-9-]+)-color\\)/);\n if (varMatch) {\n return `var(--${varMatch[1]}-color-${suffix})`;\n }\n\n // Try the original color value first, then parsed output\n const components = getColorSpaceComponents(colorValue);\n if (components !== colorValue) return components;\n\n const componentsFromParsed = getColorSpaceComponents(parsedOutput);\n if (componentsFromParsed !== parsedOutput) return componentsFromParsed;\n\n // Fallback: return the parsed output\n return parsedOutput;\n}\n\n/**\n * Check if a value is a valid token value (string, number, or boolean - not object).\n * Returns false for `false` values (they mean \"skip this token\").\n */\nfunction isValidTokenValue(\n value: unknown,\n): value is Exclude<TokenValue, undefined | null | false> {\n if (value === undefined || value === null || value === false) {\n return false;\n }\n\n if (typeof value === 'object') {\n if (devMode) {\n console.warn(\n 'Tasty: Object values are not allowed in tokens prop. ' +\n 'Tokens do not support state-based styling. Use a primitive value instead.',\n );\n }\n return false;\n }\n\n return (\n typeof value === 'string' ||\n typeof value === 'number' ||\n typeof value === 'boolean'\n );\n}\n\n/**\n * Process a single token value through the tasty parser.\n * Numbers are converted to strings; 0 stays as \"0\".\n */\nfunction processTokenValue(value: string | number): string {\n if (typeof value === 'number') {\n // 0 should remain as \"0\", not converted to any unit\n if (value === 0) {\n return '0';\n }\n return parseStyle(String(value)).output;\n }\n return parseStyle(value).output;\n}\n\n/**\n * Process tokens object into inline style properties.\n * - $name -> --name with parsed value\n * - #name -> --name-color AND --name-color-{colorSpace} with parsed values\n *\n * @param tokens - The tokens object to process\n * @returns CSSProperties object or undefined if no tokens to process\n */\nexport function processTokens(\n tokens: Tokens | undefined,\n): CSSProperties | undefined {\n if (!tokens) {\n return undefined;\n }\n\n const keys = Object.keys(tokens);\n if (keys.length === 0) {\n return undefined;\n }\n\n let result: Record<string, string> | undefined;\n\n for (const key of keys) {\n const value = tokens[key as keyof Tokens];\n\n // Skip undefined/null values\n if (!isValidTokenValue(value)) {\n continue;\n }\n\n if (key.startsWith('$')) {\n // Custom property token: $name -> --name\n const propName = `--${key.slice(1)}`;\n // Boolean true for custom properties converts to empty string (valid CSS value)\n const effectiveValue = value === true ? '' : value;\n const processedValue = processTokenValue(effectiveValue);\n\n if (!result) result = {};\n result[propName] = processedValue;\n } else if (key.startsWith('#')) {\n const colorName = key.slice(1);\n const suffix = getColorSpaceSuffix();\n\n // Normalize color token value (true → 'transparent', false is already filtered by isValidTokenValue)\n const effectiveValue = normalizeColorTokenValue(value);\n // Skip if normalized to null (shouldn't happen since false is filtered by isValidTokenValue)\n if (effectiveValue === null) continue;\n\n const originalValue =\n typeof effectiveValue === 'number'\n ? String(effectiveValue)\n : effectiveValue;\n const lowerValue = originalValue.toLowerCase();\n const processedValue = processTokenValue(effectiveValue);\n\n if (!result) result = {};\n result[`--${colorName}-color`] = processedValue;\n\n // Skip component generation for #current values (currentcolor is dynamic, cannot decompose)\n if (/^#current(?:\\.|$)/i.test(lowerValue)) {\n continue;\n }\n\n result[`--${colorName}-color-${suffix}`] = extractColorSpaceValue(\n originalValue,\n processedValue,\n );\n }\n }\n\n return result as CSSProperties | undefined;\n}\n"],"mappings":";;;;;;;;;AAgBA,SAAS,uBACP,YACA,cACQ;CACR,MAAM,SAAS,qBAAqB;CAGpC,MAAM,WAAW,aAAa,MAAM,8BAA8B;AAClE,KAAI,SACF,QAAO,SAAS,SAAS,GAAG,SAAS,OAAO;CAI9C,MAAM,aAAa,wBAAwB,WAAW;AACtD,KAAI,eAAe,WAAY,QAAO;CAEtC,MAAM,uBAAuB,wBAAwB,aAAa;AAClE,KAAI,yBAAyB,aAAc,QAAO;AAGlD,QAAO;;;;;;AAOT,SAAS,kBACP,OACwD;AACxD,KAAI,UAAU,KAAA,KAAa,UAAU,QAAQ,UAAU,MACrD,QAAO;AAGT,KAAI,OAAO,UAAU,UAAU;AAE3B,UAAQ,KACN,iIAED;AAEH,SAAO;;AAGT,QACE,OAAO,UAAU,YACjB,OAAO,UAAU,YACjB,OAAO,UAAU;;;;;;AAQrB,SAAS,kBAAkB,OAAgC;AACzD,KAAI,OAAO,UAAU,UAAU;AAE7B,MAAI,UAAU,EACZ,QAAO;AAET,SAAO,WAAW,OAAO,MAAM,CAAC,CAAC;;AAEnC,QAAO,WAAW,MAAM,CAAC;;;;;;;;;;AAW3B,SAAgB,cACd,QAC2B;AAC3B,KAAI,CAAC,OACH;CAGF,MAAM,OAAO,OAAO,KAAK,OAAO;AAChC,KAAI,KAAK,WAAW,EAClB;CAGF,IAAI;AAEJ,MAAK,MAAM,OAAO,MAAM;EACtB,MAAM,QAAQ,OAAO;AAGrB,MAAI,CAAC,kBAAkB,MAAM,CAC3B;AAGF,MAAI,IAAI,WAAW,IAAI,EAAE;GAEvB,MAAM,WAAW,KAAK,IAAI,MAAM,EAAE;GAGlC,MAAM,iBAAiB,kBADA,UAAU,OAAO,KAAK,MACW;AAExD,OAAI,CAAC,OAAQ,UAAS,EAAE;AACxB,UAAO,YAAY;aACV,IAAI,WAAW,IAAI,EAAE;GAC9B,MAAM,YAAY,IAAI,MAAM,EAAE;GAC9B,MAAM,SAAS,qBAAqB;GAGpC,MAAM,iBAAiB,yBAAyB,MAAM;AAEtD,OAAI,mBAAmB,KAAM;GAE7B,MAAM,gBACJ,OAAO,mBAAmB,WACtB,OAAO,eAAe,GACtB;GACN,MAAM,aAAa,cAAc,aAAa;GAC9C,MAAM,iBAAiB,kBAAkB,eAAe;AAExD,OAAI,CAAC,OAAQ,UAAS,EAAE;AACxB,UAAO,KAAK,UAAU,WAAW;AAGjC,OAAI,qBAAqB,KAAK,WAAW,CACvC;AAGF,UAAO,KAAK,UAAU,SAAS,YAAY,uBACzC,eACA,eACD;;;AAIL,QAAO"}
|
package/docs/injector.md
CHANGED
|
@@ -207,13 +207,15 @@ import { configure } from '@tenphi/tasty';
|
|
|
207
207
|
configure({
|
|
208
208
|
devMode: true, // Enable development features (auto-detected)
|
|
209
209
|
maxRulesPerSheet: 8192, // Cap rules per stylesheet (default: 8192)
|
|
210
|
-
unusedStylesThreshold: 500, // Trigger cleanup threshold (CSS rules only)
|
|
211
|
-
bulkCleanupDelay: 5000, // Cleanup delay (ms) - ignored if idleCleanup is true
|
|
212
|
-
idleCleanup: true, // Use requestIdleCallback for cleanup
|
|
213
|
-
bulkCleanupBatchRatio: 0.5, // Clean up oldest 50% per batch
|
|
214
|
-
unusedStylesMinAgeMs: 10000, // Minimum age before cleanup (ms)
|
|
215
210
|
forceTextInjection: false, // Force textContent insertion (auto-detected for tests)
|
|
216
211
|
nonce: 'csp-nonce', // CSP nonce for security
|
|
212
|
+
gc: { // Garbage collection for unused styles
|
|
213
|
+
auto: true, // Enable automatic background sweep
|
|
214
|
+
baseMaxAge: 60000, // Base TTL (ms) for single-use styles
|
|
215
|
+
cooldown: 30000, // Minimum time between GC runs
|
|
216
|
+
autoInterval: 300000, // Background sweep interval (ms)
|
|
217
|
+
cacheCapacity: 5000, // Hard cap on cached styles (optional)
|
|
218
|
+
},
|
|
217
219
|
states: { // Global predefined states for advanced state mapping
|
|
218
220
|
'@mobile': '@media(w < 768px)',
|
|
219
221
|
'@dark': '@root(schema=dark)',
|
|
@@ -229,7 +231,9 @@ configure({
|
|
|
229
231
|
- Most options have sensible defaults and auto-detection
|
|
230
232
|
- `configure()` is optional - the injector works with defaults
|
|
231
233
|
- **Configuration is locked after styles are generated** - calling `configure()` after first render will emit a warning and be ignored
|
|
232
|
-
- `
|
|
234
|
+
- `gc.baseMaxAge`: Base TTL for a style rendered only once. Popular styles get longer TTLs via logarithmic scaling (`baseMaxAge * log2(hitCount + 1)`).
|
|
235
|
+
- `gc.auto`: When true, runs a periodic background sweep at `gc.autoInterval` intervals using `requestIdleCallback`.
|
|
236
|
+
- `gc.cooldown`: Minimum time between GC runs to avoid thrashing.
|
|
233
237
|
|
|
234
238
|
---
|
|
235
239
|
|
|
@@ -291,21 +295,31 @@ comp3.dispose(); // refCount: 1 → 0, eligible for bulk cleanup
|
|
|
291
295
|
// Next inject() with same styles will increment refCount and reuse immediately
|
|
292
296
|
```
|
|
293
297
|
|
|
294
|
-
###
|
|
298
|
+
### Garbage Collection
|
|
295
299
|
|
|
296
300
|
```typescript
|
|
297
|
-
import { configure } from '@tenphi/tasty';
|
|
301
|
+
import { configure, gc, maybeGC } from '@tenphi/tasty';
|
|
298
302
|
|
|
299
|
-
// CSS rules: Not immediately deleted, marked for bulk cleanup (refCount = 0)
|
|
300
303
|
// Keyframes: Disposed immediately when refCount = 0 (safer for global scope)
|
|
304
|
+
// CSS rules: Tracked by popularity and cleaned up via gc()
|
|
301
305
|
|
|
302
306
|
configure({
|
|
303
|
-
|
|
304
|
-
|
|
307
|
+
gc: {
|
|
308
|
+
auto: true, // Enable background sweep
|
|
309
|
+
baseMaxAge: 60000, // 1-minute base TTL
|
|
310
|
+
cooldown: 30000, // 30s between runs
|
|
311
|
+
},
|
|
305
312
|
});
|
|
306
313
|
|
|
314
|
+
// Manual GC (synchronous, returns number of swept styles):
|
|
315
|
+
gc();
|
|
316
|
+
|
|
317
|
+
// Event-driven GC with cooldown (e.g. on route change):
|
|
318
|
+
maybeGC();
|
|
319
|
+
|
|
307
320
|
// Benefits:
|
|
308
|
-
// -
|
|
321
|
+
// - Popularity-aware: frequently used styles survive longer
|
|
322
|
+
// - DOM-safe: styles currently in the DOM are never evicted
|
|
309
323
|
// - Keyframes: Immediate cleanup prevents global namespace pollution
|
|
310
324
|
// - Unused styles can be instantly reactivated (just increment refCount)
|
|
311
325
|
```
|
|
@@ -462,13 +476,14 @@ injectGlobal([
|
|
|
462
476
|
{ selector: '.container', declarations: 'max-width: 1200px;' }
|
|
463
477
|
]);
|
|
464
478
|
|
|
465
|
-
// ✅ Configure
|
|
479
|
+
// ✅ Configure GC for your app (BEFORE first render!)
|
|
466
480
|
import { configure } from '@tenphi/tasty';
|
|
467
481
|
|
|
468
482
|
configure({
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
483
|
+
gc: {
|
|
484
|
+
auto: true, // Enable background sweep for long-lived pages
|
|
485
|
+
baseMaxAge: 60000, // Default base TTL (adjust based on app size)
|
|
486
|
+
},
|
|
472
487
|
});
|
|
473
488
|
```
|
|
474
489
|
|
|
@@ -480,8 +495,8 @@ configure({
|
|
|
480
495
|
// 1. Hash-based deduplication - same CSS = same className
|
|
481
496
|
// 2. Reference counting - styles stay alive while in use (refCount > 0)
|
|
482
497
|
// 3. Immediate keyframes cleanup - disposed instantly when refCount = 0
|
|
483
|
-
// 4.
|
|
484
|
-
// 5.
|
|
498
|
+
// 4. Popularity-aware GC - unused CSS rules are scored by hitCount and age
|
|
499
|
+
// 5. DOM safety guard - styles visible in the DOM are never evicted
|
|
485
500
|
|
|
486
501
|
// Manual cleanup is rarely needed but available:
|
|
487
502
|
cleanup(); // Force immediate cleanup of all unused CSS rules (refCount = 0)
|
package/docs/methodology.md
CHANGED
|
@@ -256,6 +256,54 @@ The `tokens` prop sets `style="--progress: 75%"` on the DOM element. The `$progr
|
|
|
256
256
|
|
|
257
257
|
Design tokens (via `configure({ tokens })`) are injected as CSS custom properties on `:root`. Replace tokens (via `configure({ replaceTokens })`) are resolved at parse time and baked into the generated CSS. The `tokens` prop on components is resolved at render time via inline CSS custom properties. Use design tokens for design-system constants, replace tokens for value aliases, and the `tokens` prop for truly dynamic per-instance values.
|
|
258
258
|
|
|
259
|
+
### tokenProps
|
|
260
|
+
|
|
261
|
+
`tokenProps` expose token keys as top-level component props — the token equivalent of `styleProps` and `modProps`. Use them when a component has a fixed set of known dynamic token values.
|
|
262
|
+
|
|
263
|
+
#### Array form
|
|
264
|
+
|
|
265
|
+
Prop names are plain camelCase identifiers. Names ending in `Color` map to `#` color tokens; everything else maps to `$` custom property tokens:
|
|
266
|
+
|
|
267
|
+
```tsx
|
|
268
|
+
const ProgressBar = tasty({
|
|
269
|
+
tokenProps: ['progress', 'accentColor'] as const,
|
|
270
|
+
styles: { width: '$progress', fill: '#accent' },
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
// Clean prop API — no tokens object needed
|
|
274
|
+
<ProgressBar progress="75%" accentColor="#purple" />
|
|
275
|
+
|
|
276
|
+
// Conversion:
|
|
277
|
+
// 'progress' → $progress → --progress
|
|
278
|
+
// 'accentColor' → #accent → --accent-color + --accent-color-oklch
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
#### Object form
|
|
282
|
+
|
|
283
|
+
Keys are prop names; values are `$`/`#`-prefixed token keys. No suffix convention needed — the prefix in the value is explicit:
|
|
284
|
+
|
|
285
|
+
```tsx
|
|
286
|
+
const Card = tasty({
|
|
287
|
+
tokenProps: {
|
|
288
|
+
size: '$card-size',
|
|
289
|
+
color: '#card-accent',
|
|
290
|
+
},
|
|
291
|
+
styles: { padding: '$card-size', fill: '#card-accent' },
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
<Card size="4x" color="#purple" />
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
#### Merge order
|
|
298
|
+
|
|
299
|
+
When all three token sources are present, values merge with increasing priority:
|
|
300
|
+
|
|
301
|
+
1. `tokens` option in `tasty({...})` — default tokens (lowest)
|
|
302
|
+
2. `tokens` prop on the component instance — runtime overrides
|
|
303
|
+
3. `tokenProps`-derived values — highest priority (explicit named props win)
|
|
304
|
+
|
|
305
|
+
The `tokens` prop remains available for ad-hoc or dynamic tokens alongside `tokenProps`.
|
|
306
|
+
|
|
259
307
|
---
|
|
260
308
|
|
|
261
309
|
## styles prop vs style prop
|
|
@@ -458,7 +506,8 @@ See [Configuration](configuration.md) for the full `configure()` API.
|
|
|
458
506
|
- **Use `elements` prop** to declare typed sub-components for compound components
|
|
459
507
|
- **Use `styleProps`** to define what product engineers can customize
|
|
460
508
|
- **Use `modProps`** to expose known modifier states as clean component props
|
|
461
|
-
- **Use `
|
|
509
|
+
- **Use `tokenProps`** to expose known token keys as clean component props
|
|
510
|
+
- **Use `tokens` prop** for ad-hoc or dynamic per-instance token values (progress, user color)
|
|
462
511
|
- **Use modifiers** (`mods` or `modProps`) for state-driven style changes instead of runtime `styles` prop changes
|
|
463
512
|
|
|
464
513
|
### Avoid
|
package/docs/runtime.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Runtime API
|
|
2
2
|
|
|
3
|
-
The React-specific `tasty()` component factory, component props, and hooks. For the shared style language (state maps, tokens, units, extending semantics), see [Style DSL](dsl.md). For global configuration, see [Configuration](configuration.md). For the broader docs map, see the [Docs Hub](README.md).
|
|
3
|
+
The React-specific `tasty()` component factory, component props, and hooks. `tasty()` components are hook-free and compatible with React Server Components — no `'use client'` directive needed. For the shared style language (state maps, tokens, units, extending semantics), see [Style DSL](dsl.md). For global configuration, see [Configuration](configuration.md). For the broader docs map, see the [Docs Hub](README.md).
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -154,6 +154,75 @@ For architecture guidance on when to use modifiers vs `styleProps`, see [Methodo
|
|
|
154
154
|
|
|
155
155
|
---
|
|
156
156
|
|
|
157
|
+
## Token Props
|
|
158
|
+
|
|
159
|
+
Use `tokenProps` to expose token keys as direct component props instead of requiring the `tokens` object:
|
|
160
|
+
|
|
161
|
+
```jsx
|
|
162
|
+
// Before: tokens object
|
|
163
|
+
<ProgressBar tokens={{ $progress: '75%', '#accent': '#purple' }} />
|
|
164
|
+
|
|
165
|
+
// After: token props
|
|
166
|
+
<ProgressBar progress="75%" accentColor="#purple" />
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Array form
|
|
170
|
+
|
|
171
|
+
List prop names. Names ending in `Color` map to `#` color tokens; everything else maps to `$` custom property tokens:
|
|
172
|
+
|
|
173
|
+
```jsx
|
|
174
|
+
const ProgressBar = tasty({
|
|
175
|
+
tokenProps: ['progress', 'accentColor'] as const,
|
|
176
|
+
styles: { width: '$progress', fill: '#accent' },
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
<ProgressBar progress="75%" accentColor="#purple" />
|
|
180
|
+
// 'progress' → $progress → --progress
|
|
181
|
+
// 'accentColor' → #accent → --accent-color + --accent-color-oklch
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Object form
|
|
185
|
+
|
|
186
|
+
Map prop names to explicit `$`/`#`-prefixed token keys:
|
|
187
|
+
|
|
188
|
+
```tsx
|
|
189
|
+
const Card = tasty({
|
|
190
|
+
tokenProps: {
|
|
191
|
+
size: '$card-size',
|
|
192
|
+
color: '#card-accent',
|
|
193
|
+
},
|
|
194
|
+
styles: { padding: '$card-size', fill: '#card-accent' },
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
<Card size="4x" color="#purple" />
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Merge with `tokens`
|
|
201
|
+
|
|
202
|
+
Token props and the `tokens` prop can be used together. Token props take precedence over `tokens`, which takes precedence over default `tokens` in `tasty({...})`:
|
|
203
|
+
|
|
204
|
+
```jsx
|
|
205
|
+
const Bar = tasty({
|
|
206
|
+
tokenProps: ['progress'] as const,
|
|
207
|
+
tokens: { $progress: '0%' }, // default
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
<Bar tokens={{ $progress: '50%' }} progress="90%" />
|
|
211
|
+
// progress="90%" wins (from token prop)
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### When to use `tokenProps` vs `tokens`
|
|
215
|
+
|
|
216
|
+
| Use case | Recommendation |
|
|
217
|
+
|---|---|
|
|
218
|
+
| Component has a fixed set of known token keys | `tokenProps` — cleaner API, better TypeScript autocomplete |
|
|
219
|
+
| Component needs arbitrary/dynamic token values | `tokens` — open-ended `Record<string, TokenValue>` |
|
|
220
|
+
| Both fixed and dynamic | Combine: `tokenProps` for known keys, `tokens` for ad-hoc |
|
|
221
|
+
|
|
222
|
+
For architecture guidance, see [Methodology — tokenProps](methodology.md#tokenprops).
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
157
226
|
## Variants
|
|
158
227
|
|
|
159
228
|
Define named style variations. Only CSS for variants actually used at runtime is injected:
|
|
@@ -264,11 +333,29 @@ For the mental model behind sub-elements — how they share root state context a
|
|
|
264
333
|
|
|
265
334
|
---
|
|
266
335
|
|
|
336
|
+
## computeStyles
|
|
337
|
+
|
|
338
|
+
Hook-free, synchronous style computation. Can be used anywhere — including React Server Components, plain functions, and non-React code:
|
|
339
|
+
|
|
340
|
+
```tsx
|
|
341
|
+
import { computeStyles } from '@tenphi/tasty';
|
|
342
|
+
|
|
343
|
+
const { className } = computeStyles({
|
|
344
|
+
padding: '2x',
|
|
345
|
+
fill: '#surface',
|
|
346
|
+
radius: '1r',
|
|
347
|
+
});
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
On the client, CSS is injected synchronously into the DOM (idempotent via the injector cache). On the server, CSS is collected via the SSR collector if one is available. This is the same function that `tasty()` components use internally.
|
|
351
|
+
|
|
352
|
+
---
|
|
353
|
+
|
|
267
354
|
## Hooks
|
|
268
355
|
|
|
269
356
|
### useStyles
|
|
270
357
|
|
|
271
|
-
Generate a className from a style object:
|
|
358
|
+
Generate a className from a style object. Thin wrapper around `computeStyles()` that adds React context-based SSR collector discovery for backward compatibility:
|
|
272
359
|
|
|
273
360
|
```tsx
|
|
274
361
|
import { useStyles } from '@tenphi/tasty';
|
|
@@ -469,7 +556,7 @@ function useCounterStyle(
|
|
|
469
556
|
### Troubleshooting
|
|
470
557
|
|
|
471
558
|
- Styles are not updating: make sure `configure()` runs before first render, and verify the generated class name or global rule with [Debug Utilities](debug.md).
|
|
472
|
-
- SSR output looks wrong: check the [SSR guide](ssr.md)
|
|
559
|
+
- SSR output looks wrong: check the [SSR guide](ssr.md) for collector setup. `computeStyles()` discovers the SSR collector via `AsyncLocalStorage` or the global getter registered by `TastyRegistry`.
|
|
473
560
|
- Animation/custom property issues: prefer `useKeyframes()` and `useProperty()` over raw CSS when you want Tasty to manage injection and SSR collection for you.
|
|
474
561
|
|
|
475
562
|
---
|
package/docs/ssr.md
CHANGED
|
@@ -18,16 +18,16 @@ The Astro integration (`@tenphi/tasty/ssr/astro`) has no additional dependencies
|
|
|
18
18
|
|
|
19
19
|
## How It Works
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
`tasty()` components are hook-free and use `computeStyles()` internally — a synchronous, framework-agnostic function. On the server, `computeStyles()` detects a `ServerStyleCollector` (via `AsyncLocalStorage` or an explicit option) and collects CSS into it instead of trying to access the DOM. On the client, CSS is injected synchronously into the DOM during render; the injector's content-based cache makes this idempotent. The collector accumulates all styles, serializes them as `<style>` tags and a cache state script in the HTML. On the client, `hydrateTastyCache()` pre-populates the injector cache so that `computeStyles()` skips the rendering pipeline entirely during hydration.
|
|
22
22
|
|
|
23
23
|
```
|
|
24
24
|
Server Client
|
|
25
25
|
────── ──────
|
|
26
26
|
tasty() renders hydrateTastyCache() pre-populates cache
|
|
27
|
-
└─
|
|
27
|
+
└─ computeStyles() └─ cacheKey → className map ready
|
|
28
28
|
└─ collector.collect()
|
|
29
29
|
tasty() renders
|
|
30
|
-
After render: └─
|
|
30
|
+
After render: └─ computeStyles()
|
|
31
31
|
<style data-tasty-ssr> └─ cache hit → skip pipeline
|
|
32
32
|
<script data-tasty-cache> └─ no CSS re-injection
|
|
33
33
|
```
|
|
@@ -82,15 +82,15 @@ That's it. All `tasty()` components inside the tree automatically get SSR suppor
|
|
|
82
82
|
|
|
83
83
|
### How it works
|
|
84
84
|
|
|
85
|
-
- `TastyRegistry` is a `'use client'` component, but Next.js still server-renders it on initial page load.
|
|
86
|
-
- During SSR, `useStyles()`
|
|
87
|
-
- `TastyRegistry` uses `useServerInsertedHTML` to flush collected CSS into the HTML stream as `<style data-tasty-ssr>` tags. This is fully streaming-compatible
|
|
85
|
+
- `TastyRegistry` is a `'use client'` component, but Next.js still server-renders it on initial page load. The `'use client'` boundary is required solely to access `useServerInsertedHTML` — **not** because `tasty()` components need the client.
|
|
86
|
+
- During SSR, `TastyRegistry` creates a `ServerStyleCollector` and registers it via a module-level global getter. All style computation — whether from `tasty()` components, `computeStyles()`, `useStyles()`, or other hooks like `useGlobalStyles()` — discovers the collector through this single global getter. No React context is involved.
|
|
87
|
+
- `TastyRegistry` uses `useServerInsertedHTML` to flush collected CSS into the HTML stream as `<style data-tasty-ssr>` tags. This is fully streaming-compatible — styles are injected alongside each Suspense boundary as it resolves.
|
|
88
88
|
- A companion `<script>` tag transfers the `cacheKey → className` mapping to the client.
|
|
89
|
-
- When the module loads on the client, `hydrateTastyCache()` runs automatically and pre-populates the injector cache. During hydration, `
|
|
89
|
+
- When the module loads on the client, `hydrateTastyCache()` runs automatically and pre-populates the injector cache. During hydration, `computeStyles()` hits the cache and skips the entire pipeline.
|
|
90
90
|
|
|
91
91
|
### Using tasty() in Server Components
|
|
92
92
|
|
|
93
|
-
`tasty()` components
|
|
93
|
+
`tasty()` components are hook-free and do not require `'use client'`. They can be used directly in React Server Components. Dynamic `styleProps` like `<Grid flow="column">` work normally in server components. During SSR, `computeStyles()` discovers the collector via the same global getter registered by `TastyRegistry` — no React context or client boundary needed for this path.
|
|
94
94
|
|
|
95
95
|
### Options
|
|
96
96
|
|
|
@@ -161,10 +161,10 @@ import Card from '../components/Card.tsx';
|
|
|
161
161
|
|
|
162
162
|
### How it works
|
|
163
163
|
|
|
164
|
-
Astro's `@astrojs/react` renderer calls `renderToString()` for each React component without wrapping the tree in a provider. The middleware uses `AsyncLocalStorage` to make the collector available to all `
|
|
164
|
+
Astro's `@astrojs/react` renderer calls `renderToString()` for each React component without wrapping the tree in a provider. The middleware uses `AsyncLocalStorage` to make the collector available to all `computeStyles()` calls within the request.
|
|
165
165
|
|
|
166
166
|
- **Static components** (no `client:*`): Styles are collected during `renderToString` and injected into `</head>`. No JavaScript is shipped for these components.
|
|
167
|
-
- **Islands** (`client:load`, `client:visible`, etc.): Styles are collected during SSR the same way. On the client, importing `@tenphi/tasty/ssr/astro` auto-hydrates the cache from `<script data-tasty-cache>`. The island's `
|
|
167
|
+
- **Islands** (`client:load`, `client:visible`, etc.): Styles are collected during SSR the same way. On the client, importing `@tenphi/tasty/ssr/astro` auto-hydrates the cache from `<script data-tasty-cache>`. The island's `computeStyles()` calls hit the cache during hydration.
|
|
168
168
|
|
|
169
169
|
### Client-side hydration for islands
|
|
170
170
|
|
|
@@ -197,12 +197,12 @@ Same as Next.js -- call `configure({ nonce: '...' })` before any rendering happe
|
|
|
197
197
|
|
|
198
198
|
## Generic Framework Integration
|
|
199
199
|
|
|
200
|
-
Any React-based framework can integrate using the
|
|
200
|
+
Any React-based framework can integrate using `runWithCollector`, which binds a `ServerStyleCollector` to the current async context via `AsyncLocalStorage`. All `computeStyles()` and hook calls within the render automatically discover the collector.
|
|
201
201
|
|
|
202
202
|
```tsx
|
|
203
203
|
import {
|
|
204
204
|
ServerStyleCollector,
|
|
205
|
-
|
|
205
|
+
runWithCollector,
|
|
206
206
|
hydrateTastyCache,
|
|
207
207
|
} from '@tenphi/tasty/ssr';
|
|
208
208
|
import { renderToString } from 'react-dom/server';
|
|
@@ -212,10 +212,8 @@ import { hydrateRoot } from 'react-dom/client';
|
|
|
212
212
|
|
|
213
213
|
const collector = new ServerStyleCollector();
|
|
214
214
|
|
|
215
|
-
const html =
|
|
216
|
-
<
|
|
217
|
-
<App />
|
|
218
|
-
</TastySSRContext.Provider>
|
|
215
|
+
const html = await runWithCollector(collector, () =>
|
|
216
|
+
renderToString(<App />)
|
|
219
217
|
);
|
|
220
218
|
|
|
221
219
|
const css = collector.getCSS();
|
|
@@ -251,11 +249,8 @@ For streaming with `renderToPipeableStream`, use `flushCSS()` instead of `getCSS
|
|
|
251
249
|
```tsx
|
|
252
250
|
const collector = new ServerStyleCollector();
|
|
253
251
|
|
|
254
|
-
const stream =
|
|
255
|
-
<
|
|
256
|
-
<App />
|
|
257
|
-
</TastySSRContext.Provider>,
|
|
258
|
-
{
|
|
252
|
+
const stream = await runWithCollector(collector, () =>
|
|
253
|
+
renderToPipeableStream(<App />, {
|
|
259
254
|
onShellReady() {
|
|
260
255
|
// Flush styles collected so far
|
|
261
256
|
const css = collector.flushCSS();
|
|
@@ -270,31 +265,10 @@ const stream = renderToPipeableStream(
|
|
|
270
265
|
const state = collector.getCacheState();
|
|
271
266
|
res.write(`<script data-tasty-cache type="application/json">${JSON.stringify(state)}</script>`);
|
|
272
267
|
},
|
|
273
|
-
}
|
|
268
|
+
})
|
|
274
269
|
);
|
|
275
270
|
```
|
|
276
271
|
|
|
277
|
-
### AsyncLocalStorage (no React context)
|
|
278
|
-
|
|
279
|
-
If your framework doesn't support wrapping the React tree with a provider, use `runWithCollector`:
|
|
280
|
-
|
|
281
|
-
```tsx
|
|
282
|
-
import {
|
|
283
|
-
ServerStyleCollector,
|
|
284
|
-
runWithCollector,
|
|
285
|
-
hydrateTastyCache,
|
|
286
|
-
} from '@tenphi/tasty/ssr';
|
|
287
|
-
|
|
288
|
-
const collector = new ServerStyleCollector();
|
|
289
|
-
|
|
290
|
-
const html = await runWithCollector(collector, () =>
|
|
291
|
-
renderToString(<App />)
|
|
292
|
-
);
|
|
293
|
-
|
|
294
|
-
const css = collector.getCSS();
|
|
295
|
-
// ... inject into HTML as above
|
|
296
|
-
```
|
|
297
|
-
|
|
298
272
|
---
|
|
299
273
|
|
|
300
274
|
## API Reference
|
|
@@ -303,7 +277,7 @@ const css = collector.getCSS();
|
|
|
303
277
|
|
|
304
278
|
| Import path | Description |
|
|
305
279
|
|---|---|
|
|
306
|
-
| `@tenphi/tasty/ssr` | Core SSR API: `ServerStyleCollector`, `
|
|
280
|
+
| `@tenphi/tasty/ssr` | Core SSR API: `ServerStyleCollector`, `runWithCollector`, `hydrateTastyCache` |
|
|
307
281
|
| `@tenphi/tasty/ssr/next` | Next.js App Router: `TastyRegistry` component |
|
|
308
282
|
| `@tenphi/tasty/ssr/astro` | Astro: `tastyMiddleware`, auto-hydration on import |
|
|
309
283
|
|
|
@@ -323,10 +297,6 @@ Server-safe style collector. One instance per request.
|
|
|
323
297
|
| `flushCSS()` | Get only CSS collected since the last flush. For streaming SSR. |
|
|
324
298
|
| `getCacheState()` | Serialize `{ entries: Record<cacheKey, className>, classCounter }` for client hydration. |
|
|
325
299
|
|
|
326
|
-
### `TastySSRContext`
|
|
327
|
-
|
|
328
|
-
React context (`createContext<ServerStyleCollector | null>(null)`). Used by `useStyles()` to find the collector during SSR.
|
|
329
|
-
|
|
330
300
|
### `TastyRegistry`
|
|
331
301
|
|
|
332
302
|
Next.js App Router component. Props:
|
|
@@ -350,7 +320,7 @@ Pre-populate the client injector cache. When called without arguments, reads fro
|
|
|
350
320
|
|
|
351
321
|
### `runWithCollector(collector, fn)`
|
|
352
322
|
|
|
353
|
-
Run a function with a `ServerStyleCollector` bound to the current async context via `AsyncLocalStorage`. All `useStyles()` calls within `fn` (and async continuations) will find this collector.
|
|
323
|
+
Run a function with a `ServerStyleCollector` bound to the current async context via `AsyncLocalStorage`. All `computeStyles()` and `useStyles()` calls within `fn` (and async continuations) will find this collector.
|
|
354
324
|
|
|
355
325
|
---
|
|
356
326
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tenphi/tasty",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "A design-system-integrated styling system and DSL for concise, state-aware UI styling",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -150,13 +150,13 @@
|
|
|
150
150
|
"name": "main (import *)",
|
|
151
151
|
"path": "dist/index.js",
|
|
152
152
|
"import": "*",
|
|
153
|
-
"limit": "
|
|
153
|
+
"limit": "48 kB"
|
|
154
154
|
},
|
|
155
155
|
{
|
|
156
156
|
"name": "core (import *)",
|
|
157
157
|
"path": "dist/core/index.js",
|
|
158
158
|
"import": "*",
|
|
159
|
-
"limit": "
|
|
159
|
+
"limit": "46 kB"
|
|
160
160
|
},
|
|
161
161
|
{
|
|
162
162
|
"name": "static",
|
|
@@ -184,7 +184,7 @@
|
|
|
184
184
|
"path",
|
|
185
185
|
"crypto"
|
|
186
186
|
],
|
|
187
|
-
"limit": "
|
|
187
|
+
"limit": "42 kB"
|
|
188
188
|
}
|
|
189
189
|
],
|
|
190
190
|
"scripts": {
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { getRegisteredSSRCollector } from "../ssr/ssr-collector-ref.js";
|
|
2
|
-
//#region src/hooks/resolve-ssr-collector.ts
|
|
3
|
-
/**
|
|
4
|
-
* Resolve the SSR collector from React context or AsyncLocalStorage.
|
|
5
|
-
* Returns null on the client (no collector available).
|
|
6
|
-
*/
|
|
7
|
-
function resolveSSRCollector(reactContext) {
|
|
8
|
-
if (reactContext) return reactContext;
|
|
9
|
-
return getRegisteredSSRCollector();
|
|
10
|
-
}
|
|
11
|
-
//#endregion
|
|
12
|
-
export { resolveSSRCollector };
|
|
13
|
-
|
|
14
|
-
//# sourceMappingURL=resolve-ssr-collector.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"resolve-ssr-collector.js","names":[],"sources":["../../src/hooks/resolve-ssr-collector.ts"],"sourcesContent":["import type { ServerStyleCollector } from '../ssr/collector';\nimport { getRegisteredSSRCollector } from '../ssr/ssr-collector-ref';\n\n/**\n * Resolve the SSR collector from React context or AsyncLocalStorage.\n * Returns null on the client (no collector available).\n */\nexport function resolveSSRCollector(\n reactContext: ServerStyleCollector | null,\n): ServerStyleCollector | null {\n if (reactContext) return reactContext;\n return getRegisteredSSRCollector();\n}\n"],"mappings":";;;;;;AAOA,SAAgB,oBACd,cAC6B;AAC7B,KAAI,aAAc,QAAO;AACzB,QAAO,2BAA2B"}
|
package/dist/ssr/context.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { ServerStyleCollector } from "./collector.js";
|
|
2
|
-
import * as _$react from "react";
|
|
3
|
-
|
|
4
|
-
//#region src/ssr/context.d.ts
|
|
5
|
-
declare const TastySSRContext: _$react.Context<ServerStyleCollector | null>;
|
|
6
|
-
//#endregion
|
|
7
|
-
export { TastySSRContext };
|
|
8
|
-
//# sourceMappingURL=context.d.ts.map
|
package/dist/ssr/context.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { createContext } from "react";
|
|
2
|
-
//#region src/ssr/context.ts
|
|
3
|
-
/**
|
|
4
|
-
* React context for SSR collector discovery.
|
|
5
|
-
*
|
|
6
|
-
* Used by Next.js TastyRegistry to provide the ServerStyleCollector
|
|
7
|
-
* to useStyles() via React context (the streaming-compatible path).
|
|
8
|
-
*/
|
|
9
|
-
const TastySSRContext = createContext(null);
|
|
10
|
-
//#endregion
|
|
11
|
-
export { TastySSRContext };
|
|
12
|
-
|
|
13
|
-
//# sourceMappingURL=context.js.map
|
package/dist/ssr/context.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","names":[],"sources":["../../src/ssr/context.ts"],"sourcesContent":["/**\n * React context for SSR collector discovery.\n *\n * Used by Next.js TastyRegistry to provide the ServerStyleCollector\n * to useStyles() via React context (the streaming-compatible path).\n */\n\nimport { createContext } from 'react';\n\nimport type { ServerStyleCollector } from './collector';\n\nexport const TastySSRContext = createContext<ServerStyleCollector | null>(null);\n"],"mappings":";;;;;;;;AAWA,MAAa,kBAAkB,cAA2C,KAAK"}
|