@tenphi/tasty 0.15.2 → 0.16.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/chunks/definitions.js +1 -1
- package/dist/chunks/definitions.js.map +1 -1
- package/dist/config.d.ts +45 -2
- package/dist/config.js +63 -24
- package/dist/config.js.map +1 -1
- package/dist/core/index.d.ts +4 -4
- package/dist/core/index.js +3 -3
- package/dist/counter-style/index.js +51 -0
- package/dist/counter-style/index.js.map +1 -0
- package/dist/font-face/index.js +63 -0
- package/dist/font-face/index.js.map +1 -0
- package/dist/hooks/resolve-ssr-collector.js +15 -0
- package/dist/hooks/resolve-ssr-collector.js.map +1 -0
- package/dist/hooks/useCounterStyle.d.ts +50 -0
- package/dist/hooks/useCounterStyle.js +47 -0
- package/dist/hooks/useCounterStyle.js.map +1 -0
- package/dist/hooks/useFontFace.d.ts +43 -0
- package/dist/hooks/useFontFace.js +71 -0
- package/dist/hooks/useFontFace.js.map +1 -0
- package/dist/hooks/useGlobalStyles.js +1 -5
- package/dist/hooks/useGlobalStyles.js.map +1 -1
- package/dist/hooks/useKeyframes.js +1 -5
- package/dist/hooks/useKeyframes.js.map +1 -1
- package/dist/hooks/useProperty.js +1 -5
- package/dist/hooks/useProperty.js.map +1 -1
- package/dist/hooks/useRawCSS.js +1 -5
- package/dist/hooks/useRawCSS.js.map +1 -1
- package/dist/hooks/useStyles.js +33 -12
- package/dist/hooks/useStyles.js.map +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.js +5 -3
- package/dist/injector/index.d.ts +20 -2
- package/dist/injector/index.js +19 -1
- package/dist/injector/index.js.map +1 -1
- package/dist/injector/injector.d.ts +19 -1
- package/dist/injector/injector.js +35 -0
- package/dist/injector/injector.js.map +1 -1
- package/dist/injector/sheet-manager.js +2 -0
- package/dist/injector/sheet-manager.js.map +1 -1
- package/dist/injector/types.d.ts +61 -1
- package/dist/ssr/collector.d.ts +17 -0
- package/dist/ssr/collector.js +50 -6
- package/dist/ssr/collector.js.map +1 -1
- package/dist/ssr/index.js +1 -1
- package/dist/states/index.js +2 -0
- package/dist/states/index.js.map +1 -1
- package/dist/styles/border.js +2 -2
- package/dist/styles/border.js.map +1 -1
- package/dist/styles/preset.js +23 -37
- package/dist/styles/preset.js.map +1 -1
- package/dist/styles/types.d.ts +25 -3
- package/dist/tasty.d.ts +1 -1
- package/dist/utils/styles.d.ts +0 -1
- package/dist/utils/styles.js +0 -1
- package/dist/utils/styles.js.map +1 -1
- package/dist/zero/babel.d.ts +11 -1
- package/dist/zero/babel.js +13 -7
- package/dist/zero/babel.js.map +1 -1
- package/dist/zero/extractor.js +53 -1
- package/dist/zero/extractor.js.map +1 -1
- package/docs/configuration.md +61 -0
- package/docs/design-system.md +17 -0
- package/docs/dsl.md +91 -1
- package/docs/runtime.md +88 -0
- package/docs/ssr.md +2 -0
- package/docs/tasty-static.md +2 -0
- package/package.json +2 -2
package/dist/hooks/useStyles.js
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import { extractLocalProperties, hasLocalProperties } from "../properties/index.js";
|
|
2
2
|
import { stringifyStyles } from "../utils/styles.js";
|
|
3
|
+
import { extractLocalFontFace, fontFaceContentHash, formatFontFaceRule, hasLocalFontFace } from "../font-face/index.js";
|
|
4
|
+
import { extractLocalCounterStyle, formatCounterStyleRule, hasLocalCounterStyle } from "../counter-style/index.js";
|
|
3
5
|
import { getConfig, getGlobalKeyframes, hasGlobalKeyframes } from "../config.js";
|
|
4
6
|
import { CHUNK_NAMES, categorizeStyleKeys } from "../chunks/definitions.js";
|
|
5
7
|
import { generateChunkCacheKey } from "../chunks/cacheKey.js";
|
|
6
8
|
import { renderStylesForChunk } from "../chunks/renderChunk.js";
|
|
7
|
-
import { allocateClassName, inject, keyframes, property } from "../injector/index.js";
|
|
9
|
+
import { allocateClassName, counterStyle, fontFace, inject, keyframes, property } from "../injector/index.js";
|
|
8
10
|
import { resolveRecipes } from "../utils/resolve-recipes.js";
|
|
9
11
|
import { extractAnimationNamesFromStyles, extractLocalKeyframes, filterUsedKeyframes, hasLocalKeyframes, mergeKeyframes, replaceAnimationNames } from "../keyframes/index.js";
|
|
10
12
|
import { formatPropertyCSS } from "../ssr/format-property.js";
|
|
11
13
|
import { collectAutoInferredProperties } from "../ssr/collect-auto-properties.js";
|
|
14
|
+
import { resolveSSRCollector } from "./resolve-ssr-collector.js";
|
|
12
15
|
import { TastySSRContext } from "../ssr/context.js";
|
|
13
16
|
import { formatKeyframesCSS } from "../ssr/format-keyframes.js";
|
|
14
|
-
import { getRegisteredSSRCollector } from "../ssr/ssr-collector-ref.js";
|
|
15
17
|
import { hasKeys } from "../utils/has-keys.js";
|
|
16
18
|
import { useContext, useInsertionEffect, useMemo, useRef } from "react";
|
|
17
19
|
|
|
@@ -89,16 +91,6 @@ function getUsedKeyframes(styles) {
|
|
|
89
91
|
return filterUsedKeyframes(mergeKeyframes(hasLocal ? extractLocalKeyframes(styles) : null, hasGlobal ? getGlobalKeyframes() : null), usedNames);
|
|
90
92
|
}
|
|
91
93
|
/**
|
|
92
|
-
* Resolve the SSR collector from React context or AsyncLocalStorage.
|
|
93
|
-
* Returns null on the client (no collector available).
|
|
94
|
-
*/
|
|
95
|
-
function resolveSSRCollector(reactContext) {
|
|
96
|
-
if (reactContext) return reactContext;
|
|
97
|
-
const alsCollector = getRegisteredSSRCollector();
|
|
98
|
-
if (alsCollector) return alsCollector;
|
|
99
|
-
return null;
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
94
|
* Process a chunk on the SSR path: allocate via collector, render, collect CSS.
|
|
103
95
|
* Returns null if the chunk produces no CSS rules.
|
|
104
96
|
*/
|
|
@@ -196,6 +188,24 @@ function useStyles(styles) {
|
|
|
196
188
|
if (css) ssrCollector.collectProperty(token, css);
|
|
197
189
|
}
|
|
198
190
|
}
|
|
191
|
+
if (hasLocalFontFace(currentStyles)) {
|
|
192
|
+
const localFontFace = extractLocalFontFace(currentStyles);
|
|
193
|
+
if (localFontFace) for (const [family, input] of Object.entries(localFontFace)) {
|
|
194
|
+
const descriptors = Array.isArray(input) ? input : [input];
|
|
195
|
+
for (const desc of descriptors) {
|
|
196
|
+
const hash = fontFaceContentHash(family, desc);
|
|
197
|
+
const css = formatFontFaceRule(family, desc);
|
|
198
|
+
ssrCollector.collectFontFace(hash, css);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
if (hasLocalCounterStyle(currentStyles)) {
|
|
203
|
+
const localCounterStyle = extractLocalCounterStyle(currentStyles);
|
|
204
|
+
if (localCounterStyle) for (const [name, descriptors] of Object.entries(localCounterStyle)) {
|
|
205
|
+
const css = formatCounterStyleRule(name, descriptors);
|
|
206
|
+
ssrCollector.collectCounterStyle(name, css);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
199
209
|
if (getConfig().autoPropertyTypes !== false) {
|
|
200
210
|
const allRules = chunks.flatMap((c) => c.renderResult.rules);
|
|
201
211
|
if (allRules.length > 0) collectAutoInferredProperties(allRules, ssrCollector, currentStyles);
|
|
@@ -215,6 +225,17 @@ function useStyles(styles) {
|
|
|
215
225
|
const localProperties = extractLocalProperties(currentStyles);
|
|
216
226
|
if (localProperties) for (const [token, definition] of Object.entries(localProperties)) property(token, definition);
|
|
217
227
|
}
|
|
228
|
+
if (currentStyles && hasLocalFontFace(currentStyles)) {
|
|
229
|
+
const localFontFace = extractLocalFontFace(currentStyles);
|
|
230
|
+
if (localFontFace) for (const [family, input] of Object.entries(localFontFace)) {
|
|
231
|
+
const descriptors = Array.isArray(input) ? input : [input];
|
|
232
|
+
for (const desc of descriptors) fontFace(family, desc);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (currentStyles && hasLocalCounterStyle(currentStyles)) {
|
|
236
|
+
const localCounterStyle = extractLocalCounterStyle(currentStyles);
|
|
237
|
+
if (localCounterStyle) for (const [name, descriptors] of Object.entries(localCounterStyle)) counterStyle(name, descriptors);
|
|
238
|
+
}
|
|
218
239
|
const usedKeyframes = currentStyles ? getUsedKeyframes(currentStyles) : null;
|
|
219
240
|
let nameMap = null;
|
|
220
241
|
if (usedKeyframes) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useStyles.js","names":[],"sources":["../../src/hooks/useStyles.ts"],"sourcesContent":["import { useContext, useInsertionEffect, useMemo, useRef } from 'react';\n\nimport {\n categorizeStyleKeys,\n CHUNK_NAMES,\n generateChunkCacheKey,\n renderStylesForChunk,\n} from '../chunks';\nimport { getConfig, getGlobalKeyframes, hasGlobalKeyframes } from '../config';\nimport { allocateClassName, inject, keyframes, property } from '../injector';\nimport type { KeyframesSteps } from '../injector/types';\nimport {\n extractAnimationNamesFromStyles,\n extractLocalKeyframes,\n filterUsedKeyframes,\n hasLocalKeyframes,\n mergeKeyframes,\n replaceAnimationNames,\n} from '../keyframes';\nimport type { RenderResult } from '../pipeline';\nimport { extractLocalProperties, hasLocalProperties } from '../properties';\nimport { collectAutoInferredProperties } from '../ssr/collect-auto-properties';\nimport type { ServerStyleCollector } from '../ssr/collector';\nimport { TastySSRContext } from '../ssr/context';\nimport { formatKeyframesCSS } from '../ssr/format-keyframes';\nimport { formatPropertyCSS } from '../ssr/format-property';\nimport { getRegisteredSSRCollector } from '../ssr/ssr-collector-ref';\nimport type { Styles } from '../styles/types';\nimport { hasKeys } from '../utils/has-keys';\nimport { resolveRecipes } from '../utils/resolve-recipes';\nimport { stringifyStyles } from '../utils/styles';\n\n/**\n * Check if styles contain @starting-style rules.\n *\n * @starting-style CSS cannot be applied via multiple class names because\n * of cascade - later rules override earlier ones. When @starting is detected,\n * we combine top-level styles into a single chunk but keep sub-element styles\n * in their own chunk for better caching.\n */\nfunction containsStartingStyle(styleKey: string): boolean {\n return styleKey.includes('@starting');\n}\n\n/**\n * Tasty styles object to generate CSS classes for.\n * Can be undefined or empty object for no styles.\n */\nexport type UseStylesOptions = Styles | undefined;\n\nexport interface UseStylesResult {\n /**\n * Generated className(s) to apply to the element.\n * Can be empty string if no styles are provided.\n * With chunking enabled, may contain multiple space-separated class names.\n */\n className: string;\n}\n\n/**\n * Information about a processed chunk\n */\ninterface ProcessedChunk {\n name: string;\n styleKeys: string[];\n cacheKey: string;\n renderResult: RenderResult;\n className: string;\n}\n\n/**\n * Render, cache-key, and allocate a className for a single chunk.\n * Returns a ProcessedChunk, or null if the chunk produces no CSS rules.\n *\n * Always runs the pipeline and calls allocateClassName. The inject()\n * call in useInsertionEffect handles all edge cases: placeholders from\n * abandoned concurrent renders, hydration hits (ruleIndex -2), and\n * runtime cache hits (already injected). The pipeline's own LRU cache\n * makes repeated calls for identical styles cheap.\n */\nfunction processChunk(\n styles: Styles,\n chunkName: string,\n styleKeys: string[],\n): ProcessedChunk | null {\n if (styleKeys.length === 0) return null;\n\n const cacheKey = generateChunkCacheKey(styles, chunkName, styleKeys);\n const renderResult = renderStylesForChunk(\n styles,\n chunkName,\n styleKeys,\n cacheKey,\n );\n if (renderResult.rules.length === 0) return null;\n\n const { className } = allocateClassName(cacheKey);\n\n return { name: chunkName, styleKeys, cacheKey, renderResult, className };\n}\n\n/**\n * Merge chunk map entries for @starting-style partial chunking.\n *\n * All non-subcomponent chunks are merged into a single COMBINED entry,\n * while SUBCOMPONENTS stays separate. This preserves CSS cascade for\n * @starting-style while still allowing sub-element styles to cache independently.\n */\nfunction mergeChunksForStartingStyle(\n chunkMap: Map<string, string[]>,\n): Map<string, string[]> {\n const merged = new Map<string, string[]>();\n const combinedKeys: string[] = [];\n\n for (const [chunkName, keys] of chunkMap) {\n if (chunkName === CHUNK_NAMES.SUBCOMPONENTS) {\n merged.set(CHUNK_NAMES.SUBCOMPONENTS, keys);\n } else {\n combinedKeys.push(...keys);\n }\n }\n\n if (combinedKeys.length > 0) {\n // Insert COMBINED first so it appears before SUBCOMPONENTS\n const result = new Map<string, string[]>();\n result.set(CHUNK_NAMES.COMBINED, combinedKeys);\n for (const [k, v] of merged) {\n result.set(k, v);\n }\n return result;\n }\n\n return merged;\n}\n\n/**\n * Get keyframes that are actually used in styles.\n * Returns null if no keyframes are used (fast path for zero overhead).\n *\n * Optimization order:\n * 1. Check if any keyframes are defined (local or global) - if not, return null\n * 2. Extract animation names from styles - if none, return null\n * 3. Merge and filter keyframes to only used ones\n */\nfunction getUsedKeyframes(\n styles: Styles,\n): Record<string, KeyframesSteps> | null {\n // Fast path: no keyframes defined anywhere\n const hasLocal = hasLocalKeyframes(styles);\n const hasGlobal = hasGlobalKeyframes();\n if (!hasLocal && !hasGlobal) return null;\n\n // Extract animation names from styles (not from rendered CSS - faster)\n const usedNames = extractAnimationNamesFromStyles(styles);\n if (usedNames.size === 0) return null;\n\n // Merge local and global keyframes\n const local = hasLocal ? extractLocalKeyframes(styles) : null;\n const global = hasGlobal ? getGlobalKeyframes() : null;\n const allKeyframes = mergeKeyframes(local, global);\n\n // Filter to only used keyframes\n return filterUsedKeyframes(allKeyframes, usedNames);\n}\n\n/**\n * Resolve the SSR collector from React context or AsyncLocalStorage.\n * Returns null on the client (no collector available).\n */\nfunction resolveSSRCollector(\n reactContext: ServerStyleCollector | null,\n): ServerStyleCollector | null {\n if (reactContext) return reactContext;\n\n const alsCollector = getRegisteredSSRCollector();\n if (alsCollector) return alsCollector;\n\n return null;\n}\n\n/**\n * Process a chunk on the SSR path: allocate via collector, render, collect CSS.\n * Returns null if the chunk produces no CSS rules.\n */\nfunction processChunkSSR(\n collector: ServerStyleCollector,\n styles: Styles,\n chunkName: string,\n styleKeys: string[],\n): ProcessedChunk | null {\n if (styleKeys.length === 0) return null;\n\n const cacheKey = generateChunkCacheKey(styles, chunkName, styleKeys);\n const { className, isNewAllocation } = collector.allocateClassName(cacheKey);\n\n if (isNewAllocation) {\n const renderResult = renderStylesForChunk(styles, chunkName, styleKeys);\n if (renderResult.rules.length > 0) {\n collector.collectChunk(cacheKey, className, renderResult.rules);\n return {\n name: chunkName,\n styleKeys,\n cacheKey,\n renderResult,\n className,\n };\n }\n return null;\n }\n\n return {\n name: chunkName,\n styleKeys,\n cacheKey,\n renderResult: { rules: [] },\n className,\n };\n}\n\n/**\n * Hook to generate CSS classes from Tasty styles.\n * Handles style rendering, className allocation, and CSS injection.\n *\n * SSR-aware: when a ServerStyleCollector is available (via React context\n * or AsyncLocalStorage), CSS is collected during the render phase instead\n * of being injected into the DOM. useInsertionEffect does not run on the\n * server, so the collector path is the only active path during SSR.\n *\n * Uses chunking to split styles into logical groups for better caching\n * and CSS reuse across components.\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { className } = useStyles({\n * padding: '2x',\n * fill: '#purple',\n * radius: '1r',\n * });\n *\n * return <div className={className}>Styled content</div>;\n * }\n * ```\n */\nexport function useStyles(styles: UseStylesOptions): UseStylesResult {\n const ssrContextValue = useContext(TastySSRContext);\n const ssrCollector = resolveSSRCollector(ssrContextValue);\n\n // Array of dispose functions for each chunk\n const disposeRef = useRef<(() => void)[]>([]);\n\n // Store styles by their stringified key to avoid recomputing when only reference changes\n const stylesRef = useRef<{ key: string; styles: Styles | undefined }>({\n key: '',\n styles: undefined,\n });\n\n // Resolve recipes before any processing (zero overhead if no recipes configured)\n const resolvedStyles = useMemo(() => {\n if (!styles) return styles;\n return resolveRecipes(styles);\n }, [styles]);\n\n // Compute style key - this is a primitive string that captures style content\n const styleKey = useMemo(() => {\n if (!resolvedStyles || !hasKeys(resolvedStyles)) {\n return '';\n }\n return stringifyStyles(resolvedStyles);\n }, [resolvedStyles]);\n\n // Update ref when styleKey changes (content actually changed)\n if (stylesRef.current.key !== styleKey) {\n stylesRef.current = { key: styleKey, styles: resolvedStyles };\n }\n\n // Process chunks: categorize, generate cache keys, render, and allocate classNames\n // Only depends on styleKey (primitive), not styles object reference\n const processedChunks: ProcessedChunk[] = useMemo(() => {\n const currentStyles = stylesRef.current.styles;\n if (!styleKey || !currentStyles) {\n return [];\n }\n\n // Categorize style keys into chunks\n let chunkMap = categorizeStyleKeys(\n currentStyles as Record<string, unknown>,\n );\n\n // Partial chunking for styles containing @starting-style rules.\n // @starting-style CSS cannot work with multiple class names due to cascade,\n // so we merge all top-level chunks into one but keep sub-element styles separate.\n if (containsStartingStyle(styleKey)) {\n chunkMap = mergeChunksForStartingStyle(chunkMap);\n }\n\n const chunks: ProcessedChunk[] = [];\n\n if (ssrCollector) {\n // Ensure internal @property and :root token CSS is included\n ssrCollector.collectInternals();\n\n // SERVER PATH: allocate via collector, collect CSS\n for (const [chunkName, chunkStyleKeys] of chunkMap) {\n const chunk = processChunkSSR(\n ssrCollector,\n currentStyles,\n chunkName,\n chunkStyleKeys,\n );\n if (chunk) chunks.push(chunk);\n }\n\n // Collect keyframes on the server\n const usedKeyframes = getUsedKeyframes(currentStyles);\n if (usedKeyframes) {\n for (const [name, steps] of Object.entries(usedKeyframes)) {\n const css = formatKeyframesCSS(name, steps);\n ssrCollector.collectKeyframes(name, css);\n }\n }\n\n // Collect explicit @property rules on the server\n if (hasLocalProperties(currentStyles)) {\n const localProperties = extractLocalProperties(currentStyles);\n if (localProperties) {\n for (const [token, definition] of Object.entries(localProperties)) {\n const css = formatPropertyCSS(token, definition);\n if (css) {\n ssrCollector.collectProperty(token, css);\n }\n }\n }\n }\n\n // Auto-infer @property types from rendered declarations (SSR).\n // On the client this happens inside StyleInjector.inject(), which\n // runs in useInsertionEffect and therefore never executes on the server.\n if (getConfig().autoPropertyTypes !== false) {\n const allRules = chunks.flatMap((c) => c.renderResult.rules);\n if (allRules.length > 0) {\n collectAutoInferredProperties(allRules, ssrCollector, currentStyles);\n }\n }\n } else {\n // CLIENT PATH: unchanged behavior\n for (const [chunkName, chunkStyleKeys] of chunkMap) {\n const chunk = processChunk(currentStyles, chunkName, chunkStyleKeys);\n if (chunk) chunks.push(chunk);\n }\n }\n\n return chunks;\n }, [styleKey]);\n\n // Inject styles in insertion effect (avoids render phase side effects).\n // Does NOT run on the server — the SSR path above handles collection.\n useInsertionEffect(() => {\n // Cleanup all previous disposals\n disposeRef.current.forEach((dispose) => dispose?.());\n disposeRef.current = [];\n\n // Fast path: no chunks to inject\n if (processedChunks.length === 0) {\n return;\n }\n\n const currentStyles = stylesRef.current.styles;\n\n // Register explicit @properties first so they take precedence over auto-inference\n // that happens during keyframe and style chunk injection.\n // Token formats: $name → --name, #name → --name-color (with auto syntax: '<color>')\n // Note: Global properties are injected once when styles are first generated (see markStylesGenerated)\n if (currentStyles && hasLocalProperties(currentStyles)) {\n const localProperties = extractLocalProperties(currentStyles);\n if (localProperties) {\n for (const [token, definition] of Object.entries(localProperties)) {\n property(token, definition);\n }\n }\n }\n\n // Get keyframes that are actually used (returns null if none - zero overhead)\n const usedKeyframes = currentStyles\n ? getUsedKeyframes(currentStyles)\n : null;\n\n // Inject keyframes and build name map (only if we have keyframes)\n let nameMap: Map<string, string> | null = null;\n\n if (usedKeyframes) {\n nameMap = new Map();\n for (const [name, steps] of Object.entries(usedKeyframes)) {\n const result = keyframes(steps, { name });\n const injectedName = result.toString();\n // Only add to map if name differs (optimization for replacement check)\n if (injectedName !== name) {\n nameMap.set(name, injectedName);\n }\n disposeRef.current.push(result.dispose);\n }\n // Clear map if no replacements needed\n if (nameMap.size === 0) {\n nameMap = null;\n }\n }\n\n // Inject each chunk\n for (const chunk of processedChunks) {\n if (chunk.renderResult.rules.length > 0) {\n // Replace animation names only if needed\n const rulesToInject = nameMap\n ? chunk.renderResult.rules.map((rule) => ({\n ...rule,\n declarations: replaceAnimationNames(rule.declarations, nameMap!),\n }))\n : chunk.renderResult.rules;\n\n const { dispose } = inject(rulesToInject, {\n cacheKey: chunk.cacheKey,\n });\n disposeRef.current.push(dispose);\n }\n }\n\n return () => {\n disposeRef.current.forEach((dispose) => dispose?.());\n disposeRef.current = [];\n };\n }, [processedChunks]);\n\n // Combine all chunk classNames\n const className = useMemo(() => {\n return processedChunks.map((chunk) => chunk.className).join(' ');\n }, [processedChunks]);\n\n return {\n className,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useStyles.js","names":[],"sources":["../../src/hooks/useStyles.ts"],"sourcesContent":["import { useContext, useInsertionEffect, useMemo, useRef } from 'react';\n\nimport {\n categorizeStyleKeys,\n CHUNK_NAMES,\n generateChunkCacheKey,\n renderStylesForChunk,\n} from '../chunks';\nimport { getConfig, getGlobalKeyframes, hasGlobalKeyframes } from '../config';\nimport {\n allocateClassName,\n counterStyle,\n fontFace,\n inject,\n keyframes,\n property,\n} from '../injector';\nimport type { FontFaceDescriptors, KeyframesSteps } from '../injector/types';\nimport {\n extractLocalCounterStyle,\n formatCounterStyleRule,\n hasLocalCounterStyle,\n} from '../counter-style';\nimport {\n extractLocalFontFace,\n fontFaceContentHash,\n formatFontFaceRule,\n hasLocalFontFace,\n} from '../font-face';\nimport {\n extractAnimationNamesFromStyles,\n extractLocalKeyframes,\n filterUsedKeyframes,\n hasLocalKeyframes,\n mergeKeyframes,\n replaceAnimationNames,\n} from '../keyframes';\nimport type { RenderResult } from '../pipeline';\nimport { extractLocalProperties, hasLocalProperties } from '../properties';\nimport { collectAutoInferredProperties } from '../ssr/collect-auto-properties';\nimport type { ServerStyleCollector } from '../ssr/collector';\nimport { resolveSSRCollector } from './resolve-ssr-collector';\nimport { TastySSRContext } from '../ssr/context';\nimport { formatKeyframesCSS } from '../ssr/format-keyframes';\nimport { formatPropertyCSS } from '../ssr/format-property';\nimport type { Styles } from '../styles/types';\nimport { hasKeys } from '../utils/has-keys';\nimport { resolveRecipes } from '../utils/resolve-recipes';\nimport { stringifyStyles } from '../utils/styles';\n\n/**\n * Check if styles contain @starting-style rules.\n *\n * @starting-style CSS cannot be applied via multiple class names because\n * of cascade - later rules override earlier ones. When @starting is detected,\n * we combine top-level styles into a single chunk but keep sub-element styles\n * in their own chunk for better caching.\n */\nfunction containsStartingStyle(styleKey: string): boolean {\n return styleKey.includes('@starting');\n}\n\n/**\n * Tasty styles object to generate CSS classes for.\n * Can be undefined or empty object for no styles.\n */\nexport type UseStylesOptions = Styles | undefined;\n\nexport interface UseStylesResult {\n /**\n * Generated className(s) to apply to the element.\n * Can be empty string if no styles are provided.\n * With chunking enabled, may contain multiple space-separated class names.\n */\n className: string;\n}\n\n/**\n * Information about a processed chunk\n */\ninterface ProcessedChunk {\n name: string;\n styleKeys: string[];\n cacheKey: string;\n renderResult: RenderResult;\n className: string;\n}\n\n/**\n * Render, cache-key, and allocate a className for a single chunk.\n * Returns a ProcessedChunk, or null if the chunk produces no CSS rules.\n *\n * Always runs the pipeline and calls allocateClassName. The inject()\n * call in useInsertionEffect handles all edge cases: placeholders from\n * abandoned concurrent renders, hydration hits (ruleIndex -2), and\n * runtime cache hits (already injected). The pipeline's own LRU cache\n * makes repeated calls for identical styles cheap.\n */\nfunction processChunk(\n styles: Styles,\n chunkName: string,\n styleKeys: string[],\n): ProcessedChunk | null {\n if (styleKeys.length === 0) return null;\n\n const cacheKey = generateChunkCacheKey(styles, chunkName, styleKeys);\n const renderResult = renderStylesForChunk(\n styles,\n chunkName,\n styleKeys,\n cacheKey,\n );\n if (renderResult.rules.length === 0) return null;\n\n const { className } = allocateClassName(cacheKey);\n\n return { name: chunkName, styleKeys, cacheKey, renderResult, className };\n}\n\n/**\n * Merge chunk map entries for @starting-style partial chunking.\n *\n * All non-subcomponent chunks are merged into a single COMBINED entry,\n * while SUBCOMPONENTS stays separate. This preserves CSS cascade for\n * @starting-style while still allowing sub-element styles to cache independently.\n */\nfunction mergeChunksForStartingStyle(\n chunkMap: Map<string, string[]>,\n): Map<string, string[]> {\n const merged = new Map<string, string[]>();\n const combinedKeys: string[] = [];\n\n for (const [chunkName, keys] of chunkMap) {\n if (chunkName === CHUNK_NAMES.SUBCOMPONENTS) {\n merged.set(CHUNK_NAMES.SUBCOMPONENTS, keys);\n } else {\n combinedKeys.push(...keys);\n }\n }\n\n if (combinedKeys.length > 0) {\n // Insert COMBINED first so it appears before SUBCOMPONENTS\n const result = new Map<string, string[]>();\n result.set(CHUNK_NAMES.COMBINED, combinedKeys);\n for (const [k, v] of merged) {\n result.set(k, v);\n }\n return result;\n }\n\n return merged;\n}\n\n/**\n * Get keyframes that are actually used in styles.\n * Returns null if no keyframes are used (fast path for zero overhead).\n *\n * Optimization order:\n * 1. Check if any keyframes are defined (local or global) - if not, return null\n * 2. Extract animation names from styles - if none, return null\n * 3. Merge and filter keyframes to only used ones\n */\nfunction getUsedKeyframes(\n styles: Styles,\n): Record<string, KeyframesSteps> | null {\n // Fast path: no keyframes defined anywhere\n const hasLocal = hasLocalKeyframes(styles);\n const hasGlobal = hasGlobalKeyframes();\n if (!hasLocal && !hasGlobal) return null;\n\n // Extract animation names from styles (not from rendered CSS - faster)\n const usedNames = extractAnimationNamesFromStyles(styles);\n if (usedNames.size === 0) return null;\n\n // Merge local and global keyframes\n const local = hasLocal ? extractLocalKeyframes(styles) : null;\n const global = hasGlobal ? getGlobalKeyframes() : null;\n const allKeyframes = mergeKeyframes(local, global);\n\n // Filter to only used keyframes\n return filterUsedKeyframes(allKeyframes, usedNames);\n}\n\n/**\n * Process a chunk on the SSR path: allocate via collector, render, collect CSS.\n * Returns null if the chunk produces no CSS rules.\n */\nfunction processChunkSSR(\n collector: ServerStyleCollector,\n styles: Styles,\n chunkName: string,\n styleKeys: string[],\n): ProcessedChunk | null {\n if (styleKeys.length === 0) return null;\n\n const cacheKey = generateChunkCacheKey(styles, chunkName, styleKeys);\n const { className, isNewAllocation } = collector.allocateClassName(cacheKey);\n\n if (isNewAllocation) {\n const renderResult = renderStylesForChunk(styles, chunkName, styleKeys);\n if (renderResult.rules.length > 0) {\n collector.collectChunk(cacheKey, className, renderResult.rules);\n return {\n name: chunkName,\n styleKeys,\n cacheKey,\n renderResult,\n className,\n };\n }\n return null;\n }\n\n return {\n name: chunkName,\n styleKeys,\n cacheKey,\n renderResult: { rules: [] },\n className,\n };\n}\n\n/**\n * Hook to generate CSS classes from Tasty styles.\n * Handles style rendering, className allocation, and CSS injection.\n *\n * SSR-aware: when a ServerStyleCollector is available (via React context\n * or AsyncLocalStorage), CSS is collected during the render phase instead\n * of being injected into the DOM. useInsertionEffect does not run on the\n * server, so the collector path is the only active path during SSR.\n *\n * Uses chunking to split styles into logical groups for better caching\n * and CSS reuse across components.\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { className } = useStyles({\n * padding: '2x',\n * fill: '#purple',\n * radius: '1r',\n * });\n *\n * return <div className={className}>Styled content</div>;\n * }\n * ```\n */\nexport function useStyles(styles: UseStylesOptions): UseStylesResult {\n const ssrContextValue = useContext(TastySSRContext);\n const ssrCollector = resolveSSRCollector(ssrContextValue);\n\n // Array of dispose functions for each chunk\n const disposeRef = useRef<(() => void)[]>([]);\n\n // Store styles by their stringified key to avoid recomputing when only reference changes\n const stylesRef = useRef<{ key: string; styles: Styles | undefined }>({\n key: '',\n styles: undefined,\n });\n\n // Resolve recipes before any processing (zero overhead if no recipes configured)\n const resolvedStyles = useMemo(() => {\n if (!styles) return styles;\n return resolveRecipes(styles);\n }, [styles]);\n\n // Compute style key - this is a primitive string that captures style content\n const styleKey = useMemo(() => {\n if (!resolvedStyles || !hasKeys(resolvedStyles)) {\n return '';\n }\n return stringifyStyles(resolvedStyles);\n }, [resolvedStyles]);\n\n // Update ref when styleKey changes (content actually changed)\n if (stylesRef.current.key !== styleKey) {\n stylesRef.current = { key: styleKey, styles: resolvedStyles };\n }\n\n // Process chunks: categorize, generate cache keys, render, and allocate classNames\n // Only depends on styleKey (primitive), not styles object reference\n const processedChunks: ProcessedChunk[] = useMemo(() => {\n const currentStyles = stylesRef.current.styles;\n if (!styleKey || !currentStyles) {\n return [];\n }\n\n // Categorize style keys into chunks\n let chunkMap = categorizeStyleKeys(\n currentStyles as Record<string, unknown>,\n );\n\n // Partial chunking for styles containing @starting-style rules.\n // @starting-style CSS cannot work with multiple class names due to cascade,\n // so we merge all top-level chunks into one but keep sub-element styles separate.\n if (containsStartingStyle(styleKey)) {\n chunkMap = mergeChunksForStartingStyle(chunkMap);\n }\n\n const chunks: ProcessedChunk[] = [];\n\n if (ssrCollector) {\n // Ensure internal @property and :root token CSS is included\n ssrCollector.collectInternals();\n\n // SERVER PATH: allocate via collector, collect CSS\n for (const [chunkName, chunkStyleKeys] of chunkMap) {\n const chunk = processChunkSSR(\n ssrCollector,\n currentStyles,\n chunkName,\n chunkStyleKeys,\n );\n if (chunk) chunks.push(chunk);\n }\n\n // Collect keyframes on the server\n const usedKeyframes = getUsedKeyframes(currentStyles);\n if (usedKeyframes) {\n for (const [name, steps] of Object.entries(usedKeyframes)) {\n const css = formatKeyframesCSS(name, steps);\n ssrCollector.collectKeyframes(name, css);\n }\n }\n\n // Collect explicit @property rules on the server\n if (hasLocalProperties(currentStyles)) {\n const localProperties = extractLocalProperties(currentStyles);\n if (localProperties) {\n for (const [token, definition] of Object.entries(localProperties)) {\n const css = formatPropertyCSS(token, definition);\n if (css) {\n ssrCollector.collectProperty(token, css);\n }\n }\n }\n }\n\n // Collect @font-face rules on the server\n if (hasLocalFontFace(currentStyles)) {\n const localFontFace = extractLocalFontFace(currentStyles);\n if (localFontFace) {\n for (const [family, input] of Object.entries(localFontFace)) {\n const descriptors: FontFaceDescriptors[] = Array.isArray(input)\n ? input\n : [input];\n for (const desc of descriptors) {\n const hash = fontFaceContentHash(family, desc);\n const css = formatFontFaceRule(family, desc);\n ssrCollector.collectFontFace(hash, css);\n }\n }\n }\n }\n\n // Collect @counter-style rules on the server\n if (hasLocalCounterStyle(currentStyles)) {\n const localCounterStyle = extractLocalCounterStyle(currentStyles);\n if (localCounterStyle) {\n for (const [name, descriptors] of Object.entries(localCounterStyle)) {\n const css = formatCounterStyleRule(name, descriptors);\n ssrCollector.collectCounterStyle(name, css);\n }\n }\n }\n\n // Auto-infer @property types from rendered declarations (SSR).\n // On the client this happens inside StyleInjector.inject(), which\n // runs in useInsertionEffect and therefore never executes on the server.\n if (getConfig().autoPropertyTypes !== false) {\n const allRules = chunks.flatMap((c) => c.renderResult.rules);\n if (allRules.length > 0) {\n collectAutoInferredProperties(allRules, ssrCollector, currentStyles);\n }\n }\n } else {\n // CLIENT PATH: unchanged behavior\n for (const [chunkName, chunkStyleKeys] of chunkMap) {\n const chunk = processChunk(currentStyles, chunkName, chunkStyleKeys);\n if (chunk) chunks.push(chunk);\n }\n }\n\n return chunks;\n }, [styleKey]);\n\n // Inject styles in insertion effect (avoids render phase side effects).\n // Does NOT run on the server — the SSR path above handles collection.\n useInsertionEffect(() => {\n // Cleanup all previous disposals\n disposeRef.current.forEach((dispose) => dispose?.());\n disposeRef.current = [];\n\n // Fast path: no chunks to inject\n if (processedChunks.length === 0) {\n return;\n }\n\n const currentStyles = stylesRef.current.styles;\n\n // Register explicit @properties first so they take precedence over auto-inference\n // that happens during keyframe and style chunk injection.\n // Token formats: $name → --name, #name → --name-color (with auto syntax: '<color>')\n // Note: Global properties are injected once when styles are first generated (see markStylesGenerated)\n if (currentStyles && hasLocalProperties(currentStyles)) {\n const localProperties = extractLocalProperties(currentStyles);\n if (localProperties) {\n for (const [token, definition] of Object.entries(localProperties)) {\n property(token, definition);\n }\n }\n }\n\n // Inject @font-face rules (permanent, no cleanup needed)\n if (currentStyles && hasLocalFontFace(currentStyles)) {\n const localFontFace = extractLocalFontFace(currentStyles);\n if (localFontFace) {\n for (const [family, input] of Object.entries(localFontFace)) {\n const descriptors: FontFaceDescriptors[] = Array.isArray(input)\n ? input\n : [input];\n for (const desc of descriptors) {\n fontFace(family, desc);\n }\n }\n }\n }\n\n // Inject @counter-style rules (permanent, no cleanup needed)\n if (currentStyles && hasLocalCounterStyle(currentStyles)) {\n const localCounterStyle = extractLocalCounterStyle(currentStyles);\n if (localCounterStyle) {\n for (const [name, descriptors] of Object.entries(localCounterStyle)) {\n counterStyle(name, descriptors);\n }\n }\n }\n\n // Get keyframes that are actually used (returns null if none - zero overhead)\n const usedKeyframes = currentStyles\n ? getUsedKeyframes(currentStyles)\n : null;\n\n // Inject keyframes and build name map (only if we have keyframes)\n let nameMap: Map<string, string> | null = null;\n\n if (usedKeyframes) {\n nameMap = new Map();\n for (const [name, steps] of Object.entries(usedKeyframes)) {\n const result = keyframes(steps, { name });\n const injectedName = result.toString();\n // Only add to map if name differs (optimization for replacement check)\n if (injectedName !== name) {\n nameMap.set(name, injectedName);\n }\n disposeRef.current.push(result.dispose);\n }\n // Clear map if no replacements needed\n if (nameMap.size === 0) {\n nameMap = null;\n }\n }\n\n // Inject each chunk\n for (const chunk of processedChunks) {\n if (chunk.renderResult.rules.length > 0) {\n // Replace animation names only if needed\n const rulesToInject = nameMap\n ? chunk.renderResult.rules.map((rule) => ({\n ...rule,\n declarations: replaceAnimationNames(rule.declarations, nameMap!),\n }))\n : chunk.renderResult.rules;\n\n const { dispose } = inject(rulesToInject, {\n cacheKey: chunk.cacheKey,\n });\n disposeRef.current.push(dispose);\n }\n }\n\n return () => {\n disposeRef.current.forEach((dispose) => dispose?.());\n disposeRef.current = [];\n };\n }, [processedChunks]);\n\n // Combine all chunk classNames\n const className = useMemo(() => {\n return processedChunks.map((chunk) => chunk.className).join(' ');\n }, [processedChunks]);\n\n return {\n className,\n };\n}\n"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CacheMetrics, DisposeFunction, InjectResult, KeyframesCacheEntry, KeyframesInfo, KeyframesResult, KeyframesSteps, PropertyDefinition, RawCSSResult, RootRegistry, RuleInfo, SheetInfo, StyleInjectorConfig, StyleRule } from "./injector/types.js";
|
|
1
|
+
import { CacheMetrics, CounterStyleDescriptors, DisposeFunction, FontFaceDescriptors, FontFaceInput, InjectResult, KeyframesCacheEntry, KeyframesInfo, KeyframesResult, KeyframesSteps, PropertyDefinition, RawCSSResult, RootRegistry, RuleInfo, SheetInfo, StyleInjectorConfig, StyleRule } from "./injector/types.js";
|
|
2
2
|
import { CSSProperties } from "./utils/css-types.js";
|
|
3
3
|
import { Bucket, ParserOptions, ProcessedStyle, StyleDetails, StyleDetailsPart, UnitHandler } from "./parser/types.js";
|
|
4
4
|
import { StyleParser } from "./parser/parser.js";
|
|
@@ -13,7 +13,7 @@ import { SheetManager } from "./injector/sheet-manager.js";
|
|
|
13
13
|
import { StyleInjector } from "./injector/injector.js";
|
|
14
14
|
import { ColorSpace } from "./utils/color-space.js";
|
|
15
15
|
import { TastyPlugin, TastyPluginFactory } from "./plugins/types.js";
|
|
16
|
-
import { TastyConfig, configure, getConfig, getGlobalKeyframes, getGlobalRecipes, hasGlobalKeyframes, hasGlobalRecipes, hasStylesGenerated, isConfigLocked, isTestEnvironment, resetConfig } from "./config.js";
|
|
16
|
+
import { TastyConfig, configure, getConfig, getGlobalCounterStyle, getGlobalFontFace, getGlobalKeyframes, getGlobalRecipes, hasGlobalKeyframes, hasGlobalRecipes, hasStylesGenerated, isConfigLocked, isTestEnvironment, resetConfig } from "./config.js";
|
|
17
17
|
import { okhslFunc, okhslPlugin } from "./plugins/okhsl-plugin.js";
|
|
18
18
|
import { CHUNK_NAMES, ChunkInfo, ChunkName, STYLE_TO_CHUNK, categorizeStyleKeys } from "./chunks/definitions.js";
|
|
19
19
|
import { BASE_STYLES, BLOCK_INNER_STYLES, BLOCK_OUTER_STYLES, BLOCK_STYLES, COLOR_STYLES, CONTAINER_STYLES, DIMENSION_STYLES, FLOW_STYLES, INNER_STYLES, OUTER_STYLES, POSITION_STYLES, TEXT_STYLES } from "./styles/list.js";
|
|
@@ -24,9 +24,11 @@ import { useGlobalStyles } from "./hooks/useGlobalStyles.js";
|
|
|
24
24
|
import { useRawCSS } from "./hooks/useRawCSS.js";
|
|
25
25
|
import { useKeyframes } from "./hooks/useKeyframes.js";
|
|
26
26
|
import { UsePropertyOptions, useProperty } from "./hooks/useProperty.js";
|
|
27
|
+
import { useFontFace } from "./hooks/useFontFace.js";
|
|
28
|
+
import { useCounterStyle } from "./hooks/useCounterStyle.js";
|
|
27
29
|
import { getDisplayName } from "./utils/get-display-name.js";
|
|
28
30
|
import { styleHandlers } from "./styles/predefined.js";
|
|
29
|
-
import { PropertyOptions, allocateClassName, cleanup, createInjector, destroy, getCssText, getCssTextForNode, getIsTestEnvironment, getRawCSSText, inject, injectGlobal, injectRawCSS, injector, isPropertyDefined, keyframes, property, trackRef } from "./injector/index.js";
|
|
31
|
+
import { PropertyOptions, allocateClassName, cleanup, counterStyle, createInjector, destroy, fontFace, getCssText, getCssTextForNode, getIsTestEnvironment, getRawCSSText, inject, injectGlobal, injectRawCSS, injector, isPropertyDefined, keyframes, property, trackRef } from "./injector/index.js";
|
|
30
32
|
import { filterBaseProps } from "./utils/filter-base-props.js";
|
|
31
33
|
import { color } from "./utils/colors.js";
|
|
32
34
|
import { _modAttrs } from "./utils/mod-attrs.js";
|
|
@@ -45,5 +47,5 @@ declare module './utils/css-types' {
|
|
|
45
47
|
interface CSSProperties extends CSSProperties$1 {}
|
|
46
48
|
}
|
|
47
49
|
//#endregion
|
|
48
|
-
export { type AllBaseProps, type AllBasePropsWithMods, AtRuleContext, BASE_STYLES, BLOCK_INNER_STYLES, BLOCK_OUTER_STYLES, BLOCK_STYLES, type BaseProps, type BasePropsWithoutChildren, BaseStyleProps, BlockInnerStyleProps, BlockOuterStyleProps, BlockStyleProps, Bucket, CHUNK_NAMES, COLOR_STYLES, CONTAINER_STYLES, CSSMap, CSSProperties, CUSTOM_UNITS, CacheMetrics, ChunkInfo, ChunkName, ColorSpace, ColorStyleProps, ConditionNode, ConfigTokenValue, ConfigTokens, ContainerStyleProps, DIMENSION_STYLES, DIRECTIONS, DimensionStyleProps, DisposeFunction, Element, type ElementsDefinition, FLOW_STYLES, FlowStyleProps, GlobalStyledProps, INNER_STYLES, InjectResult, InnerStyleProps, KeyframesCacheEntry, KeyframesInfo, KeyframesResult, KeyframesSteps, type ModPropDef, type ModPropsInput, ModValue, Mods, NoType, NotSelector, OUTER_STYLES, OuterStyleProps, POSITION_STYLES, ParseStateKeyOptions, ParsedAdvancedState, ParsedColor, ParserOptions, PositionStyleProps, ProcessedStyle, PropertyDefinition, PropertyOptions, Props, RawCSSResult, RawStyleHandler, RecipeStyles, RenderResult, type ResolveModPropDef, type ResolveModProps, RootRegistry, RuleInfo, STYLE_TO_CHUNK, Selector, SheetInfo, SheetManager, ShortGridStyles, StateParserContext, StyleDetails, StyleDetailsPart, StyleHandler, StyleHandlerDefinition, StyleHandlerResult, StyleInjector, StyleInjectorConfig, StyleMap, StyleParser, StylePropValue, StyleResult, StyleRule, StyleValue, StyleValueStateMap, Styles, StylesInterface, StylesWithoutSelectors, type SubElementDefinition, type SubElementProps, SuffixForSelector, TEXT_STYLES, TagName, TastyConfig, type TastyElementOptions, type TastyElementProps, TastyExtensionConfig, TastyNamedColors, TastyPlugin, TastyPluginFactory, TastyPresetNames, type TastyProps, TastyThemeNames, TextStyleProps, TokenValue, Tokens, TypographyPreset, UnitHandler, type UsePropertyOptions, type UseStylesOptions, type UseStylesResult, type VariantMap, type WithVariant, allocateClassName, categorizeStyleKeys, cleanup, color, configure, createInjector, createStateParserContext, customFunc, deprecationWarning, destroy, dotize, filterBaseProps, filterMods, generateTypographyTokens, getConfig, getCssText, getCssTextForNode, getDisplayName, getGlobalFuncs, getGlobalKeyframes, getGlobalParser, getGlobalPredefinedStates, getGlobalPredefinedTokens, getGlobalRecipes, getIsTestEnvironment, getNamedColorHex, getRawCSSText, getRgbValuesFromRgbaString, hasGlobalKeyframes, hasGlobalRecipes, hasStylesGenerated, hexToRgb, hslToRgbValues, inject, injectGlobal, injectRawCSS, injector, isConfigLocked, isPropertyDefined, isSelector, isTestEnvironment, keyframes, mergeStyles, _modAttrs as modAttrs, normalizeColorTokenValue, okhslFunc, okhslPlugin, parseColor, parseStateKey, parseStyle, processTokens, property, renderStyles, resetConfig, resetGlobalPredefinedTokens, resolveRecipes, setGlobalPredefinedStates, setGlobalPredefinedTokens, strToRgb, stringifyStyles, stringifyTokens, styleHandlers, tasty, tastyDebug, trackRef, useGlobalStyles, useKeyframes, useProperty, useRawCSS, useStyles, warn };
|
|
50
|
+
export { type AllBaseProps, type AllBasePropsWithMods, AtRuleContext, BASE_STYLES, BLOCK_INNER_STYLES, BLOCK_OUTER_STYLES, BLOCK_STYLES, type BaseProps, type BasePropsWithoutChildren, BaseStyleProps, BlockInnerStyleProps, BlockOuterStyleProps, BlockStyleProps, Bucket, CHUNK_NAMES, COLOR_STYLES, CONTAINER_STYLES, CSSMap, CSSProperties, CUSTOM_UNITS, CacheMetrics, ChunkInfo, ChunkName, ColorSpace, ColorStyleProps, ConditionNode, ConfigTokenValue, ConfigTokens, ContainerStyleProps, CounterStyleDescriptors, DIMENSION_STYLES, DIRECTIONS, DimensionStyleProps, DisposeFunction, Element, type ElementsDefinition, FLOW_STYLES, FlowStyleProps, FontFaceDescriptors, FontFaceInput, GlobalStyledProps, INNER_STYLES, InjectResult, InnerStyleProps, KeyframesCacheEntry, KeyframesInfo, KeyframesResult, KeyframesSteps, type ModPropDef, type ModPropsInput, ModValue, Mods, NoType, NotSelector, OUTER_STYLES, OuterStyleProps, POSITION_STYLES, ParseStateKeyOptions, ParsedAdvancedState, ParsedColor, ParserOptions, PositionStyleProps, ProcessedStyle, PropertyDefinition, PropertyOptions, Props, RawCSSResult, RawStyleHandler, RecipeStyles, RenderResult, type ResolveModPropDef, type ResolveModProps, RootRegistry, RuleInfo, STYLE_TO_CHUNK, Selector, SheetInfo, SheetManager, ShortGridStyles, StateParserContext, StyleDetails, StyleDetailsPart, StyleHandler, StyleHandlerDefinition, StyleHandlerResult, StyleInjector, StyleInjectorConfig, StyleMap, StyleParser, StylePropValue, StyleResult, StyleRule, StyleValue, StyleValueStateMap, Styles, StylesInterface, StylesWithoutSelectors, type SubElementDefinition, type SubElementProps, SuffixForSelector, TEXT_STYLES, TagName, TastyConfig, type TastyElementOptions, type TastyElementProps, TastyExtensionConfig, TastyNamedColors, TastyPlugin, TastyPluginFactory, TastyPresetNames, type TastyProps, TastyThemeNames, TextStyleProps, TokenValue, Tokens, TypographyPreset, UnitHandler, type UsePropertyOptions, type UseStylesOptions, type UseStylesResult, type VariantMap, type WithVariant, allocateClassName, categorizeStyleKeys, cleanup, color, configure, counterStyle, createInjector, createStateParserContext, customFunc, deprecationWarning, destroy, dotize, filterBaseProps, filterMods, fontFace, generateTypographyTokens, getConfig, getCssText, getCssTextForNode, getDisplayName, getGlobalCounterStyle, getGlobalFontFace, getGlobalFuncs, getGlobalKeyframes, getGlobalParser, getGlobalPredefinedStates, getGlobalPredefinedTokens, getGlobalRecipes, getIsTestEnvironment, getNamedColorHex, getRawCSSText, getRgbValuesFromRgbaString, hasGlobalKeyframes, hasGlobalRecipes, hasStylesGenerated, hexToRgb, hslToRgbValues, inject, injectGlobal, injectRawCSS, injector, isConfigLocked, isPropertyDefined, isSelector, isTestEnvironment, keyframes, mergeStyles, _modAttrs as modAttrs, normalizeColorTokenValue, okhslFunc, okhslPlugin, parseColor, parseStateKey, parseStyle, processTokens, property, renderStyles, resetConfig, resetGlobalPredefinedTokens, resolveRecipes, setGlobalPredefinedStates, setGlobalPredefinedTokens, strToRgb, stringifyStyles, stringifyTokens, styleHandlers, tasty, tastyDebug, trackRef, useCounterStyle, useFontFace, useGlobalStyles, useKeyframes, useProperty, useRawCSS, useStyles, warn };
|
|
49
51
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -10,10 +10,10 @@ import { StyleInjector } from "./injector/injector.js";
|
|
|
10
10
|
import { createStateParserContext, getGlobalPredefinedStates, setGlobalPredefinedStates } from "./states/index.js";
|
|
11
11
|
import { parseStateKey } from "./pipeline/parseStateKey.js";
|
|
12
12
|
import { isSelector, renderStyles } from "./pipeline/index.js";
|
|
13
|
-
import { configure, getConfig, getGlobalKeyframes, getGlobalRecipes, hasGlobalKeyframes, hasGlobalRecipes, hasStylesGenerated, isConfigLocked, isTestEnvironment, resetConfig } from "./config.js";
|
|
13
|
+
import { configure, getConfig, getGlobalCounterStyle, getGlobalFontFace, getGlobalKeyframes, getGlobalRecipes, hasGlobalKeyframes, hasGlobalRecipes, hasStylesGenerated, isConfigLocked, isTestEnvironment, resetConfig } from "./config.js";
|
|
14
14
|
import { CHUNK_NAMES, STYLE_TO_CHUNK, categorizeStyleKeys } from "./chunks/definitions.js";
|
|
15
15
|
import { BASE_STYLES, BLOCK_INNER_STYLES, BLOCK_OUTER_STYLES, BLOCK_STYLES, COLOR_STYLES, CONTAINER_STYLES, DIMENSION_STYLES, FLOW_STYLES, INNER_STYLES, OUTER_STYLES, POSITION_STYLES, TEXT_STYLES } from "./styles/list.js";
|
|
16
|
-
import { allocateClassName, cleanup, createInjector, destroy, getCssText, getCssTextForNode, getIsTestEnvironment, getRawCSSText, inject, injectGlobal, injectRawCSS, injector, isPropertyDefined, keyframes, property, trackRef } from "./injector/index.js";
|
|
16
|
+
import { allocateClassName, cleanup, counterStyle, createInjector, destroy, fontFace, getCssText, getCssTextForNode, getIsTestEnvironment, getRawCSSText, inject, injectGlobal, injectRawCSS, injector, isPropertyDefined, keyframes, property, trackRef } from "./injector/index.js";
|
|
17
17
|
import { filterBaseProps } from "./utils/filter-base-props.js";
|
|
18
18
|
import { color } from "./utils/colors.js";
|
|
19
19
|
import { _modAttrs } from "./utils/mod-attrs.js";
|
|
@@ -30,5 +30,7 @@ import { useGlobalStyles } from "./hooks/useGlobalStyles.js";
|
|
|
30
30
|
import { useRawCSS } from "./hooks/useRawCSS.js";
|
|
31
31
|
import { useKeyframes } from "./hooks/useKeyframes.js";
|
|
32
32
|
import { useProperty } from "./hooks/useProperty.js";
|
|
33
|
+
import { useFontFace } from "./hooks/useFontFace.js";
|
|
34
|
+
import { useCounterStyle } from "./hooks/useCounterStyle.js";
|
|
33
35
|
|
|
34
|
-
export { BASE_STYLES, BLOCK_INNER_STYLES, BLOCK_OUTER_STYLES, BLOCK_STYLES, Bucket, CHUNK_NAMES, COLOR_STYLES, CONTAINER_STYLES, CUSTOM_UNITS, DIMENSION_STYLES, DIRECTIONS, Element, FLOW_STYLES, INNER_STYLES, OUTER_STYLES, POSITION_STYLES, STYLE_TO_CHUNK, SheetManager, StyleInjector, StyleParser, TEXT_STYLES, allocateClassName, categorizeStyleKeys, cleanup, color, configure, createInjector, createStateParserContext, customFunc, deprecationWarning, destroy, dotize, filterBaseProps, filterMods, generateTypographyTokens, getConfig, getCssText, getCssTextForNode, getDisplayName, getGlobalFuncs, getGlobalKeyframes, getGlobalParser, getGlobalPredefinedStates, getGlobalPredefinedTokens, getGlobalRecipes, getIsTestEnvironment, getNamedColorHex, getRawCSSText, getRgbValuesFromRgbaString, hasGlobalKeyframes, hasGlobalRecipes, hasStylesGenerated, hexToRgb, hslToRgbValues, inject, injectGlobal, injectRawCSS, injector, isConfigLocked, isPropertyDefined, isSelector, isTestEnvironment, keyframes, mergeStyles, _modAttrs as modAttrs, normalizeColorTokenValue, okhslFunc, okhslPlugin, parseColor, parseStateKey, parseStyle, processTokens, property, renderStyles, resetConfig, resetGlobalPredefinedTokens, resolveRecipes, setGlobalPredefinedStates, setGlobalPredefinedTokens, strToRgb, stringifyStyles, stringifyTokens, styleHandlers, tasty, tastyDebug, trackRef, useGlobalStyles, useKeyframes, useProperty, useRawCSS, useStyles, warn };
|
|
36
|
+
export { BASE_STYLES, BLOCK_INNER_STYLES, BLOCK_OUTER_STYLES, BLOCK_STYLES, Bucket, CHUNK_NAMES, COLOR_STYLES, CONTAINER_STYLES, CUSTOM_UNITS, DIMENSION_STYLES, DIRECTIONS, Element, FLOW_STYLES, INNER_STYLES, OUTER_STYLES, POSITION_STYLES, STYLE_TO_CHUNK, SheetManager, StyleInjector, StyleParser, TEXT_STYLES, allocateClassName, categorizeStyleKeys, cleanup, color, configure, counterStyle, createInjector, createStateParserContext, customFunc, deprecationWarning, destroy, dotize, filterBaseProps, filterMods, fontFace, generateTypographyTokens, getConfig, getCssText, getCssTextForNode, getDisplayName, getGlobalCounterStyle, getGlobalFontFace, getGlobalFuncs, getGlobalKeyframes, getGlobalParser, getGlobalPredefinedStates, getGlobalPredefinedTokens, getGlobalRecipes, getIsTestEnvironment, getNamedColorHex, getRawCSSText, getRgbValuesFromRgbaString, hasGlobalKeyframes, hasGlobalRecipes, hasStylesGenerated, hexToRgb, hslToRgbValues, inject, injectGlobal, injectRawCSS, injector, isConfigLocked, isPropertyDefined, isSelector, isTestEnvironment, keyframes, mergeStyles, _modAttrs as modAttrs, normalizeColorTokenValue, okhslFunc, okhslPlugin, parseColor, parseStateKey, parseStyle, processTokens, property, renderStyles, resetConfig, resetGlobalPredefinedTokens, resolveRecipes, setGlobalPredefinedStates, setGlobalPredefinedTokens, strToRgb, stringifyStyles, stringifyTokens, styleHandlers, tasty, tastyDebug, trackRef, useCounterStyle, useFontFace, useGlobalStyles, useKeyframes, useProperty, useRawCSS, useStyles, warn };
|
package/dist/injector/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CacheMetrics, DisposeFunction, GlobalInjectResult, InjectResult, KeyframesCacheEntry, KeyframesInfo, KeyframesResult, KeyframesSteps, PropertyDefinition, RawCSSResult, RootRegistry, RuleInfo, SheetInfo, StyleInjectorConfig, StyleRule } from "./types.js";
|
|
1
|
+
import { CacheMetrics, CounterStyleDescriptors, DisposeFunction, FontFaceDescriptors, FontFaceInput, GlobalInjectResult, InjectResult, KeyframesCacheEntry, KeyframesInfo, KeyframesResult, KeyframesSteps, PropertyDefinition, RawCSSResult, RootRegistry, RuleInfo, SheetInfo, StyleInjectorConfig, StyleRule } from "./types.js";
|
|
2
2
|
import { StyleResult } from "../pipeline/index.js";
|
|
3
3
|
import { SheetManager } from "./sheet-manager.js";
|
|
4
4
|
import { StyleInjector } from "./injector.js";
|
|
@@ -125,6 +125,24 @@ declare function property(name: string, options?: PropertyOptions): void;
|
|
|
125
125
|
declare function isPropertyDefined(name: string, options?: {
|
|
126
126
|
root?: Document | ShadowRoot;
|
|
127
127
|
}): boolean;
|
|
128
|
+
/**
|
|
129
|
+
* Inject a CSS @font-face rule.
|
|
130
|
+
*
|
|
131
|
+
* Permanent and global — no dispose or ref-counting.
|
|
132
|
+
* Deduplicates by content hash (family + descriptors).
|
|
133
|
+
*/
|
|
134
|
+
declare function fontFace(family: string, descriptors: FontFaceDescriptors, options?: {
|
|
135
|
+
root?: Document | ShadowRoot;
|
|
136
|
+
}): void;
|
|
137
|
+
/**
|
|
138
|
+
* Inject a CSS @counter-style rule.
|
|
139
|
+
*
|
|
140
|
+
* Permanent and global — no dispose or ref-counting.
|
|
141
|
+
* Deduplicates by name (first definition wins).
|
|
142
|
+
*/
|
|
143
|
+
declare function counterStyle(name: string, descriptors: CounterStyleDescriptors, options?: {
|
|
144
|
+
root?: Document | ShadowRoot;
|
|
145
|
+
}): void;
|
|
128
146
|
/**
|
|
129
147
|
* Get CSS text from all sheets (for SSR)
|
|
130
148
|
*/
|
|
@@ -161,5 +179,5 @@ declare function destroy(root?: Document | ShadowRoot): void;
|
|
|
161
179
|
*/
|
|
162
180
|
declare function createInjector(config?: Partial<StyleInjectorConfig>): StyleInjector;
|
|
163
181
|
//#endregion
|
|
164
|
-
export { PropertyOptions, allocateClassName, cleanup, createInjector, destroy, getCssText, getCssTextForNode, getIsTestEnvironment, getRawCSSText, inject, injectGlobal, injectRawCSS, injector, isPropertyDefined, keyframes, property, trackRef };
|
|
182
|
+
export { PropertyOptions, allocateClassName, cleanup, counterStyle, createInjector, destroy, fontFace, getCssText, getCssTextForNode, getIsTestEnvironment, getRawCSSText, inject, injectGlobal, injectRawCSS, injector, isPropertyDefined, keyframes, property, trackRef };
|
|
165
183
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/injector/index.js
CHANGED
|
@@ -101,6 +101,24 @@ function isPropertyDefined(name, options) {
|
|
|
101
101
|
return getGlobalInjector().isPropertyDefined(name, options);
|
|
102
102
|
}
|
|
103
103
|
/**
|
|
104
|
+
* Inject a CSS @font-face rule.
|
|
105
|
+
*
|
|
106
|
+
* Permanent and global — no dispose or ref-counting.
|
|
107
|
+
* Deduplicates by content hash (family + descriptors).
|
|
108
|
+
*/
|
|
109
|
+
function fontFace(family, descriptors, options) {
|
|
110
|
+
return getGlobalInjector().fontFace(family, descriptors, options);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Inject a CSS @counter-style rule.
|
|
114
|
+
*
|
|
115
|
+
* Permanent and global — no dispose or ref-counting.
|
|
116
|
+
* Deduplicates by name (first definition wins).
|
|
117
|
+
*/
|
|
118
|
+
function counterStyle(name, descriptors, options) {
|
|
119
|
+
return getGlobalInjector().counterStyle(name, descriptors, options);
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
104
122
|
* Get CSS text from all sheets (for SSR)
|
|
105
123
|
*/
|
|
106
124
|
function getCssText(options) {
|
|
@@ -158,5 +176,5 @@ function createInjector(config = {}) {
|
|
|
158
176
|
}
|
|
159
177
|
|
|
160
178
|
//#endregion
|
|
161
|
-
export { allocateClassName, cleanup, createInjector, destroy, getCssText, getCssTextForNode, getIsTestEnvironment, getRawCSSText, inject, injectGlobal, injectRawCSS, injector, isPropertyDefined, keyframes, property, trackRef };
|
|
179
|
+
export { allocateClassName, cleanup, counterStyle, createInjector, destroy, fontFace, getCssText, getCssTextForNode, getIsTestEnvironment, getRawCSSText, inject, injectGlobal, injectRawCSS, injector, isPropertyDefined, keyframes, property, trackRef };
|
|
162
180
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/injector/index.ts"],"sourcesContent":["import {\n getConfig,\n getGlobalInjector,\n isTestEnvironment,\n markStylesGenerated,\n} from '../config';\nimport type { StyleResult } from '../pipeline';\n\nimport { StyleInjector } from './injector';\nimport type {\n GlobalInjectResult,\n InjectResult,\n KeyframesResult,\n KeyframesSteps,\n StyleInjectorConfig,\n} from './types';\n\n/**\n * Allocate a className for a cacheKey without injecting styles yet\n */\nexport function allocateClassName(\n cacheKey: string,\n options?: { root?: Document | ShadowRoot },\n): { className: string; isNewAllocation: boolean } {\n return getGlobalInjector().allocateClassName(cacheKey, options);\n}\n\n/**\n * Track a reference to an already-injected cacheKey (refCount + dispose).\n * Used on cache hits (SSR hydration or runtime reuse) where the pipeline\n * was skipped. Returns null if the cacheKey is not in the cache.\n */\nexport function trackRef(\n cacheKey: string,\n options?: { root?: Document | ShadowRoot },\n): InjectResult | null {\n return getGlobalInjector().trackRef(cacheKey, options);\n}\n\n/**\n * Inject styles and return className with dispose function\n */\nexport function inject(\n rules: StyleResult[],\n options?: { root?: Document | ShadowRoot; cacheKey?: string },\n): InjectResult {\n // Mark that styles have been generated (prevents configuration changes)\n markStylesGenerated();\n\n return getGlobalInjector().inject(rules, options);\n}\n\n/**\n * Inject global rules that should not reserve tasty class names\n */\nexport function injectGlobal(\n rules: StyleResult[],\n options?: { root?: Document | ShadowRoot },\n): GlobalInjectResult {\n return getGlobalInjector().injectGlobal(rules, options);\n}\n\n/**\n * Inject raw CSS text directly without parsing\n * This is a low-overhead method for injecting raw CSS that doesn't need tasty processing.\n * The CSS is inserted into a separate style element to avoid conflicts with tasty's chunking.\n *\n * @example\n * ```tsx\n * // Inject raw CSS\n * const { dispose } = injectRawCSS(`\n * body { margin: 0; padding: 0; }\n * .my-class { color: red; }\n * `);\n *\n * // Later, remove the injected CSS\n * dispose();\n * ```\n */\nexport function injectRawCSS(\n css: string,\n options?: { root?: Document | ShadowRoot },\n): { dispose: () => void } {\n return getGlobalInjector().injectRawCSS(css, options);\n}\n\n/**\n * Get raw CSS text for SSR\n */\nexport function getRawCSSText(options?: {\n root?: Document | ShadowRoot;\n}): string {\n return getGlobalInjector().getRawCSSText(options);\n}\n\n/**\n * Inject keyframes and return object with toString() and dispose()\n */\nexport function keyframes(\n steps: KeyframesSteps,\n nameOrOptions?: string | { root?: Document | ShadowRoot; name?: string },\n): KeyframesResult {\n return getGlobalInjector().keyframes(steps, nameOrOptions);\n}\n\nexport interface PropertyOptions {\n /**\n * CSS syntax string for the property (e.g., '<color>', '<length>', '<angle>')\n * @see https://developer.mozilla.org/en-US/docs/Web/CSS/@property/syntax\n */\n syntax?: string;\n /**\n * Whether the property inherits from parent elements\n * @default true\n */\n inherits?: boolean;\n /**\n * Initial value for the property\n */\n initialValue?: string | number;\n /**\n * Shadow root or document to inject into\n */\n root?: Document | ShadowRoot;\n}\n\n/**\n * Define a CSS @property custom property.\n * This enables advanced features like animating custom properties.\n *\n * Note: @property rules are global and persistent once defined.\n * Re-registering the same property name is a no-op.\n *\n * @param name - The custom property name (must start with --)\n * @param options - Property configuration\n *\n * @example\n * ```ts\n * // Define a color property that can be animated\n * property('--my-color', {\n * syntax: '<color>',\n * initialValue: 'red',\n * });\n *\n * // Define an angle property\n * property('--rotation', {\n * syntax: '<angle>',\n * inherits: false,\n * initialValue: '0deg',\n * });\n * ```\n */\nexport function property(name: string, options?: PropertyOptions): void {\n return getGlobalInjector().property(name, options);\n}\n\n/**\n * Check if a CSS @property has already been defined\n *\n * @param name - The custom property name to check\n * @param options - Options including root\n */\nexport function isPropertyDefined(\n name: string,\n options?: { root?: Document | ShadowRoot },\n): boolean {\n return getGlobalInjector().isPropertyDefined(name, options);\n}\n\n/**\n * Get CSS text from all sheets (for SSR)\n */\nexport function getCssText(options?: { root?: Document | ShadowRoot }): string {\n return getGlobalInjector().getCssText(options);\n}\n\n/**\n * Collect only CSS used by a rendered subtree (like jest-styled-components).\n * Pass the container returned by render(...).\n */\nexport function getCssTextForNode(\n node: ParentNode | Element | DocumentFragment,\n options?: { root?: Document | ShadowRoot },\n): string {\n // Collect tasty-generated class names (t<number>) from the subtree\n const classSet = new Set<string>();\n\n const readClasses = (el: Element) => {\n const cls = el.getAttribute('class');\n if (!cls) return;\n for (const token of cls.split(/\\s+/)) {\n if (/^t\\d+$/.test(token)) classSet.add(token);\n }\n };\n\n // Include node itself if it's an Element\n if ((node as Element).getAttribute) {\n readClasses(node as Element);\n }\n // Walk descendants\n const elements = (node as ParentNode).querySelectorAll\n ? (node as ParentNode).querySelectorAll('[class]')\n : ([] as unknown as NodeListOf<Element>);\n if (elements) elements.forEach(readClasses);\n\n return getGlobalInjector().getCssTextForClasses(classSet, options);\n}\n\n/**\n * Force cleanup of unused rules\n */\nexport function cleanup(root?: Document | ShadowRoot): void {\n return getGlobalInjector().cleanup(root);\n}\n\n/**\n * Check if we're currently running in a test environment\n */\nexport function getIsTestEnvironment(): boolean {\n return isTestEnvironment();\n}\n\n/**\n * Get the global injector instance for debugging\n */\nexport const injector = {\n get instance() {\n return getGlobalInjector();\n },\n};\n\n/**\n * Destroy all resources and clean up\n */\nexport function destroy(root?: Document | ShadowRoot): void {\n return getGlobalInjector().destroy(root);\n}\n\n/**\n * Create a new isolated injector instance\n */\nexport function createInjector(\n config: Partial<StyleInjectorConfig> = {},\n): StyleInjector {\n const defaultConfig = getConfig();\n\n const fullConfig: StyleInjectorConfig = {\n ...defaultConfig,\n // Auto-enable forceTextInjection in test environments\n forceTextInjection: config.forceTextInjection ?? isTestEnvironment(),\n ...config,\n };\n\n return new StyleInjector(fullConfig);\n}\n\n// Re-export types\nexport type {\n StyleInjectorConfig,\n InjectResult,\n DisposeFunction,\n RuleInfo,\n SheetInfo,\n RootRegistry,\n StyleRule,\n KeyframesInfo,\n KeyframesResult,\n KeyframesSteps,\n KeyframesCacheEntry,\n CacheMetrics,\n RawCSSResult,\n PropertyDefinition,\n} from './types';\n\nexport { StyleInjector } from './injector';\nexport { SheetManager } from './sheet-manager';\n"],"mappings":";;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/injector/index.ts"],"sourcesContent":["import {\n getConfig,\n getGlobalInjector,\n isTestEnvironment,\n markStylesGenerated,\n} from '../config';\nimport type { StyleResult } from '../pipeline';\n\nimport { StyleInjector } from './injector';\nimport type {\n CounterStyleDescriptors,\n FontFaceDescriptors,\n GlobalInjectResult,\n InjectResult,\n KeyframesResult,\n KeyframesSteps,\n StyleInjectorConfig,\n} from './types';\n\n/**\n * Allocate a className for a cacheKey without injecting styles yet\n */\nexport function allocateClassName(\n cacheKey: string,\n options?: { root?: Document | ShadowRoot },\n): { className: string; isNewAllocation: boolean } {\n return getGlobalInjector().allocateClassName(cacheKey, options);\n}\n\n/**\n * Track a reference to an already-injected cacheKey (refCount + dispose).\n * Used on cache hits (SSR hydration or runtime reuse) where the pipeline\n * was skipped. Returns null if the cacheKey is not in the cache.\n */\nexport function trackRef(\n cacheKey: string,\n options?: { root?: Document | ShadowRoot },\n): InjectResult | null {\n return getGlobalInjector().trackRef(cacheKey, options);\n}\n\n/**\n * Inject styles and return className with dispose function\n */\nexport function inject(\n rules: StyleResult[],\n options?: { root?: Document | ShadowRoot; cacheKey?: string },\n): InjectResult {\n // Mark that styles have been generated (prevents configuration changes)\n markStylesGenerated();\n\n return getGlobalInjector().inject(rules, options);\n}\n\n/**\n * Inject global rules that should not reserve tasty class names\n */\nexport function injectGlobal(\n rules: StyleResult[],\n options?: { root?: Document | ShadowRoot },\n): GlobalInjectResult {\n return getGlobalInjector().injectGlobal(rules, options);\n}\n\n/**\n * Inject raw CSS text directly without parsing\n * This is a low-overhead method for injecting raw CSS that doesn't need tasty processing.\n * The CSS is inserted into a separate style element to avoid conflicts with tasty's chunking.\n *\n * @example\n * ```tsx\n * // Inject raw CSS\n * const { dispose } = injectRawCSS(`\n * body { margin: 0; padding: 0; }\n * .my-class { color: red; }\n * `);\n *\n * // Later, remove the injected CSS\n * dispose();\n * ```\n */\nexport function injectRawCSS(\n css: string,\n options?: { root?: Document | ShadowRoot },\n): { dispose: () => void } {\n return getGlobalInjector().injectRawCSS(css, options);\n}\n\n/**\n * Get raw CSS text for SSR\n */\nexport function getRawCSSText(options?: {\n root?: Document | ShadowRoot;\n}): string {\n return getGlobalInjector().getRawCSSText(options);\n}\n\n/**\n * Inject keyframes and return object with toString() and dispose()\n */\nexport function keyframes(\n steps: KeyframesSteps,\n nameOrOptions?: string | { root?: Document | ShadowRoot; name?: string },\n): KeyframesResult {\n return getGlobalInjector().keyframes(steps, nameOrOptions);\n}\n\nexport interface PropertyOptions {\n /**\n * CSS syntax string for the property (e.g., '<color>', '<length>', '<angle>')\n * @see https://developer.mozilla.org/en-US/docs/Web/CSS/@property/syntax\n */\n syntax?: string;\n /**\n * Whether the property inherits from parent elements\n * @default true\n */\n inherits?: boolean;\n /**\n * Initial value for the property\n */\n initialValue?: string | number;\n /**\n * Shadow root or document to inject into\n */\n root?: Document | ShadowRoot;\n}\n\n/**\n * Define a CSS @property custom property.\n * This enables advanced features like animating custom properties.\n *\n * Note: @property rules are global and persistent once defined.\n * Re-registering the same property name is a no-op.\n *\n * @param name - The custom property name (must start with --)\n * @param options - Property configuration\n *\n * @example\n * ```ts\n * // Define a color property that can be animated\n * property('--my-color', {\n * syntax: '<color>',\n * initialValue: 'red',\n * });\n *\n * // Define an angle property\n * property('--rotation', {\n * syntax: '<angle>',\n * inherits: false,\n * initialValue: '0deg',\n * });\n * ```\n */\nexport function property(name: string, options?: PropertyOptions): void {\n return getGlobalInjector().property(name, options);\n}\n\n/**\n * Check if a CSS @property has already been defined\n *\n * @param name - The custom property name to check\n * @param options - Options including root\n */\nexport function isPropertyDefined(\n name: string,\n options?: { root?: Document | ShadowRoot },\n): boolean {\n return getGlobalInjector().isPropertyDefined(name, options);\n}\n\n/**\n * Inject a CSS @font-face rule.\n *\n * Permanent and global — no dispose or ref-counting.\n * Deduplicates by content hash (family + descriptors).\n */\nexport function fontFace(\n family: string,\n descriptors: FontFaceDescriptors,\n options?: { root?: Document | ShadowRoot },\n): void {\n return getGlobalInjector().fontFace(family, descriptors, options);\n}\n\n/**\n * Inject a CSS @counter-style rule.\n *\n * Permanent and global — no dispose or ref-counting.\n * Deduplicates by name (first definition wins).\n */\nexport function counterStyle(\n name: string,\n descriptors: CounterStyleDescriptors,\n options?: { root?: Document | ShadowRoot },\n): void {\n return getGlobalInjector().counterStyle(name, descriptors, options);\n}\n\n/**\n * Get CSS text from all sheets (for SSR)\n */\nexport function getCssText(options?: { root?: Document | ShadowRoot }): string {\n return getGlobalInjector().getCssText(options);\n}\n\n/**\n * Collect only CSS used by a rendered subtree (like jest-styled-components).\n * Pass the container returned by render(...).\n */\nexport function getCssTextForNode(\n node: ParentNode | Element | DocumentFragment,\n options?: { root?: Document | ShadowRoot },\n): string {\n // Collect tasty-generated class names (t<number>) from the subtree\n const classSet = new Set<string>();\n\n const readClasses = (el: Element) => {\n const cls = el.getAttribute('class');\n if (!cls) return;\n for (const token of cls.split(/\\s+/)) {\n if (/^t\\d+$/.test(token)) classSet.add(token);\n }\n };\n\n // Include node itself if it's an Element\n if ((node as Element).getAttribute) {\n readClasses(node as Element);\n }\n // Walk descendants\n const elements = (node as ParentNode).querySelectorAll\n ? (node as ParentNode).querySelectorAll('[class]')\n : ([] as unknown as NodeListOf<Element>);\n if (elements) elements.forEach(readClasses);\n\n return getGlobalInjector().getCssTextForClasses(classSet, options);\n}\n\n/**\n * Force cleanup of unused rules\n */\nexport function cleanup(root?: Document | ShadowRoot): void {\n return getGlobalInjector().cleanup(root);\n}\n\n/**\n * Check if we're currently running in a test environment\n */\nexport function getIsTestEnvironment(): boolean {\n return isTestEnvironment();\n}\n\n/**\n * Get the global injector instance for debugging\n */\nexport const injector = {\n get instance() {\n return getGlobalInjector();\n },\n};\n\n/**\n * Destroy all resources and clean up\n */\nexport function destroy(root?: Document | ShadowRoot): void {\n return getGlobalInjector().destroy(root);\n}\n\n/**\n * Create a new isolated injector instance\n */\nexport function createInjector(\n config: Partial<StyleInjectorConfig> = {},\n): StyleInjector {\n const defaultConfig = getConfig();\n\n const fullConfig: StyleInjectorConfig = {\n ...defaultConfig,\n // Auto-enable forceTextInjection in test environments\n forceTextInjection: config.forceTextInjection ?? isTestEnvironment(),\n ...config,\n };\n\n return new StyleInjector(fullConfig);\n}\n\n// Re-export types\nexport type {\n StyleInjectorConfig,\n InjectResult,\n DisposeFunction,\n RuleInfo,\n SheetInfo,\n RootRegistry,\n StyleRule,\n KeyframesInfo,\n KeyframesResult,\n KeyframesSteps,\n KeyframesCacheEntry,\n CacheMetrics,\n RawCSSResult,\n PropertyDefinition,\n FontFaceDescriptors,\n FontFaceInput,\n CounterStyleDescriptors,\n} from './types';\n\nexport { StyleInjector } from './injector';\nexport { SheetManager } from './sheet-manager';\n"],"mappings":";;;;;;;;AAsBA,SAAgB,kBACd,UACA,SACiD;AACjD,QAAO,mBAAmB,CAAC,kBAAkB,UAAU,QAAQ;;;;;;;AAQjE,SAAgB,SACd,UACA,SACqB;AACrB,QAAO,mBAAmB,CAAC,SAAS,UAAU,QAAQ;;;;;AAMxD,SAAgB,OACd,OACA,SACc;AAEd,sBAAqB;AAErB,QAAO,mBAAmB,CAAC,OAAO,OAAO,QAAQ;;;;;AAMnD,SAAgB,aACd,OACA,SACoB;AACpB,QAAO,mBAAmB,CAAC,aAAa,OAAO,QAAQ;;;;;;;;;;;;;;;;;;;AAoBzD,SAAgB,aACd,KACA,SACyB;AACzB,QAAO,mBAAmB,CAAC,aAAa,KAAK,QAAQ;;;;;AAMvD,SAAgB,cAAc,SAEnB;AACT,QAAO,mBAAmB,CAAC,cAAc,QAAQ;;;;;AAMnD,SAAgB,UACd,OACA,eACiB;AACjB,QAAO,mBAAmB,CAAC,UAAU,OAAO,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkD5D,SAAgB,SAAS,MAAc,SAAiC;AACtE,QAAO,mBAAmB,CAAC,SAAS,MAAM,QAAQ;;;;;;;;AASpD,SAAgB,kBACd,MACA,SACS;AACT,QAAO,mBAAmB,CAAC,kBAAkB,MAAM,QAAQ;;;;;;;;AAS7D,SAAgB,SACd,QACA,aACA,SACM;AACN,QAAO,mBAAmB,CAAC,SAAS,QAAQ,aAAa,QAAQ;;;;;;;;AASnE,SAAgB,aACd,MACA,aACA,SACM;AACN,QAAO,mBAAmB,CAAC,aAAa,MAAM,aAAa,QAAQ;;;;;AAMrE,SAAgB,WAAW,SAAoD;AAC7E,QAAO,mBAAmB,CAAC,WAAW,QAAQ;;;;;;AAOhD,SAAgB,kBACd,MACA,SACQ;CAER,MAAM,2BAAW,IAAI,KAAa;CAElC,MAAM,eAAe,OAAgB;EACnC,MAAM,MAAM,GAAG,aAAa,QAAQ;AACpC,MAAI,CAAC,IAAK;AACV,OAAK,MAAM,SAAS,IAAI,MAAM,MAAM,CAClC,KAAI,SAAS,KAAK,MAAM,CAAE,UAAS,IAAI,MAAM;;AAKjD,KAAK,KAAiB,aACpB,aAAY,KAAgB;CAG9B,MAAM,WAAY,KAAoB,mBACjC,KAAoB,iBAAiB,UAAU,GAC/C,EAAE;AACP,KAAI,SAAU,UAAS,QAAQ,YAAY;AAE3C,QAAO,mBAAmB,CAAC,qBAAqB,UAAU,QAAQ;;;;;AAMpE,SAAgB,QAAQ,MAAoC;AAC1D,QAAO,mBAAmB,CAAC,QAAQ,KAAK;;;;;AAM1C,SAAgB,uBAAgC;AAC9C,QAAO,mBAAmB;;;;;AAM5B,MAAa,WAAW,EACtB,IAAI,WAAW;AACb,QAAO,mBAAmB;GAE7B;;;;AAKD,SAAgB,QAAQ,MAAoC;AAC1D,QAAO,mBAAmB,CAAC,QAAQ,KAAK;;;;;AAM1C,SAAgB,eACd,SAAuC,EAAE,EAC1B;AAUf,QAAO,IAAI,cAP6B;EACtC,GAHoB,WAAW;EAK/B,oBAAoB,OAAO,sBAAsB,mBAAmB;EACpE,GAAG;EACJ,CAEmC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CacheMetrics, GlobalInjectResult, InjectResult, KeyframesResult, KeyframesSteps, PropertyDefinition, RawCSSResult, StyleInjectorConfig } from "./types.js";
|
|
1
|
+
import { CacheMetrics, CounterStyleDescriptors, FontFaceDescriptors, GlobalInjectResult, InjectResult, KeyframesResult, KeyframesSteps, PropertyDefinition, RawCSSResult, StyleInjectorConfig } from "./types.js";
|
|
2
2
|
import { StyleResult } from "../pipeline/index.js";
|
|
3
3
|
import { SheetManager } from "./sheet-manager.js";
|
|
4
4
|
|
|
@@ -121,6 +121,24 @@ declare class StyleInjector {
|
|
|
121
121
|
isPropertyDefined(name: string, options?: {
|
|
122
122
|
root?: Document | ShadowRoot;
|
|
123
123
|
}): boolean;
|
|
124
|
+
/**
|
|
125
|
+
* Inject a CSS @font-face rule.
|
|
126
|
+
*
|
|
127
|
+
* Permanent and global — no dispose or ref-counting.
|
|
128
|
+
* Deduplicates by content hash (family + descriptors).
|
|
129
|
+
*/
|
|
130
|
+
fontFace(family: string, descriptors: FontFaceDescriptors, options?: {
|
|
131
|
+
root?: Document | ShadowRoot;
|
|
132
|
+
}): void;
|
|
133
|
+
/**
|
|
134
|
+
* Inject a CSS @counter-style rule.
|
|
135
|
+
*
|
|
136
|
+
* Permanent and global — no dispose or ref-counting.
|
|
137
|
+
* Deduplicates by name (first definition wins).
|
|
138
|
+
*/
|
|
139
|
+
counterStyle(name: string, descriptors: CounterStyleDescriptors, options?: {
|
|
140
|
+
root?: Document | ShadowRoot;
|
|
141
|
+
}): void;
|
|
124
142
|
/**
|
|
125
143
|
* Inject keyframes and return object with toString() and dispose()
|
|
126
144
|
*
|
|
@@ -2,6 +2,8 @@ import { getEffectiveDefinition, normalizePropertyDefinition } from "../properti
|
|
|
2
2
|
import { isDevEnv } from "../utils/is-dev-env.js";
|
|
3
3
|
import { parseStyle } from "../utils/styles.js";
|
|
4
4
|
import { SheetManager } from "./sheet-manager.js";
|
|
5
|
+
import { fontFaceContentHash, formatFontFaceDeclarations } from "../font-face/index.js";
|
|
6
|
+
import { formatCounterStyleDeclarations } from "../counter-style/index.js";
|
|
5
7
|
|
|
6
8
|
//#region src/injector/injector.ts
|
|
7
9
|
/**
|
|
@@ -333,6 +335,39 @@ var StyleInjector = class {
|
|
|
333
335
|
return registry.injectedProperties.has(effectiveResult.cssName);
|
|
334
336
|
}
|
|
335
337
|
/**
|
|
338
|
+
* Inject a CSS @font-face rule.
|
|
339
|
+
*
|
|
340
|
+
* Permanent and global — no dispose or ref-counting.
|
|
341
|
+
* Deduplicates by content hash (family + descriptors).
|
|
342
|
+
*/
|
|
343
|
+
fontFace(family, descriptors, options) {
|
|
344
|
+
const root = options?.root || document;
|
|
345
|
+
const registry = this.sheetManager.getRegistry(root);
|
|
346
|
+
const hash = fontFaceContentHash(family, descriptors);
|
|
347
|
+
if (registry.injectedFontFaces.has(hash)) return;
|
|
348
|
+
const rule = {
|
|
349
|
+
selector: "@font-face",
|
|
350
|
+
declarations: formatFontFaceDeclarations(family, descriptors)
|
|
351
|
+
};
|
|
352
|
+
if (this.sheetManager.insertGlobalRule(registry, [rule], `fontface:${hash}`, root)) registry.injectedFontFaces.add(hash);
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Inject a CSS @counter-style rule.
|
|
356
|
+
*
|
|
357
|
+
* Permanent and global — no dispose or ref-counting.
|
|
358
|
+
* Deduplicates by name (first definition wins).
|
|
359
|
+
*/
|
|
360
|
+
counterStyle(name, descriptors, options) {
|
|
361
|
+
const root = options?.root || document;
|
|
362
|
+
const registry = this.sheetManager.getRegistry(root);
|
|
363
|
+
if (registry.injectedCounterStyles.has(name)) return;
|
|
364
|
+
const rule = {
|
|
365
|
+
selector: `@counter-style ${name}`,
|
|
366
|
+
declarations: formatCounterStyleDeclarations(descriptors)
|
|
367
|
+
};
|
|
368
|
+
if (this.sheetManager.insertGlobalRule(registry, [rule], `counterstyle:${name}`, root)) registry.injectedCounterStyles.add(name);
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
336
371
|
* Inject keyframes and return object with toString() and dispose()
|
|
337
372
|
*
|
|
338
373
|
* Keyframes are cached by content (steps). If the same content is injected
|