@tenphi/tasty 3.1.0 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/README.md +1 -0
  2. package/dist/{babel-R2qT7yLN.d.ts → babel-BUQGeOXA.d.ts} +2 -2
  3. package/dist/{collector-D7yzmG5G.js → collector-BNQJyxFh.js} +3 -3
  4. package/dist/{collector-D7yzmG5G.js.map → collector-BNQJyxFh.js.map} +1 -1
  5. package/dist/{collector-D8o4Wdq-.d.ts → collector-DUaHCcTS.d.ts} +2 -2
  6. package/dist/{config-De8L9NWM.d.ts → config-YsxGv4tq.d.ts} +101 -10
  7. package/dist/{config-CwQ-fAsp.js → config-zkrtb424.js} +739 -960
  8. package/dist/config-zkrtb424.js.map +1 -0
  9. package/dist/core/index.d.ts +5 -5
  10. package/dist/core/index.js +6 -6
  11. package/dist/{core-CqSh853z.js → core-Bf48Z1I-.js} +57 -41
  12. package/dist/core-Bf48Z1I-.js.map +1 -0
  13. package/dist/{css-writer-dS1srTkS.js → css-writer-B-SvwNbq.js} +3 -3
  14. package/dist/{css-writer-dS1srTkS.js.map → css-writer-B-SvwNbq.js.map} +1 -1
  15. package/dist/{format-rules-CaW4lJGg.js → format-rules-Co21uwA3.js} +5 -20
  16. package/dist/format-rules-Co21uwA3.js.map +1 -0
  17. package/dist/{hydrate-uFv9kx7G.js → hydrate-D38TyhAG.js} +2 -2
  18. package/dist/{hydrate-uFv9kx7G.js.map → hydrate-D38TyhAG.js.map} +1 -1
  19. package/dist/{index-KUYya3x7.d.ts → index-Cd45t5NM.d.ts} +108 -3
  20. package/dist/{index-DzGxoeyN.d.ts → index-DhhUI0yi.d.ts} +63 -12
  21. package/dist/index.d.ts +5 -5
  22. package/dist/index.js +62 -8
  23. package/dist/index.js.map +1 -1
  24. package/dist/{keyframes-DaZhjqkd.js → keyframes-mDAB6pLf.js} +2 -2
  25. package/dist/{keyframes-DaZhjqkd.js.map → keyframes-mDAB6pLf.js.map} +1 -1
  26. package/dist/{merge-styles-H8LFJ5HY.js → merge-styles-CFwtEHzv.js} +2 -2
  27. package/dist/{merge-styles-H8LFJ5HY.js.map → merge-styles-CFwtEHzv.js.map} +1 -1
  28. package/dist/{merge-styles-DLm4wdnb.d.ts → merge-styles-CU7JbEwg.d.ts} +2 -2
  29. package/dist/{resolve-recipes-aN94fjqS.js → resolve-recipes-B8pIVinB.js} +3 -3
  30. package/dist/{resolve-recipes-aN94fjqS.js.map → resolve-recipes-B8pIVinB.js.map} +1 -1
  31. package/dist/ssr/astro-client.js +1 -1
  32. package/dist/ssr/astro.js +3 -3
  33. package/dist/ssr/index.d.ts +1 -1
  34. package/dist/ssr/index.js +3 -3
  35. package/dist/ssr/next.d.ts +1 -1
  36. package/dist/ssr/next.js +4 -4
  37. package/dist/static/index.d.ts +2 -2
  38. package/dist/static/index.js +1 -1
  39. package/dist/zero/babel.d.ts +1 -1
  40. package/dist/zero/babel.js +4 -4
  41. package/dist/zero/index.d.ts +1 -1
  42. package/dist/zero/index.js +1 -1
  43. package/dist/zero/next.d.ts +1 -1
  44. package/docs/configuration.md +195 -15
  45. package/docs/dsl.md +28 -6
  46. package/docs/injector.md +11 -0
  47. package/docs/methodology.md +1 -1
  48. package/docs/pipeline.md +1 -4
  49. package/docs/react-api.md +1 -1
  50. package/docs/styles.md +6 -1
  51. package/package.json +7 -6
  52. package/dist/config-CwQ-fAsp.js.map +0 -1
  53. package/dist/core-CqSh853z.js.map +0 -1
  54. package/dist/format-rules-CaW4lJGg.js.map +0 -1
package/README.md CHANGED
@@ -556,6 +556,7 @@ Run `pnpm bench` to reproduce. `pnpm bench:browser` runs the component-render be
556
556
  - Style normalization guarantees equivalent style input resolves to the same chunks, improving deduplication hit rates.
557
557
  - A style garbage collector removes unused styles/chunks over time.
558
558
  - A dedicated style injector minimizes DOM/style-tag overhead.
559
+ - Optional [batched injection](docs/configuration.md#batched-injection) collapses many `insertRule()` calls into one style invalidation per commit, which matters when components measure layout during render.
559
560
  - This approach is validated in enterprise-scale apps where runtime styling overhead is not noticeable in normal UI flows.
560
561
 
561
562
  ## Ecosystem
@@ -1,4 +1,4 @@
1
- import { t as TastyConfig } from "./config-De8L9NWM.js";
1
+ import { t as TastyConfig } from "./config-YsxGv4tq.js";
2
2
  import { PluginPass } from "@babel/core";
3
3
 
4
4
  //#region src/zero/babel-types.d.ts
@@ -80,4 +80,4 @@ interface TastyZeroBabelOptions {
80
80
  declare const _default: (api: object, options: TastyZeroBabelOptions | null | undefined, dirname: string) => import("@babel/core").PluginObj<PluginPass>;
81
81
  //#endregion
82
82
  export { _default as n, TastyZeroConfig as r, TastyZeroBabelOptions as t };
83
- //# sourceMappingURL=babel-R2qT7yLN.d.ts.map
83
+ //# sourceMappingURL=babel-BUQGeOXA.d.ts.map
@@ -1,5 +1,5 @@
1
- import { Dt as formatFunctionRule, L as renderStyles, X as fontFaceContentHash, Z as formatFontFaceRule, a as getGlobalCounterStyles, ct as makeCounterStyleName, d as getGlobalStyles, dt as validateNamePrefix, f as getNamePrefix, ft as hashString, i as getGlobalConfigTokens, kt as parseFunctionName, lt as makeKeyframeName, o as getGlobalFontFaces, q as formatCounterStyleRule, r as getEffectiveProperties, s as getGlobalFunctions, st as makeClassName } from "./config-CwQ-fAsp.js";
2
- import { n as formatPropertyCSS, t as formatRules } from "./format-rules-CaW4lJGg.js";
1
+ import { L as renderStyles, Mt as formatFunctionRule, Pt as parseFunctionName, X as fontFaceContentHash, Z as formatFontFaceRule, _t as hashString, a as getGlobalCounterStyles, d as getGlobalStyles, f as getNamePrefix, ft as makeClassName, gt as validateNamePrefix, i as getGlobalConfigTokens, mt as makeKeyframeName, o as getGlobalFontFaces, pt as makeCounterStyleName, q as formatCounterStyleRule, r as getEffectiveProperties, s as getGlobalFunctions } from "./config-zkrtb424.js";
2
+ import { n as formatPropertyCSS, t as formatRules } from "./format-rules-Co21uwA3.js";
3
3
  import { t as formatGlobalRules } from "./format-global-rules-DklyaXv-.js";
4
4
  //#region src/ssr/collector.ts
5
5
  /**
@@ -301,4 +301,4 @@ function createServerStyleCollector(namePrefix) {
301
301
  //#endregion
302
302
  export { createServerStyleCollector as n, ServerStyleCollector as t };
303
303
 
304
- //# sourceMappingURL=collector-D7yzmG5G.js.map
304
+ //# sourceMappingURL=collector-BNQJyxFh.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"collector-D7yzmG5G.js","names":[],"sources":["../src/ssr/collector.ts"],"sourcesContent":["/**\n * ServerStyleCollector — server-safe style collector for SSR.\n *\n * Accumulates CSS rules and cache metadata during server rendering.\n * This is the server-side counterpart to StyleInjector: it allocates\n * hash-based class names using the configured `namePrefix` (defaults\n * to `'t'`), formats CSS rules into text, and tracks rendered class\n * names for lightweight client transfer.\n *\n * One instance is created per HTTP request. Concurrent requests\n * each get their own collector (via AsyncLocalStorage or React context).\n */\n\nimport {\n getEffectiveProperties,\n getGlobalStyles,\n getGlobalCounterStyles,\n getGlobalFontFaces,\n getGlobalFunctions,\n getGlobalConfigTokens,\n getNamePrefix,\n} from '../config';\nimport { formatCounterStyleRule } from '../counter-style';\nimport { fontFaceContentHash, formatFontFaceRule } from '../font-face';\nimport { formatFunctionRule, parseFunctionName } from '../functions';\nimport { renderStyles } from '../pipeline';\nimport type { StyleResult } from '../pipeline';\nimport { hashString } from '../utils/hash';\nimport {\n makeClassName,\n makeCounterStyleName,\n makeKeyframeName,\n validateNamePrefix,\n} from '../utils/name-prefix';\nimport { formatPropertyCSS } from './format-property';\nimport { formatGlobalRules } from './format-global-rules';\nimport { formatRules } from './format-rules';\n\nexport class ServerStyleCollector {\n private chunks = new Map<string, string>();\n private cacheKeyToClassName = new Map<string, string>();\n private flushedKeys = new Set<string>();\n private propertyRules = new Map<string, string>();\n private flushedPropertyKeys = new Set<string>();\n private keyframeRules = new Map<string, string>();\n private flushedKeyframeKeys = new Set<string>();\n private globalStyles = new Map<string, string>();\n private flushedGlobalKeys = new Set<string>();\n private rawCSS = new Map<string, string>();\n private flushedRawKeys = new Set<string>();\n private fontFaceRules = new Map<string, string>();\n private flushedFontFaceKeys = new Set<string>();\n private counterStyleRules = new Map<string, string>();\n private flushedCounterStyleKeys = new Set<string>();\n private functionRules = new Map<string, string>();\n private flushedFunctionKeys = new Set<string>();\n private keyframesCounter = 0;\n private counterStyleCounter = 0;\n private internalsCollected = false;\n private namePrefix: string;\n\n /**\n * @param namePrefix - Optional override for the configured prefix.\n * Defaults to the value from `configure({ namePrefix })` (or `'t'`).\n * Pass an explicit prefix when constructing a collector outside the\n * normal configure() lifecycle (e.g. in tests). Validated eagerly\n * so misconfiguration fails before any CSS is collected.\n */\n constructor(namePrefix?: string) {\n if (namePrefix !== undefined) {\n validateNamePrefix(namePrefix);\n }\n this.namePrefix = namePrefix ?? getNamePrefix();\n }\n\n private generateClassName(cacheKey: string): string {\n return makeClassName(this.namePrefix, hashString(cacheKey));\n }\n\n /**\n * Collect internal @property rules and :root token defaults.\n * Mirrors markStylesGenerated() from the client-side injector.\n * Called automatically on first chunk collection; idempotent.\n *\n * Internals are always emitted here — the RSC path deliberately\n * defers to SSR so that tokens appear exactly once per page in\n * <style data-tasty-ssr> (avoiding duplication of large token sets).\n */\n collectInternals(): void {\n if (this.internalsCollected) return;\n this.internalsCollected = true;\n\n for (const [token, definition] of Object.entries(\n getEffectiveProperties(),\n )) {\n const css = formatPropertyCSS(token, definition);\n if (css) {\n this.collectProperty(`__prop:${token}`, css);\n }\n }\n\n const tokenStyles = getGlobalConfigTokens();\n if (tokenStyles && Object.keys(tokenStyles).length > 0) {\n const tokenRules = renderStyles(tokenStyles, ':root') as StyleResult[];\n if (tokenRules.length > 0) {\n const css = formatGlobalRules(tokenRules);\n if (css) {\n this.collectGlobalStyles('__global:tokens', css);\n }\n }\n }\n\n const globalFF = getGlobalFontFaces();\n if (globalFF) {\n for (const [family, input] of Object.entries(globalFF)) {\n const descriptors = Array.isArray(input) ? input : [input];\n for (const desc of descriptors) {\n const hash = fontFaceContentHash(family, desc);\n const css = formatFontFaceRule(family, desc);\n this.collectFontFace(hash, css);\n }\n }\n }\n\n const globalCS = getGlobalCounterStyles();\n if (globalCS) {\n for (const [name, descriptors] of Object.entries(globalCS)) {\n const css = formatCounterStyleRule(name, descriptors);\n this.collectCounterStyle(name, css, { weak: true });\n }\n }\n\n const globalFn = getGlobalFunctions();\n if (globalFn) {\n for (const [name, definition] of Object.entries(globalFn)) {\n const css = formatFunctionRule(name, definition);\n this.collectFunction(parseFunctionName(name), css, { weak: true });\n }\n }\n\n const globalStyles = getGlobalStyles();\n if (globalStyles) {\n for (const [selector, styles] of Object.entries(globalStyles)) {\n if (Object.keys(styles).length > 0) {\n const rules = renderStyles(styles, selector) as StyleResult[];\n if (rules.length > 0) {\n const css = formatGlobalRules(rules);\n if (css) {\n this.collectGlobalStyles(`__global:styles:${selector}`, css);\n }\n }\n }\n }\n }\n }\n\n /**\n * Allocate a className for a cache key, server-side.\n * Mirrors StyleInjector.allocateClassName but without DOM access.\n */\n allocateClassName(cacheKey: string): {\n className: string;\n isNewAllocation: boolean;\n } {\n const existing = this.cacheKeyToClassName.get(cacheKey);\n if (existing) {\n return { className: existing, isNewAllocation: false };\n }\n\n const className = this.generateClassName(cacheKey);\n this.cacheKeyToClassName.set(cacheKey, className);\n\n return { className, isNewAllocation: true };\n }\n\n /**\n * Record CSS rules for a chunk.\n * Called by useStyles during server render.\n */\n collectChunk(\n cacheKey: string,\n className: string,\n rules: StyleResult[],\n ): void {\n if (this.chunks.has(cacheKey)) return;\n const css = formatRules(rules, className);\n if (css) {\n this.chunks.set(cacheKey, css);\n }\n }\n\n /**\n * Record a @property rule. Deduplicated by name.\n */\n collectProperty(name: string, css: string): void {\n if (!this.propertyRules.has(name)) {\n this.propertyRules.set(name, css);\n }\n }\n\n /**\n * Record a @keyframes rule. Deduplicated by name.\n */\n collectKeyframes(name: string, css: string): void {\n if (!this.keyframeRules.has(name)) {\n this.keyframeRules.set(name, css);\n }\n }\n\n /**\n * Allocate a keyframe name for SSR. Uses provided name or generates one.\n */\n allocateKeyframeName(providedName?: string): string {\n return (\n providedName ??\n makeKeyframeName(this.namePrefix, String(this.keyframesCounter++))\n );\n }\n\n /**\n * Record a @font-face rule. Deduplicated by key (content hash).\n */\n collectFontFace(key: string, css: string): void {\n if (!this.fontFaceRules.has(key)) {\n this.fontFaceRules.set(key, css);\n }\n }\n\n /**\n * Record a @counter-style rule. Deduplicated by name and overrides an\n * existing rule by default. Pass `weak: true` for global `configure()`\n * definitions, which never clobber an existing rule.\n */\n collectCounterStyle(\n name: string,\n css: string,\n options?: { weak?: boolean },\n ): void {\n const existing = this.counterStyleRules.get(name);\n if (existing === undefined) {\n this.counterStyleRules.set(name, css);\n return;\n }\n if (options?.weak || existing === css) return;\n this.counterStyleRules.set(name, css);\n // If a rule with this name was already flushed (streaming), allow the\n // overriding rule to be flushed again so it wins by source order.\n this.flushedCounterStyleKeys.delete(name);\n }\n\n /**\n * Record a @function rule. Deduplicated by CSS function name and overrides an\n * existing rule by default. Pass `weak: true` for global `configure()`\n * definitions, which never clobber an existing rule.\n */\n collectFunction(\n name: string,\n css: string,\n options?: { weak?: boolean },\n ): void {\n const existing = this.functionRules.get(name);\n if (existing === undefined) {\n this.functionRules.set(name, css);\n return;\n }\n if (options?.weak || existing === css) return;\n this.functionRules.set(name, css);\n // If a rule with this name was already flushed (streaming), allow the\n // overriding rule to be flushed again so it wins by source order.\n this.flushedFunctionKeys.delete(name);\n }\n\n /**\n * Allocate a counter-style name for SSR. Uses provided name or generates one.\n */\n allocateCounterStyleName(providedName?: string): string {\n return (\n providedName ??\n makeCounterStyleName(this.namePrefix, String(this.counterStyleCounter++))\n );\n }\n\n /**\n * Record global styles (from useGlobalStyles). Deduplicated by key.\n *\n * Pass `replace` for slot-keyed entries (an explicit `id`), where the last\n * write must win to match the client's update-tracking behavior.\n */\n collectGlobalStyles(key: string, css: string, replace?: boolean): void {\n if (replace || !this.globalStyles.has(key)) {\n this.globalStyles.set(key, css);\n }\n }\n\n /**\n * Record raw CSS text (from useRawCSS). Deduplicated by key.\n *\n * Pass `replace` for slot-keyed entries (an explicit `id`), where the last\n * write must win to match the client's update-tracking behavior.\n */\n collectRawCSS(key: string, css: string, replace?: boolean): void {\n if (replace || !this.rawCSS.has(key)) {\n this.rawCSS.set(key, css);\n }\n }\n\n /**\n * Extract all CSS collected so far as a single string.\n * Includes @property and @keyframes rules.\n * Used for non-streaming SSR (renderToString).\n */\n getCSS(): string {\n const parts: string[] = [];\n\n for (const css of this.propertyRules.values()) {\n parts.push(css);\n }\n\n for (const css of this.fontFaceRules.values()) {\n parts.push(css);\n }\n\n for (const css of this.counterStyleRules.values()) {\n parts.push(css);\n }\n\n for (const css of this.functionRules.values()) {\n parts.push(css);\n }\n\n for (const css of this.rawCSS.values()) {\n parts.push(css);\n }\n\n for (const css of this.globalStyles.values()) {\n parts.push(css);\n }\n\n for (const css of this.chunks.values()) {\n parts.push(css);\n }\n\n for (const css of this.keyframeRules.values()) {\n parts.push(css);\n }\n\n return parts.join('\\n');\n }\n\n /**\n * Flush only newly collected CSS since the last flush.\n * Used for streaming SSR (renderToPipeableStream + useServerInsertedHTML).\n */\n flushCSS(): string {\n const parts: string[] = [];\n\n for (const [name, css] of this.propertyRules) {\n if (!this.flushedPropertyKeys.has(name)) {\n parts.push(css);\n this.flushedPropertyKeys.add(name);\n }\n }\n\n for (const [key, css] of this.fontFaceRules) {\n if (!this.flushedFontFaceKeys.has(key)) {\n parts.push(css);\n this.flushedFontFaceKeys.add(key);\n }\n }\n\n for (const [key, css] of this.counterStyleRules) {\n if (!this.flushedCounterStyleKeys.has(key)) {\n parts.push(css);\n this.flushedCounterStyleKeys.add(key);\n }\n }\n\n for (const [key, css] of this.functionRules) {\n if (!this.flushedFunctionKeys.has(key)) {\n parts.push(css);\n this.flushedFunctionKeys.add(key);\n }\n }\n\n for (const [key, css] of this.rawCSS) {\n if (!this.flushedRawKeys.has(key)) {\n parts.push(css);\n this.flushedRawKeys.add(key);\n }\n }\n\n for (const [key, css] of this.globalStyles) {\n if (!this.flushedGlobalKeys.has(key)) {\n parts.push(css);\n this.flushedGlobalKeys.add(key);\n }\n }\n\n for (const [key, css] of this.chunks) {\n if (!this.flushedKeys.has(key)) {\n parts.push(css);\n this.flushedKeys.add(key);\n }\n }\n\n for (const [name, css] of this.keyframeRules) {\n if (!this.flushedKeyframeKeys.has(name)) {\n parts.push(css);\n this.flushedKeyframeKeys.add(name);\n }\n }\n\n return parts.join('\\n');\n }\n\n private flushedClassNames = new Set<string>();\n\n /**\n * Return class names rendered since the last call (for streaming).\n * Used to emit lightweight class-list scripts for client hydration.\n */\n getRenderedClassNames(): string[] {\n const names: string[] = [];\n for (const className of this.cacheKeyToClassName.values()) {\n if (!this.flushedClassNames.has(className)) {\n this.flushedClassNames.add(className);\n names.push(className);\n }\n }\n return names;\n }\n}\n\n/**\n * Factory for creating a {@link ServerStyleCollector} instance.\n *\n * Canonical functional entry point; the `ServerStyleCollector` class remains\n * exported for advanced/internal use.\n *\n * @param namePrefix - Optional override for the configured class-name prefix.\n * Defaults to the value from `configure({ namePrefix })` (or `'t'`).\n *\n * @example\n * ```ts\n * import { createServerStyleCollector } from '@tenphi/tasty/ssr';\n *\n * const collector = createServerStyleCollector();\n * ```\n */\nexport function createServerStyleCollector(\n namePrefix?: string,\n): ServerStyleCollector {\n return new ServerStyleCollector(namePrefix);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"collector-BNQJyxFh.js","names":[],"sources":["../src/ssr/collector.ts"],"sourcesContent":["/**\n * ServerStyleCollector — server-safe style collector for SSR.\n *\n * Accumulates CSS rules and cache metadata during server rendering.\n * This is the server-side counterpart to StyleInjector: it allocates\n * hash-based class names using the configured `namePrefix` (defaults\n * to `'t'`), formats CSS rules into text, and tracks rendered class\n * names for lightweight client transfer.\n *\n * One instance is created per HTTP request. Concurrent requests\n * each get their own collector (via AsyncLocalStorage or React context).\n */\n\nimport {\n getEffectiveProperties,\n getGlobalStyles,\n getGlobalCounterStyles,\n getGlobalFontFaces,\n getGlobalFunctions,\n getGlobalConfigTokens,\n getNamePrefix,\n} from '../config';\nimport { formatCounterStyleRule } from '../counter-style';\nimport { fontFaceContentHash, formatFontFaceRule } from '../font-face';\nimport { formatFunctionRule, parseFunctionName } from '../functions';\nimport { renderStyles } from '../pipeline';\nimport type { StyleResult } from '../pipeline';\nimport { hashString } from '../utils/hash';\nimport {\n makeClassName,\n makeCounterStyleName,\n makeKeyframeName,\n validateNamePrefix,\n} from '../utils/name-prefix';\nimport { formatPropertyCSS } from './format-property';\nimport { formatGlobalRules } from './format-global-rules';\nimport { formatRules } from './format-rules';\n\nexport class ServerStyleCollector {\n private chunks = new Map<string, string>();\n private cacheKeyToClassName = new Map<string, string>();\n private flushedKeys = new Set<string>();\n private propertyRules = new Map<string, string>();\n private flushedPropertyKeys = new Set<string>();\n private keyframeRules = new Map<string, string>();\n private flushedKeyframeKeys = new Set<string>();\n private globalStyles = new Map<string, string>();\n private flushedGlobalKeys = new Set<string>();\n private rawCSS = new Map<string, string>();\n private flushedRawKeys = new Set<string>();\n private fontFaceRules = new Map<string, string>();\n private flushedFontFaceKeys = new Set<string>();\n private counterStyleRules = new Map<string, string>();\n private flushedCounterStyleKeys = new Set<string>();\n private functionRules = new Map<string, string>();\n private flushedFunctionKeys = new Set<string>();\n private keyframesCounter = 0;\n private counterStyleCounter = 0;\n private internalsCollected = false;\n private namePrefix: string;\n\n /**\n * @param namePrefix - Optional override for the configured prefix.\n * Defaults to the value from `configure({ namePrefix })` (or `'t'`).\n * Pass an explicit prefix when constructing a collector outside the\n * normal configure() lifecycle (e.g. in tests). Validated eagerly\n * so misconfiguration fails before any CSS is collected.\n */\n constructor(namePrefix?: string) {\n if (namePrefix !== undefined) {\n validateNamePrefix(namePrefix);\n }\n this.namePrefix = namePrefix ?? getNamePrefix();\n }\n\n private generateClassName(cacheKey: string): string {\n return makeClassName(this.namePrefix, hashString(cacheKey));\n }\n\n /**\n * Collect internal @property rules and :root token defaults.\n * Mirrors markStylesGenerated() from the client-side injector.\n * Called automatically on first chunk collection; idempotent.\n *\n * Internals are always emitted here — the RSC path deliberately\n * defers to SSR so that tokens appear exactly once per page in\n * <style data-tasty-ssr> (avoiding duplication of large token sets).\n */\n collectInternals(): void {\n if (this.internalsCollected) return;\n this.internalsCollected = true;\n\n for (const [token, definition] of Object.entries(\n getEffectiveProperties(),\n )) {\n const css = formatPropertyCSS(token, definition);\n if (css) {\n this.collectProperty(`__prop:${token}`, css);\n }\n }\n\n const tokenStyles = getGlobalConfigTokens();\n if (tokenStyles && Object.keys(tokenStyles).length > 0) {\n const tokenRules = renderStyles(tokenStyles, ':root') as StyleResult[];\n if (tokenRules.length > 0) {\n const css = formatGlobalRules(tokenRules);\n if (css) {\n this.collectGlobalStyles('__global:tokens', css);\n }\n }\n }\n\n const globalFF = getGlobalFontFaces();\n if (globalFF) {\n for (const [family, input] of Object.entries(globalFF)) {\n const descriptors = Array.isArray(input) ? input : [input];\n for (const desc of descriptors) {\n const hash = fontFaceContentHash(family, desc);\n const css = formatFontFaceRule(family, desc);\n this.collectFontFace(hash, css);\n }\n }\n }\n\n const globalCS = getGlobalCounterStyles();\n if (globalCS) {\n for (const [name, descriptors] of Object.entries(globalCS)) {\n const css = formatCounterStyleRule(name, descriptors);\n this.collectCounterStyle(name, css, { weak: true });\n }\n }\n\n const globalFn = getGlobalFunctions();\n if (globalFn) {\n for (const [name, definition] of Object.entries(globalFn)) {\n const css = formatFunctionRule(name, definition);\n this.collectFunction(parseFunctionName(name), css, { weak: true });\n }\n }\n\n const globalStyles = getGlobalStyles();\n if (globalStyles) {\n for (const [selector, styles] of Object.entries(globalStyles)) {\n if (Object.keys(styles).length > 0) {\n const rules = renderStyles(styles, selector) as StyleResult[];\n if (rules.length > 0) {\n const css = formatGlobalRules(rules);\n if (css) {\n this.collectGlobalStyles(`__global:styles:${selector}`, css);\n }\n }\n }\n }\n }\n }\n\n /**\n * Allocate a className for a cache key, server-side.\n * Mirrors StyleInjector.allocateClassName but without DOM access.\n */\n allocateClassName(cacheKey: string): {\n className: string;\n isNewAllocation: boolean;\n } {\n const existing = this.cacheKeyToClassName.get(cacheKey);\n if (existing) {\n return { className: existing, isNewAllocation: false };\n }\n\n const className = this.generateClassName(cacheKey);\n this.cacheKeyToClassName.set(cacheKey, className);\n\n return { className, isNewAllocation: true };\n }\n\n /**\n * Record CSS rules for a chunk.\n * Called by useStyles during server render.\n */\n collectChunk(\n cacheKey: string,\n className: string,\n rules: StyleResult[],\n ): void {\n if (this.chunks.has(cacheKey)) return;\n const css = formatRules(rules, className);\n if (css) {\n this.chunks.set(cacheKey, css);\n }\n }\n\n /**\n * Record a @property rule. Deduplicated by name.\n */\n collectProperty(name: string, css: string): void {\n if (!this.propertyRules.has(name)) {\n this.propertyRules.set(name, css);\n }\n }\n\n /**\n * Record a @keyframes rule. Deduplicated by name.\n */\n collectKeyframes(name: string, css: string): void {\n if (!this.keyframeRules.has(name)) {\n this.keyframeRules.set(name, css);\n }\n }\n\n /**\n * Allocate a keyframe name for SSR. Uses provided name or generates one.\n */\n allocateKeyframeName(providedName?: string): string {\n return (\n providedName ??\n makeKeyframeName(this.namePrefix, String(this.keyframesCounter++))\n );\n }\n\n /**\n * Record a @font-face rule. Deduplicated by key (content hash).\n */\n collectFontFace(key: string, css: string): void {\n if (!this.fontFaceRules.has(key)) {\n this.fontFaceRules.set(key, css);\n }\n }\n\n /**\n * Record a @counter-style rule. Deduplicated by name and overrides an\n * existing rule by default. Pass `weak: true` for global `configure()`\n * definitions, which never clobber an existing rule.\n */\n collectCounterStyle(\n name: string,\n css: string,\n options?: { weak?: boolean },\n ): void {\n const existing = this.counterStyleRules.get(name);\n if (existing === undefined) {\n this.counterStyleRules.set(name, css);\n return;\n }\n if (options?.weak || existing === css) return;\n this.counterStyleRules.set(name, css);\n // If a rule with this name was already flushed (streaming), allow the\n // overriding rule to be flushed again so it wins by source order.\n this.flushedCounterStyleKeys.delete(name);\n }\n\n /**\n * Record a @function rule. Deduplicated by CSS function name and overrides an\n * existing rule by default. Pass `weak: true` for global `configure()`\n * definitions, which never clobber an existing rule.\n */\n collectFunction(\n name: string,\n css: string,\n options?: { weak?: boolean },\n ): void {\n const existing = this.functionRules.get(name);\n if (existing === undefined) {\n this.functionRules.set(name, css);\n return;\n }\n if (options?.weak || existing === css) return;\n this.functionRules.set(name, css);\n // If a rule with this name was already flushed (streaming), allow the\n // overriding rule to be flushed again so it wins by source order.\n this.flushedFunctionKeys.delete(name);\n }\n\n /**\n * Allocate a counter-style name for SSR. Uses provided name or generates one.\n */\n allocateCounterStyleName(providedName?: string): string {\n return (\n providedName ??\n makeCounterStyleName(this.namePrefix, String(this.counterStyleCounter++))\n );\n }\n\n /**\n * Record global styles (from useGlobalStyles). Deduplicated by key.\n *\n * Pass `replace` for slot-keyed entries (an explicit `id`), where the last\n * write must win to match the client's update-tracking behavior.\n */\n collectGlobalStyles(key: string, css: string, replace?: boolean): void {\n if (replace || !this.globalStyles.has(key)) {\n this.globalStyles.set(key, css);\n }\n }\n\n /**\n * Record raw CSS text (from useRawCSS). Deduplicated by key.\n *\n * Pass `replace` for slot-keyed entries (an explicit `id`), where the last\n * write must win to match the client's update-tracking behavior.\n */\n collectRawCSS(key: string, css: string, replace?: boolean): void {\n if (replace || !this.rawCSS.has(key)) {\n this.rawCSS.set(key, css);\n }\n }\n\n /**\n * Extract all CSS collected so far as a single string.\n * Includes @property and @keyframes rules.\n * Used for non-streaming SSR (renderToString).\n */\n getCSS(): string {\n const parts: string[] = [];\n\n for (const css of this.propertyRules.values()) {\n parts.push(css);\n }\n\n for (const css of this.fontFaceRules.values()) {\n parts.push(css);\n }\n\n for (const css of this.counterStyleRules.values()) {\n parts.push(css);\n }\n\n for (const css of this.functionRules.values()) {\n parts.push(css);\n }\n\n for (const css of this.rawCSS.values()) {\n parts.push(css);\n }\n\n for (const css of this.globalStyles.values()) {\n parts.push(css);\n }\n\n for (const css of this.chunks.values()) {\n parts.push(css);\n }\n\n for (const css of this.keyframeRules.values()) {\n parts.push(css);\n }\n\n return parts.join('\\n');\n }\n\n /**\n * Flush only newly collected CSS since the last flush.\n * Used for streaming SSR (renderToPipeableStream + useServerInsertedHTML).\n */\n flushCSS(): string {\n const parts: string[] = [];\n\n for (const [name, css] of this.propertyRules) {\n if (!this.flushedPropertyKeys.has(name)) {\n parts.push(css);\n this.flushedPropertyKeys.add(name);\n }\n }\n\n for (const [key, css] of this.fontFaceRules) {\n if (!this.flushedFontFaceKeys.has(key)) {\n parts.push(css);\n this.flushedFontFaceKeys.add(key);\n }\n }\n\n for (const [key, css] of this.counterStyleRules) {\n if (!this.flushedCounterStyleKeys.has(key)) {\n parts.push(css);\n this.flushedCounterStyleKeys.add(key);\n }\n }\n\n for (const [key, css] of this.functionRules) {\n if (!this.flushedFunctionKeys.has(key)) {\n parts.push(css);\n this.flushedFunctionKeys.add(key);\n }\n }\n\n for (const [key, css] of this.rawCSS) {\n if (!this.flushedRawKeys.has(key)) {\n parts.push(css);\n this.flushedRawKeys.add(key);\n }\n }\n\n for (const [key, css] of this.globalStyles) {\n if (!this.flushedGlobalKeys.has(key)) {\n parts.push(css);\n this.flushedGlobalKeys.add(key);\n }\n }\n\n for (const [key, css] of this.chunks) {\n if (!this.flushedKeys.has(key)) {\n parts.push(css);\n this.flushedKeys.add(key);\n }\n }\n\n for (const [name, css] of this.keyframeRules) {\n if (!this.flushedKeyframeKeys.has(name)) {\n parts.push(css);\n this.flushedKeyframeKeys.add(name);\n }\n }\n\n return parts.join('\\n');\n }\n\n private flushedClassNames = new Set<string>();\n\n /**\n * Return class names rendered since the last call (for streaming).\n * Used to emit lightweight class-list scripts for client hydration.\n */\n getRenderedClassNames(): string[] {\n const names: string[] = [];\n for (const className of this.cacheKeyToClassName.values()) {\n if (!this.flushedClassNames.has(className)) {\n this.flushedClassNames.add(className);\n names.push(className);\n }\n }\n return names;\n }\n}\n\n/**\n * Factory for creating a {@link ServerStyleCollector} instance.\n *\n * Canonical functional entry point; the `ServerStyleCollector` class remains\n * exported for advanced/internal use.\n *\n * @param namePrefix - Optional override for the configured class-name prefix.\n * Defaults to the value from `configure({ namePrefix })` (or `'t'`).\n *\n * @example\n * ```ts\n * import { createServerStyleCollector } from '@tenphi/tasty/ssr';\n *\n * const collector = createServerStyleCollector();\n * ```\n */\nexport function createServerStyleCollector(\n namePrefix?: string,\n): ServerStyleCollector {\n return new ServerStyleCollector(namePrefix);\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAsCA,IAAa,uBAAb,MAAkC;CAChC,yBAAiB,IAAI,IAAoB;CACzC,sCAA8B,IAAI,IAAoB;CACtD,8BAAsB,IAAI,IAAY;CACtC,gCAAwB,IAAI,IAAoB;CAChD,sCAA8B,IAAI,IAAY;CAC9C,gCAAwB,IAAI,IAAoB;CAChD,sCAA8B,IAAI,IAAY;CAC9C,+BAAuB,IAAI,IAAoB;CAC/C,oCAA4B,IAAI,IAAY;CAC5C,yBAAiB,IAAI,IAAoB;CACzC,iCAAyB,IAAI,IAAY;CACzC,gCAAwB,IAAI,IAAoB;CAChD,sCAA8B,IAAI,IAAY;CAC9C,oCAA4B,IAAI,IAAoB;CACpD,0CAAkC,IAAI,IAAY;CAClD,gCAAwB,IAAI,IAAoB;CAChD,sCAA8B,IAAI,IAAY;CAC9C,mBAA2B;CAC3B,sBAA8B;CAC9B,qBAA6B;CAC7B;;;;;;;;CASA,YAAY,YAAqB;EAC/B,IAAI,eAAe,KAAA,GACjB,mBAAmB,UAAU;EAE/B,KAAK,aAAa,cAAc,cAAc;CAChD;CAEA,kBAA0B,UAA0B;EAClD,OAAO,cAAc,KAAK,YAAY,WAAW,QAAQ,CAAC;CAC5D;;;;;;;;;;CAWA,mBAAyB;EACvB,IAAI,KAAK,oBAAoB;EAC7B,KAAK,qBAAqB;EAE1B,KAAK,MAAM,CAAC,OAAO,eAAe,OAAO,QACvC,uBAAuB,CACzB,GAAG;GACD,MAAM,MAAM,kBAAkB,OAAO,UAAU;GAC/C,IAAI,KACF,KAAK,gBAAgB,UAAU,SAAS,GAAG;EAE/C;EAEA,MAAM,cAAc,sBAAsB;EAC1C,IAAI,eAAe,OAAO,KAAK,WAAW,CAAC,CAAC,SAAS,GAAG;GACtD,MAAM,aAAa,aAAa,aAAa,OAAO;GACpD,IAAI,WAAW,SAAS,GAAG;IACzB,MAAM,MAAM,kBAAkB,UAAU;IACxC,IAAI,KACF,KAAK,oBAAoB,mBAAmB,GAAG;GAEnD;EACF;EAEA,MAAM,WAAW,mBAAmB;EACpC,IAAI,UACF,KAAK,MAAM,CAAC,QAAQ,UAAU,OAAO,QAAQ,QAAQ,GAAG;GACtD,MAAM,cAAc,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;GACzD,KAAK,MAAM,QAAQ,aAAa;IAC9B,MAAM,OAAO,oBAAoB,QAAQ,IAAI;IAC7C,MAAM,MAAM,mBAAmB,QAAQ,IAAI;IAC3C,KAAK,gBAAgB,MAAM,GAAG;GAChC;EACF;EAGF,MAAM,WAAW,uBAAuB;EACxC,IAAI,UACF,KAAK,MAAM,CAAC,MAAM,gBAAgB,OAAO,QAAQ,QAAQ,GAAG;GAC1D,MAAM,MAAM,uBAAuB,MAAM,WAAW;GACpD,KAAK,oBAAoB,MAAM,KAAK,EAAE,MAAM,KAAK,CAAC;EACpD;EAGF,MAAM,WAAW,mBAAmB;EACpC,IAAI,UACF,KAAK,MAAM,CAAC,MAAM,eAAe,OAAO,QAAQ,QAAQ,GAAG;GACzD,MAAM,MAAM,mBAAmB,MAAM,UAAU;GAC/C,KAAK,gBAAgB,kBAAkB,IAAI,GAAG,KAAK,EAAE,MAAM,KAAK,CAAC;EACnE;EAGF,MAAM,eAAe,gBAAgB;EACrC,IAAI;QACG,MAAM,CAAC,UAAU,WAAW,OAAO,QAAQ,YAAY,GAC1D,IAAI,OAAO,KAAK,MAAM,CAAC,CAAC,SAAS,GAAG;IAClC,MAAM,QAAQ,aAAa,QAAQ,QAAQ;IAC3C,IAAI,MAAM,SAAS,GAAG;KACpB,MAAM,MAAM,kBAAkB,KAAK;KACnC,IAAI,KACF,KAAK,oBAAoB,mBAAmB,YAAY,GAAG;IAE/D;GACF;;CAGN;;;;;CAMA,kBAAkB,UAGhB;EACA,MAAM,WAAW,KAAK,oBAAoB,IAAI,QAAQ;EACtD,IAAI,UACF,OAAO;GAAE,WAAW;GAAU,iBAAiB;EAAM;EAGvD,MAAM,YAAY,KAAK,kBAAkB,QAAQ;EACjD,KAAK,oBAAoB,IAAI,UAAU,SAAS;EAEhD,OAAO;GAAE;GAAW,iBAAiB;EAAK;CAC5C;;;;;CAMA,aACE,UACA,WACA,OACM;EACN,IAAI,KAAK,OAAO,IAAI,QAAQ,GAAG;EAC/B,MAAM,MAAM,YAAY,OAAO,SAAS;EACxC,IAAI,KACF,KAAK,OAAO,IAAI,UAAU,GAAG;CAEjC;;;;CAKA,gBAAgB,MAAc,KAAmB;EAC/C,IAAI,CAAC,KAAK,cAAc,IAAI,IAAI,GAC9B,KAAK,cAAc,IAAI,MAAM,GAAG;CAEpC;;;;CAKA,iBAAiB,MAAc,KAAmB;EAChD,IAAI,CAAC,KAAK,cAAc,IAAI,IAAI,GAC9B,KAAK,cAAc,IAAI,MAAM,GAAG;CAEpC;;;;CAKA,qBAAqB,cAA+B;EAClD,OACE,gBACA,iBAAiB,KAAK,YAAY,OAAO,KAAK,kBAAkB,CAAC;CAErE;;;;CAKA,gBAAgB,KAAa,KAAmB;EAC9C,IAAI,CAAC,KAAK,cAAc,IAAI,GAAG,GAC7B,KAAK,cAAc,IAAI,KAAK,GAAG;CAEnC;;;;;;CAOA,oBACE,MACA,KACA,SACM;EACN,MAAM,WAAW,KAAK,kBAAkB,IAAI,IAAI;EAChD,IAAI,aAAa,KAAA,GAAW;GAC1B,KAAK,kBAAkB,IAAI,MAAM,GAAG;GACpC;EACF;EACA,IAAI,SAAS,QAAQ,aAAa,KAAK;EACvC,KAAK,kBAAkB,IAAI,MAAM,GAAG;EAGpC,KAAK,wBAAwB,OAAO,IAAI;CAC1C;;;;;;CAOA,gBACE,MACA,KACA,SACM;EACN,MAAM,WAAW,KAAK,cAAc,IAAI,IAAI;EAC5C,IAAI,aAAa,KAAA,GAAW;GAC1B,KAAK,cAAc,IAAI,MAAM,GAAG;GAChC;EACF;EACA,IAAI,SAAS,QAAQ,aAAa,KAAK;EACvC,KAAK,cAAc,IAAI,MAAM,GAAG;EAGhC,KAAK,oBAAoB,OAAO,IAAI;CACtC;;;;CAKA,yBAAyB,cAA+B;EACtD,OACE,gBACA,qBAAqB,KAAK,YAAY,OAAO,KAAK,qBAAqB,CAAC;CAE5E;;;;;;;CAQA,oBAAoB,KAAa,KAAa,SAAyB;EACrE,IAAI,WAAW,CAAC,KAAK,aAAa,IAAI,GAAG,GACvC,KAAK,aAAa,IAAI,KAAK,GAAG;CAElC;;;;;;;CAQA,cAAc,KAAa,KAAa,SAAyB;EAC/D,IAAI,WAAW,CAAC,KAAK,OAAO,IAAI,GAAG,GACjC,KAAK,OAAO,IAAI,KAAK,GAAG;CAE5B;;;;;;CAOA,SAAiB;EACf,MAAM,QAAkB,CAAC;EAEzB,KAAK,MAAM,OAAO,KAAK,cAAc,OAAO,GAC1C,MAAM,KAAK,GAAG;EAGhB,KAAK,MAAM,OAAO,KAAK,cAAc,OAAO,GAC1C,MAAM,KAAK,GAAG;EAGhB,KAAK,MAAM,OAAO,KAAK,kBAAkB,OAAO,GAC9C,MAAM,KAAK,GAAG;EAGhB,KAAK,MAAM,OAAO,KAAK,cAAc,OAAO,GAC1C,MAAM,KAAK,GAAG;EAGhB,KAAK,MAAM,OAAO,KAAK,OAAO,OAAO,GACnC,MAAM,KAAK,GAAG;EAGhB,KAAK,MAAM,OAAO,KAAK,aAAa,OAAO,GACzC,MAAM,KAAK,GAAG;EAGhB,KAAK,MAAM,OAAO,KAAK,OAAO,OAAO,GACnC,MAAM,KAAK,GAAG;EAGhB,KAAK,MAAM,OAAO,KAAK,cAAc,OAAO,GAC1C,MAAM,KAAK,GAAG;EAGhB,OAAO,MAAM,KAAK,IAAI;CACxB;;;;;CAMA,WAAmB;EACjB,MAAM,QAAkB,CAAC;EAEzB,KAAK,MAAM,CAAC,MAAM,QAAQ,KAAK,eAC7B,IAAI,CAAC,KAAK,oBAAoB,IAAI,IAAI,GAAG;GACvC,MAAM,KAAK,GAAG;GACd,KAAK,oBAAoB,IAAI,IAAI;EACnC;EAGF,KAAK,MAAM,CAAC,KAAK,QAAQ,KAAK,eAC5B,IAAI,CAAC,KAAK,oBAAoB,IAAI,GAAG,GAAG;GACtC,MAAM,KAAK,GAAG;GACd,KAAK,oBAAoB,IAAI,GAAG;EAClC;EAGF,KAAK,MAAM,CAAC,KAAK,QAAQ,KAAK,mBAC5B,IAAI,CAAC,KAAK,wBAAwB,IAAI,GAAG,GAAG;GAC1C,MAAM,KAAK,GAAG;GACd,KAAK,wBAAwB,IAAI,GAAG;EACtC;EAGF,KAAK,MAAM,CAAC,KAAK,QAAQ,KAAK,eAC5B,IAAI,CAAC,KAAK,oBAAoB,IAAI,GAAG,GAAG;GACtC,MAAM,KAAK,GAAG;GACd,KAAK,oBAAoB,IAAI,GAAG;EAClC;EAGF,KAAK,MAAM,CAAC,KAAK,QAAQ,KAAK,QAC5B,IAAI,CAAC,KAAK,eAAe,IAAI,GAAG,GAAG;GACjC,MAAM,KAAK,GAAG;GACd,KAAK,eAAe,IAAI,GAAG;EAC7B;EAGF,KAAK,MAAM,CAAC,KAAK,QAAQ,KAAK,cAC5B,IAAI,CAAC,KAAK,kBAAkB,IAAI,GAAG,GAAG;GACpC,MAAM,KAAK,GAAG;GACd,KAAK,kBAAkB,IAAI,GAAG;EAChC;EAGF,KAAK,MAAM,CAAC,KAAK,QAAQ,KAAK,QAC5B,IAAI,CAAC,KAAK,YAAY,IAAI,GAAG,GAAG;GAC9B,MAAM,KAAK,GAAG;GACd,KAAK,YAAY,IAAI,GAAG;EAC1B;EAGF,KAAK,MAAM,CAAC,MAAM,QAAQ,KAAK,eAC7B,IAAI,CAAC,KAAK,oBAAoB,IAAI,IAAI,GAAG;GACvC,MAAM,KAAK,GAAG;GACd,KAAK,oBAAoB,IAAI,IAAI;EACnC;EAGF,OAAO,MAAM,KAAK,IAAI;CACxB;CAEA,oCAA4B,IAAI,IAAY;;;;;CAM5C,wBAAkC;EAChC,MAAM,QAAkB,CAAC;EACzB,KAAK,MAAM,aAAa,KAAK,oBAAoB,OAAO,GACtD,IAAI,CAAC,KAAK,kBAAkB,IAAI,SAAS,GAAG;GAC1C,KAAK,kBAAkB,IAAI,SAAS;GACpC,MAAM,KAAK,SAAS;EACtB;EAEF,OAAO;CACT;AACF;;;;;;;;;;;;;;;;;AAkBA,SAAgB,2BACd,YACsB;CACtB,OAAO,IAAI,qBAAqB,UAAU;AAC5C"}
@@ -1,4 +1,4 @@
1
- import { n as StyleResult } from "./index-KUYya3x7.js";
1
+ import { n as StyleResult } from "./index-Cd45t5NM.js";
2
2
 
3
3
  //#region src/ssr/collector.d.ts
4
4
  declare class ServerStyleCollector {
@@ -142,4 +142,4 @@ declare class ServerStyleCollector {
142
142
  declare function createServerStyleCollector(namePrefix?: string): ServerStyleCollector;
143
143
  //#endregion
144
144
  export { createServerStyleCollector as n, ServerStyleCollector as t };
145
- //# sourceMappingURL=collector-D8o4Wdq-.d.ts.map
145
+ //# sourceMappingURL=collector-DUaHCcTS.d.ts.map
@@ -1,4 +1,4 @@
1
- import { Dt as SheetInfo, Et as RuleInfo, Ot as StyleInjectorConfig, P as StyleHandlerDefinition, St as PropertyDefinition, Tt as RootRegistry, b as Styles, bt as KeyframesResult, dt as FunctionDefinition, gt as InjectResult, h as ConfigTokens, ht as GlobalInjectResult, it as UnitHandler, kt as StyleRule, lt as FontFaceDescriptors, mt as GCOptions, n as StyleResult, nt as StyleDetails, ot as CacheMetrics, pt as GCConfig, st as CounterStyleDescriptors, ut as FontFaceInput, v as RecipeStyles, wt as RawCSSResult, xt as KeyframesSteps, yt as KeyframesInfo } from "./index-KUYya3x7.js";
1
+ import { Dt as SheetInfo, Et as RuleInfo, Ot as StyleInjectorConfig, P as StyleHandlerDefinition, St as PropertyDefinition, Tt as RootRegistry, b as Styles, bt as KeyframesResult, dt as FunctionDefinition, gt as InjectResult, h as ConfigTokens, ht as GlobalInjectResult, it as UnitHandler, kt as StyleRule, lt as FontFaceDescriptors, mt as GCOptions, n as StyleResult, nt as StyleDetails, ot as CacheMetrics, pt as GCConfig, st as CounterStyleDescriptors, ut as FontFaceInput, v as RecipeStyles, wt as RawCSSResult, xt as KeyframesSteps, yt as KeyframesInfo } from "./index-Cd45t5NM.js";
2
2
 
3
3
  //#region src/prop-handlers.d.ts
4
4
  /**
@@ -243,6 +243,36 @@ declare class StyleInjector {
243
243
  private rscClassRegex;
244
244
  /** @internal — exposed for debug utilities only */
245
245
  get _sheetManager(): SheetManager;
246
+ /**
247
+ * Whether sheet writes should be queued instead of applied immediately.
248
+ *
249
+ * Only ever true on the client: SSR collects CSS as text and the RSC path
250
+ * returns it as strings, so neither has a live sheet to batch writes against.
251
+ *
252
+ * In the default `true` mode a write is only queued inside an open batch
253
+ * window — a commit in which `<TastyBatchProvider>` rendered and will
254
+ * therefore flush in its insertion effect, before any layout effect can
255
+ * measure. Everything else falls through to a synchronous write, so enabling
256
+ * the flag cannot make a `useLayoutEffect` read an unstyled element.
257
+ * `'always'` drops the gate and accepts that trade for wider coverage.
258
+ */
259
+ private get batching();
260
+ /**
261
+ * Apply a sheet write now, or queue it when batching is on.
262
+ * Returns the queue handle when deferred, so the caller can cancel it if it
263
+ * disposes before the flush.
264
+ */
265
+ private writeSheet;
266
+ /**
267
+ * Insert a global (non-class) rule, honouring batching.
268
+ *
269
+ * `onApplied` records the caller's dedupe bookkeeping. When the write is
270
+ * queued it runs eagerly, so a repeat call before the flush bails out instead
271
+ * of queueing the same rule twice — the same reasoning as
272
+ * `insertPropertyRule`'s eager marking. When written synchronously it runs
273
+ * only on success, preserving the existing retry-on-failure behaviour.
274
+ */
275
+ private writeGlobalRule;
246
276
  constructor(config?: StyleInjectorConfig);
247
277
  /**
248
278
  * Generate a deterministic class name from a cache key using content hash.
@@ -470,6 +500,22 @@ type ParseFunction = (groups: StyleDetails[]) => string;
470
500
  type FunctionsConfig = Record<string, FunctionDefinition | ParseFunction>;
471
501
  //#endregion
472
502
  //#region src/utils/color-space.d.ts
503
+ /**
504
+ * Color handling that survives into the emitted CSS.
505
+ *
506
+ * Tasty does not rewrite a color into a particular color space: opacity is
507
+ * applied with CSS relative color syntax, which reads the channels off whatever
508
+ * the browser resolves a value to, so a color is emitted exactly as authored.
509
+ * What is left here is how an alpha gets applied, and the one distinction that
510
+ * matters — replacing a token's alpha versus composing onto an inherited one.
511
+ */
512
+ /**
513
+ * The color space a `#name` token's value used to be rewritten into.
514
+ *
515
+ * @deprecated Kept for the `colorSpace` config option, which no longer has any
516
+ * effect. Colors are emitted as authored and opacity is always applied in
517
+ * `oklch` through relative color syntax.
518
+ */
473
519
  type ColorSpace = 'rgb' | 'hsl' | 'oklch';
474
520
  //#endregion
475
521
  //#region src/utils/typography.d.ts
@@ -587,7 +633,7 @@ interface TastyPlugin {
587
633
  * Design tokens injected as CSS custom properties on `:root`.
588
634
  * Values are parsed through the Tasty DSL. Supports state maps.
589
635
  * - `$name` → `--name` CSS custom property
590
- * - `#name` → `--name-color` and `--name-color-{colorSpace}`
636
+ * - `#name` → `--name-color`
591
637
  */
592
638
  tokens?: ConfigTokens;
593
639
  /** Predefined tokens replaced during style parsing (`$name` or `#name`) */
@@ -703,14 +749,18 @@ interface TastyConfig {
703
749
  */
704
750
  functions?: FunctionsConfig;
705
751
  /**
706
- * Color space used for decomposed color token companion variables.
707
- * Controls the CSS function and suffix for alpha composition.
752
+ * @deprecated No longer has any effect; will be removed in the next major.
753
+ * Setting it warns in development.
708
754
  *
709
- * - `'rgb'` — suffix `-rgb`, e.g. `rgb(var(--name-color-rgb) / .5)`
710
- * - `'hsl'` — suffix `-hsl`, e.g. `hsl(var(--name-color-hsl) / .5)`
711
- * - `'oklch'`suffix `-oklch`, e.g. `oklch(var(--name-color-oklch) / .5)`
755
+ * A `#name` token's value used to be rewritten into this color space so an
756
+ * opacity suffix had numeric channels to write an alpha into. Opacity now uses
757
+ * relative color syntax — `oklch(from var(--name-color) l c h / .5)` — which
758
+ * has the browser read the channels, so a color is emitted exactly as
759
+ * authored and there is nothing left for the setting to decide.
712
760
  *
713
- * @default 'oklch'
761
+ * To address a token's channels yourself, write relative color syntax against
762
+ * the token: `oklch(from var(--brand-color) calc(l * 1.2) c h)`. It works on
763
+ * every `<color>`, including the ones no conversion could evaluate.
714
764
  */
715
765
  colorSpace?: ColorSpace;
716
766
  /**
@@ -721,6 +771,47 @@ interface TastyConfig {
721
771
  * @default true
722
772
  */
723
773
  autoPropertyTypes?: boolean;
774
+ /**
775
+ * Defer stylesheet writes and apply them in one batch instead of performing
776
+ * one `insertRule()` per component during render.
777
+ *
778
+ * Each `insertRule()` on a live sheet invalidates style for that sheet's
779
+ * scope. When components inject during React's render phase while other
780
+ * components read layout in the same pass, the two interleave and the browser
781
+ * is forced to recalculate style between every injection. Batching collapses
782
+ * that into one invalidation per flush.
783
+ *
784
+ * - `false` (default) — inject synchronously, one write per component.
785
+ * - `true` — batch, but only inside a *batch window*: a commit in which
786
+ * `<TastyBatchProvider>` rendered and will therefore flush in its
787
+ * `useInsertionEffect`, before any `useLayoutEffect` runs. Any injection
788
+ * outside a window — a deep update the provider did not re-render for, an
789
+ * injection from a layout effect, an event handler, an async callback — is
790
+ * written straight through. Enabling this can never make a layout effect
791
+ * measure an unstyled element. Requires `<TastyBatchProvider>`; without it
792
+ * nothing is batched (and dev mode says so once).
793
+ * - `'always'` — batch every injection, flushing on a microtask when no
794
+ * window is open. Wins on more commits, but a `useLayoutEffect` that
795
+ * measures a freshly mounted element can read its unstyled box, because
796
+ * microtasks run after the layout phase. Paint is unaffected: microtasks
797
+ * always drain before the browser paints.
798
+ *
799
+ * No effect during SSR or RSC: styles are collected as text there, the
800
+ * runtime injector never runs, and the provider is inert without a
801
+ * `document`. No effect on zero-runtime `tastyStatic` styles either — those
802
+ * are extracted at build time and never reach the injector.
803
+ *
804
+ * @default false
805
+ * @example
806
+ * ```tsx
807
+ * configure({ batchInjection: true });
808
+ *
809
+ * <TastyBatchProvider>
810
+ * <App />
811
+ * </TastyBatchProvider>
812
+ * ```
813
+ */
814
+ batchInjection?: boolean | 'always';
724
815
  /**
725
816
  * Garbage collection configuration for unused styles.
726
817
  * GC is triggered by touch count: every `touchInterval` touches, the
@@ -954,7 +1045,7 @@ interface TastyConfig {
954
1045
  * for responsive/theme-aware tokens.
955
1046
  *
956
1047
  * - `$name` keys become `--name` CSS custom properties
957
- * - `#name` keys become `--name-color` and `--name-color-{colorSpace}` properties
1048
+ * - `#name` keys become `--name-color` properties
958
1049
  *
959
1050
  * Tokens are injected once when the first style is rendered.
960
1051
  *
@@ -1169,4 +1260,4 @@ declare function getNamePrefix(): string;
1169
1260
  declare function resetConfig(): void;
1170
1261
  //#endregion
1171
1262
  export { ParseFunction as C, PropHandlerDefinition as D, PropHandler as E, PropHandlerProps as O, FunctionsConfig as S, SheetManager as T, TastyPluginFactory as _, getGlobalFontFaces as a, generateTypographyTokens as b, getGlobalRecipes as c, hasGlobalRecipes as d, hasStylesGenerated as f, TastyPlugin as g, resetConfig as h, getGlobalCounterStyles as i, getNamePrefix as l, isTestEnvironment as m, configure as n, getGlobalFunctions as o, isConfigLocked as p, getConfig as r, getGlobalKeyframes as s, TastyConfig as t, hasGlobalKeyframes as u, TypographyPreset as v, StyleInjector as w, ColorSpace as x, TypographyTokenValue as y };
1172
- //# sourceMappingURL=config-De8L9NWM.d.ts.map
1263
+ //# sourceMappingURL=config-YsxGv4tq.d.ts.map