@tenphi/tasty 0.0.0-snapshot.d656d18 → 0.0.0-snapshot.d720187
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/{babel-_RVkw0iE.d.ts → babel-D6lOuSwk.d.ts} +2 -2
- package/dist/chunks/{collector-DBGcmUEq.js → collector-BVzrXWil.js} +4 -3
- package/dist/chunks/{collector-DBGcmUEq.js.map → collector-BVzrXWil.js.map} +1 -1
- package/dist/chunks/config-engine-7nX85gCT.js +403 -0
- package/dist/chunks/config-engine-7nX85gCT.js.map +1 -0
- package/dist/chunks/css-definitions-CfXdhJ-p.js +1194 -0
- package/dist/chunks/css-definitions-CfXdhJ-p.js.map +1 -0
- package/dist/chunks/{debug-BUwqo6vC.js → debug-DpMV1J0r.js} +4 -3
- package/dist/chunks/{debug-BUwqo6vC.js.map → debug-DpMV1J0r.js.map} +1 -1
- package/dist/chunks/hydration-CLdVKcH2.js +59 -0
- package/dist/chunks/hydration-CLdVKcH2.js.map +1 -0
- package/dist/chunks/{react-runtime-B3CmvDEQ.js → react-runtime-C5_xOQFf.js} +4 -3
- package/dist/chunks/{react-runtime-B3CmvDEQ.js.map → react-runtime-C5_xOQFf.js.map} +1 -1
- package/dist/chunks/{runtime-engine-Y00VWjrS.js → runtime-engine-BfqCASPn.js} +17 -1601
- package/dist/chunks/runtime-engine-BfqCASPn.js.map +1 -0
- package/dist/chunks/{style-engine-CqSmIlud.js → style-engine-CBuOt1e4.js} +192 -174
- package/dist/chunks/style-engine-CBuOt1e4.js.map +1 -0
- package/dist/chunks/{css-writer-PFzrSPeu.js → zero-engine-CJR3ZKcW.js} +3 -3
- package/dist/chunks/zero-engine-CJR3ZKcW.js.map +1 -0
- package/dist/{config-BI0y21JV.d.ts → config-BWYrv_Aa.d.ts} +4 -4
- package/dist/core/index.d.ts +2 -2
- package/dist/core/index.js +6 -4
- package/dist/{index-CrT0bsiI.d.ts → index-C5tyPTer.d.ts} +3 -12
- package/dist/index.d.ts +2 -2
- package/dist/index.js +6 -4
- package/dist/ssr/astro-client.js +1 -1
- package/dist/ssr/astro.js +2 -2
- package/dist/ssr/index.d.ts +5 -5
- package/dist/ssr/index.js +3 -3
- package/dist/ssr/next-config.d.ts +1 -1
- package/dist/ssr/next-config.js +2 -2
- package/dist/ssr/next.js +4 -4
- package/dist/zero/babel.d.ts +1 -1
- package/dist/zero/babel.js +63 -23
- package/dist/zero/babel.js.map +1 -1
- package/dist/zero/index.js +1 -1
- package/dist/zero/next.d.ts +1 -1
- package/package.json +9 -3
- package/dist/chunks/css-writer-PFzrSPeu.js.map +0 -1
- package/dist/chunks/hydrate-6YoHZP6A.js +0 -37
- package/dist/chunks/hydrate-6YoHZP6A.js.map +0 -1
- package/dist/chunks/runtime-engine-Y00VWjrS.js.map +0 -1
- package/dist/chunks/style-engine-CqSmIlud.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as TastyConfig } from "./config-
|
|
1
|
+
import { t as TastyConfig } from "./config-BWYrv_Aa.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-
|
|
83
|
+
//# sourceMappingURL=babel-D6lOuSwk.d.ts.map
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { b as renderStyles } from "./style-engine-
|
|
1
|
+
import { A as validateNamePrefix, B as formatFunctionRule, D as makeKeyframeName, E as makeCounterStyleName, H as parseFunctionName, T as makeClassName, b as formatFontFaceRule, h as formatCounterStyleRule, i as formatPropertyCSS, j as hashString, n as formatRules, t as formatGlobalRules, v as fontFaceContentHash } from "./css-definitions-CfXdhJ-p.js";
|
|
2
|
+
import { b as renderStyles } from "./style-engine-CBuOt1e4.js";
|
|
3
|
+
import { B as getGlobalStyles, F as getGlobalFontFaces, I as getGlobalFunctions, M as getEffectiveProperties, N as getGlobalConfigTokens, P as getGlobalCounterStyles, V as getNamePrefix } from "./runtime-engine-BfqCASPn.js";
|
|
3
4
|
//#region src/ssr/collector.ts
|
|
4
5
|
/**
|
|
5
6
|
* ServerStyleCollector — server-safe style collector for SSR.
|
|
@@ -323,4 +324,4 @@ function createServerStyleCollector(namePrefix) {
|
|
|
323
324
|
//#endregion
|
|
324
325
|
export { createServerStyleCollector as n, ServerStyleCollector as t };
|
|
325
326
|
|
|
326
|
-
//# sourceMappingURL=collector-
|
|
327
|
+
//# sourceMappingURL=collector-BVzrXWil.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collector-DBGcmUEq.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 type ServerStyleArtifactKind =\n | 'property'\n | 'font-face'\n | 'counter-style'\n | 'function'\n | 'raw'\n | 'global'\n | 'chunk'\n | 'keyframes';\n\nexport interface ServerStyleArtifact {\n /** Stable identifier derived from the artifact kind, logical key, and CSS. */\n id: string;\n kind: ServerStyleArtifactKind;\n css: string;\n /** Zero-based position in the collector's final cascade order. */\n order: number;\n}\n\nfunction artifactId(kind: ServerStyleArtifactKind, key: string, css: string) {\n const content = `${kind}\\0${key}\\0${css}`;\n return `${kind}:${hashString(content)}:${content.length.toString(36)}`;\n}\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 * Return the collected CSS as structured, ordered artifacts.\n *\n * Artifact boundaries are part of the collector output so build tools never\n * need to split or parse CSS text. IDs include the logical collection key\n * and content, making them stable across equivalent page renders while a CSS\n * change always produces a different ID.\n */\n getArtifacts(): ServerStyleArtifact[] {\n const artifacts: ServerStyleArtifact[] = [];\n\n const append = (\n kind: ServerStyleArtifactKind,\n entries: Iterable<[string, string]>,\n ) => {\n for (const [key, css] of entries) {\n artifacts.push({\n id: artifactId(kind, key, css),\n kind,\n css,\n order: artifacts.length,\n });\n }\n };\n\n append('property', this.propertyRules);\n append('font-face', this.fontFaceRules);\n append('counter-style', this.counterStyleRules);\n append('function', this.functionRules);\n append('raw', this.rawCSS);\n append('global', this.globalStyles);\n append('chunk', this.chunks);\n append('keyframes', this.keyframeRules);\n\n return artifacts;\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 return this.getArtifacts()\n .map(({ css }) => css)\n .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-BVzrXWil.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 type ServerStyleArtifactKind =\n | 'property'\n | 'font-face'\n | 'counter-style'\n | 'function'\n | 'raw'\n | 'global'\n | 'chunk'\n | 'keyframes';\n\nexport interface ServerStyleArtifact {\n /** Stable identifier derived from the artifact kind, logical key, and CSS. */\n id: string;\n kind: ServerStyleArtifactKind;\n css: string;\n /** Zero-based position in the collector's final cascade order. */\n order: number;\n}\n\nfunction artifactId(kind: ServerStyleArtifactKind, key: string, css: string) {\n const content = `${kind}\\0${key}\\0${css}`;\n return `${kind}:${hashString(content)}:${content.length.toString(36)}`;\n}\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 * Return the collected CSS as structured, ordered artifacts.\n *\n * Artifact boundaries are part of the collector output so build tools never\n * need to split or parse CSS text. IDs include the logical collection key\n * and content, making them stable across equivalent page renders while a CSS\n * change always produces a different ID.\n */\n getArtifacts(): ServerStyleArtifact[] {\n const artifacts: ServerStyleArtifact[] = [];\n\n const append = (\n kind: ServerStyleArtifactKind,\n entries: Iterable<[string, string]>,\n ) => {\n for (const [key, css] of entries) {\n artifacts.push({\n id: artifactId(kind, key, css),\n kind,\n css,\n order: artifacts.length,\n });\n }\n };\n\n append('property', this.propertyRules);\n append('font-face', this.fontFaceRules);\n append('counter-style', this.counterStyleRules);\n append('function', this.functionRules);\n append('raw', this.rawCSS);\n append('global', this.globalStyles);\n append('chunk', this.chunks);\n append('keyframes', this.keyframeRules);\n\n return artifacts;\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 return this.getArtifacts()\n .map(({ css }) => css)\n .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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"}
|
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
import { _ as setGlobalPredefinedTokens, c as getGlobalParseFunctions, d as normalizeColorTokenValue, i as CUSTOM_UNITS, l as getGlobalParser } from "./dsl-CXvoaLnj.js";
|
|
2
|
+
import { n as isSelector, o as isDevEnv, t as mergeStyles } from "./shared-utils-OIg0N_dp.js";
|
|
3
|
+
import { K as splitFunctions, U as registerFunctionPolyfill } from "./css-definitions-CfXdhJ-p.js";
|
|
4
|
+
import { E as registerHandler, T as normalizeHandlerDefinition, U as isFunctionsPolyfillEnabled, V as setGlobalPredefinedStates, q as setGlobalPolyfillsState } from "./style-engine-CBuOt1e4.js";
|
|
5
|
+
//#region src/utils/typography.ts
|
|
6
|
+
const RESERVED_PRESET_NAMES = new Set([
|
|
7
|
+
"strong",
|
|
8
|
+
"bold",
|
|
9
|
+
"italic",
|
|
10
|
+
"icon",
|
|
11
|
+
"tight"
|
|
12
|
+
]);
|
|
13
|
+
/**
|
|
14
|
+
* Generate typography tokens with $ prefix for CSS custom properties.
|
|
15
|
+
*
|
|
16
|
+
* Each preset generates the following CSS custom properties:
|
|
17
|
+
* - `${name}-font-size`
|
|
18
|
+
* - `${name}-line-height`
|
|
19
|
+
* - `${name}-letter-spacing`
|
|
20
|
+
* - `${name}-font-weight`
|
|
21
|
+
* - `${name}-bold-font-weight` (if defined)
|
|
22
|
+
* - `${name}-icon-size` (if defined)
|
|
23
|
+
* - `${name}-text-transform` (if defined)
|
|
24
|
+
* - `${name}-font-family` (if defined)
|
|
25
|
+
* - `${name}-font-style` (if defined)
|
|
26
|
+
*
|
|
27
|
+
* @param presets - Typography presets object
|
|
28
|
+
* @returns ConfigTokens object with $ prefixed keys
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* const customTokens = generateTypographyTokens({
|
|
32
|
+
* myHeading: { fontSize: '24px', lineHeight: '32px', fontWeight: '700' },
|
|
33
|
+
* body: { fontSize: '16px', lineHeight: '24px', fontWeight: '400' },
|
|
34
|
+
* });
|
|
35
|
+
*/
|
|
36
|
+
function generateTypographyTokens(presets) {
|
|
37
|
+
const tokens = {};
|
|
38
|
+
for (const [name, preset] of Object.entries(presets)) {
|
|
39
|
+
if (RESERVED_PRESET_NAMES.has(name)) throw new Error(`Invalid typography preset name "${name}". This name is reserved as a preset modifier.`);
|
|
40
|
+
tokens[`$${name}-font-size`] = preset.fontSize;
|
|
41
|
+
tokens[`$${name}-line-height`] = preset.lineHeight;
|
|
42
|
+
tokens[`$${name}-letter-spacing`] = preset.letterSpacing ?? "normal";
|
|
43
|
+
tokens[`$${name}-font-weight`] = preset.fontWeight;
|
|
44
|
+
if (preset.boldFontWeight !== void 0) tokens[`$${name}-bold-font-weight`] = preset.boldFontWeight;
|
|
45
|
+
if (preset.iconSize !== void 0) tokens[`$${name}-icon-size`] = preset.iconSize;
|
|
46
|
+
if (preset.textTransform !== void 0) tokens[`$${name}-text-transform`] = preset.textTransform;
|
|
47
|
+
if (preset.fontFamily !== void 0) tokens[`$${name}-font-family`] = preset.fontFamily;
|
|
48
|
+
if (preset.fontStyle !== void 0) tokens[`$${name}-font-style`] = preset.fontStyle;
|
|
49
|
+
}
|
|
50
|
+
return tokens;
|
|
51
|
+
}
|
|
52
|
+
//#endregion
|
|
53
|
+
//#region src/config-normalize.ts
|
|
54
|
+
/**
|
|
55
|
+
* Configuration processing shared by runtime and build-time paths.
|
|
56
|
+
*
|
|
57
|
+
* Plugins are folded first and direct configuration wins. Keeping this step
|
|
58
|
+
* independent from the DOM injector lets zero-runtime tooling reuse the exact
|
|
59
|
+
* same precedence and style-engine setup without loading browser infrastructure.
|
|
60
|
+
*/
|
|
61
|
+
/** Apply parser and style-engine configuration shared by every renderer. */
|
|
62
|
+
function applyStyleConfig(config, normalized, warnOnce) {
|
|
63
|
+
const tokenKeys = new Set(Object.keys(normalized.tokens));
|
|
64
|
+
for (const key of Object.keys(normalized.replaceTokens)) if (tokenKeys.has(key)) warnOnce(`token-conflict-${key}`, `[Tasty] Token "${key}" is defined in both \`tokens\` and \`replaceTokens\`. \`replaceTokens\` performs parse-time substitution, so the \`tokens\` CSS custom property will be injected but never used by Tasty styles. Remove it from one of the two.`);
|
|
65
|
+
if (config.colorSpace) warnOnce("colorSpace-deprecated", "[Tasty] configure({ colorSpace }) no longer has any effect and will be removed in the next major. Colors are emitted as authored, and opacity is applied with relative color syntax, which reads a color's channels in the browser. To address channels yourself, write `oklch(from var(--name-color) l c h)` against the token.");
|
|
66
|
+
if (Object.keys(normalized.states).length > 0) setGlobalPredefinedStates(normalized.states);
|
|
67
|
+
const parser = getGlobalParser();
|
|
68
|
+
if (config.parserCacheSize !== void 0) parser.updateOptions({ cacheSize: config.parserCacheSize });
|
|
69
|
+
if (Object.keys(normalized.units).length > 0) {
|
|
70
|
+
const currentUnits = parser.getUnits() ?? CUSTOM_UNITS;
|
|
71
|
+
parser.setUnits({
|
|
72
|
+
...currentUnits,
|
|
73
|
+
...normalized.units
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
if (config.polyfills) setGlobalPolyfillsState(config.polyfills);
|
|
77
|
+
const { parseFuncs, functionDefs } = splitFunctions(normalized.functions, (key, kind) => {
|
|
78
|
+
warnOnce(`functions-mismatch-${key}`, kind === "expected-definition" ? `[Tasty] functions["${key}"]: a "$$"-prefixed key denotes a CSS @function and expects a definition object, but received a function. Entry ignored.` : `[Tasty] functions["${key}"]: a bare key denotes a parse function and expects a function value, but received an object. Did you mean "$$${key}"? Entry ignored.`);
|
|
79
|
+
});
|
|
80
|
+
if (Object.keys(parseFuncs).length > 0) {
|
|
81
|
+
const currentFuncs = getGlobalParseFunctions();
|
|
82
|
+
parser.setFunctions({
|
|
83
|
+
...currentFuncs,
|
|
84
|
+
...parseFuncs
|
|
85
|
+
});
|
|
86
|
+
Object.assign(currentFuncs, parseFuncs);
|
|
87
|
+
}
|
|
88
|
+
if (isFunctionsPolyfillEnabled()) for (const [name, definition] of Object.entries(functionDefs)) registerFunctionPolyfill(name, definition);
|
|
89
|
+
for (const [name, definition] of Object.entries(normalized.handlers)) registerHandler(normalizeHandlerDefinition(name, definition), {
|
|
90
|
+
key: name,
|
|
91
|
+
source: normalized.handlerSources.get(name)
|
|
92
|
+
});
|
|
93
|
+
if (Object.keys(normalized.replaceTokens).length > 0) {
|
|
94
|
+
const processedTokens = {};
|
|
95
|
+
for (const [key, value] of Object.entries(normalized.replaceTokens)) if (key.startsWith("#")) {
|
|
96
|
+
const normalizedValue = normalizeColorTokenValue(value);
|
|
97
|
+
if (normalizedValue === null) continue;
|
|
98
|
+
processedTokens[key] = String(normalizedValue);
|
|
99
|
+
} else if (value !== false) processedTokens[key] = String(value);
|
|
100
|
+
setGlobalPredefinedTokens(processedTokens);
|
|
101
|
+
}
|
|
102
|
+
return functionDefs;
|
|
103
|
+
}
|
|
104
|
+
function normalizeConfig(config) {
|
|
105
|
+
let states = {};
|
|
106
|
+
let units = {};
|
|
107
|
+
let functions = {};
|
|
108
|
+
let handlers = {};
|
|
109
|
+
const handlerSources = /* @__PURE__ */ new Map();
|
|
110
|
+
let propHandlers = {};
|
|
111
|
+
const propHandlerSources = /* @__PURE__ */ new Map();
|
|
112
|
+
const baseStyleProps = [];
|
|
113
|
+
let properties = {};
|
|
114
|
+
let keyframes = {};
|
|
115
|
+
let fontFaces = {};
|
|
116
|
+
let counterStyles = {};
|
|
117
|
+
let replaceTokens = {};
|
|
118
|
+
let tokens = {};
|
|
119
|
+
let recipes = {};
|
|
120
|
+
let presets = {};
|
|
121
|
+
const globalStyles = {};
|
|
122
|
+
for (const plugin of config.plugins ?? []) {
|
|
123
|
+
if (plugin.states) states = {
|
|
124
|
+
...states,
|
|
125
|
+
...plugin.states
|
|
126
|
+
};
|
|
127
|
+
if (plugin.units) units = {
|
|
128
|
+
...units,
|
|
129
|
+
...plugin.units
|
|
130
|
+
};
|
|
131
|
+
if (plugin.functions) functions = {
|
|
132
|
+
...functions,
|
|
133
|
+
...plugin.functions
|
|
134
|
+
};
|
|
135
|
+
if (plugin.handlers) {
|
|
136
|
+
handlers = {
|
|
137
|
+
...handlers,
|
|
138
|
+
...plugin.handlers
|
|
139
|
+
};
|
|
140
|
+
for (const key of Object.keys(plugin.handlers)) handlerSources.set(key, `plugin "${plugin.name}"`);
|
|
141
|
+
}
|
|
142
|
+
if (plugin.propHandlers) {
|
|
143
|
+
propHandlers = {
|
|
144
|
+
...propHandlers,
|
|
145
|
+
...plugin.propHandlers
|
|
146
|
+
};
|
|
147
|
+
for (const key of Object.keys(plugin.propHandlers)) propHandlerSources.set(key, `plugin "${plugin.name}"`);
|
|
148
|
+
}
|
|
149
|
+
if (plugin.baseStyleProps) baseStyleProps.push(...plugin.baseStyleProps);
|
|
150
|
+
if (plugin.properties) properties = {
|
|
151
|
+
...properties,
|
|
152
|
+
...plugin.properties
|
|
153
|
+
};
|
|
154
|
+
if (plugin.keyframes) keyframes = {
|
|
155
|
+
...keyframes,
|
|
156
|
+
...plugin.keyframes
|
|
157
|
+
};
|
|
158
|
+
if (plugin.fontFaces) fontFaces = {
|
|
159
|
+
...fontFaces,
|
|
160
|
+
...plugin.fontFaces
|
|
161
|
+
};
|
|
162
|
+
if (plugin.counterStyles) counterStyles = {
|
|
163
|
+
...counterStyles,
|
|
164
|
+
...plugin.counterStyles
|
|
165
|
+
};
|
|
166
|
+
if (plugin.replaceTokens) replaceTokens = {
|
|
167
|
+
...replaceTokens,
|
|
168
|
+
...plugin.replaceTokens
|
|
169
|
+
};
|
|
170
|
+
if (plugin.tokens) tokens = {
|
|
171
|
+
...tokens,
|
|
172
|
+
...plugin.tokens
|
|
173
|
+
};
|
|
174
|
+
if (plugin.recipes) recipes = {
|
|
175
|
+
...recipes,
|
|
176
|
+
...plugin.recipes
|
|
177
|
+
};
|
|
178
|
+
if (plugin.presets) presets = {
|
|
179
|
+
...presets,
|
|
180
|
+
...plugin.presets
|
|
181
|
+
};
|
|
182
|
+
if (plugin.globalStyles) mergeGlobalStyles(globalStyles, plugin.globalStyles);
|
|
183
|
+
}
|
|
184
|
+
if (config.states) states = {
|
|
185
|
+
...states,
|
|
186
|
+
...config.states
|
|
187
|
+
};
|
|
188
|
+
if (config.units) units = {
|
|
189
|
+
...units,
|
|
190
|
+
...config.units
|
|
191
|
+
};
|
|
192
|
+
if (config.functions) functions = {
|
|
193
|
+
...functions,
|
|
194
|
+
...config.functions
|
|
195
|
+
};
|
|
196
|
+
if (config.handlers) {
|
|
197
|
+
handlers = {
|
|
198
|
+
...handlers,
|
|
199
|
+
...config.handlers
|
|
200
|
+
};
|
|
201
|
+
for (const key of Object.keys(config.handlers)) handlerSources.set(key, "configure()");
|
|
202
|
+
}
|
|
203
|
+
if (config.propHandlers) {
|
|
204
|
+
propHandlers = {
|
|
205
|
+
...propHandlers,
|
|
206
|
+
...config.propHandlers
|
|
207
|
+
};
|
|
208
|
+
for (const key of Object.keys(config.propHandlers)) propHandlerSources.set(key, "configure()");
|
|
209
|
+
}
|
|
210
|
+
if (config.baseStyleProps) baseStyleProps.push(...config.baseStyleProps);
|
|
211
|
+
if (config.properties) properties = {
|
|
212
|
+
...properties,
|
|
213
|
+
...config.properties
|
|
214
|
+
};
|
|
215
|
+
if (config.keyframes) keyframes = {
|
|
216
|
+
...keyframes,
|
|
217
|
+
...config.keyframes
|
|
218
|
+
};
|
|
219
|
+
if (config.fontFaces) fontFaces = {
|
|
220
|
+
...fontFaces,
|
|
221
|
+
...config.fontFaces
|
|
222
|
+
};
|
|
223
|
+
if (config.counterStyles) counterStyles = {
|
|
224
|
+
...counterStyles,
|
|
225
|
+
...config.counterStyles
|
|
226
|
+
};
|
|
227
|
+
if (config.replaceTokens) replaceTokens = {
|
|
228
|
+
...replaceTokens,
|
|
229
|
+
...config.replaceTokens
|
|
230
|
+
};
|
|
231
|
+
if (config.presets) presets = {
|
|
232
|
+
...presets,
|
|
233
|
+
...config.presets
|
|
234
|
+
};
|
|
235
|
+
if (Object.keys(presets).length > 0) tokens = {
|
|
236
|
+
...generateTypographyTokens(presets),
|
|
237
|
+
...tokens
|
|
238
|
+
};
|
|
239
|
+
if (config.tokens) tokens = {
|
|
240
|
+
...tokens,
|
|
241
|
+
...config.tokens
|
|
242
|
+
};
|
|
243
|
+
if (config.recipes) recipes = {
|
|
244
|
+
...recipes,
|
|
245
|
+
...config.recipes
|
|
246
|
+
};
|
|
247
|
+
if (config.globalStyles) mergeGlobalStyles(globalStyles, config.globalStyles);
|
|
248
|
+
return {
|
|
249
|
+
states,
|
|
250
|
+
units,
|
|
251
|
+
functions,
|
|
252
|
+
handlers,
|
|
253
|
+
handlerSources,
|
|
254
|
+
propHandlers,
|
|
255
|
+
propHandlerSources,
|
|
256
|
+
baseStyleProps,
|
|
257
|
+
properties,
|
|
258
|
+
keyframes,
|
|
259
|
+
fontFaces,
|
|
260
|
+
counterStyles,
|
|
261
|
+
replaceTokens,
|
|
262
|
+
tokens,
|
|
263
|
+
recipes,
|
|
264
|
+
globalStyles
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
function mergeGlobalStyles(target, source) {
|
|
268
|
+
for (const [selector, styles] of Object.entries(source)) target[selector] = target[selector] ? {
|
|
269
|
+
...target[selector],
|
|
270
|
+
...styles
|
|
271
|
+
} : styles;
|
|
272
|
+
}
|
|
273
|
+
//#endregion
|
|
274
|
+
//#region src/utils/resolve-recipes-core.ts
|
|
275
|
+
const devMode = isDevEnv();
|
|
276
|
+
/**
|
|
277
|
+
* Parse a recipe string into base and post recipe name groups.
|
|
278
|
+
*
|
|
279
|
+
* Syntax: `'base1 base2 / post1 post2'`
|
|
280
|
+
* - Names are space-separated within each group
|
|
281
|
+
* - `/` separates base (before component) from post (after component) groups
|
|
282
|
+
* - `/` is optional; if absent, all names are base
|
|
283
|
+
* - `none` as the sole base value means "no base recipes"
|
|
284
|
+
*
|
|
285
|
+
* Returns `{ base: null, post: null }` if the string is empty or invalid.
|
|
286
|
+
*/
|
|
287
|
+
function parseRecipeNames(value) {
|
|
288
|
+
const empty = {
|
|
289
|
+
base: null,
|
|
290
|
+
post: null
|
|
291
|
+
};
|
|
292
|
+
if (typeof value !== "string") return empty;
|
|
293
|
+
const trimmed = value.trim();
|
|
294
|
+
if (trimmed === "") return empty;
|
|
295
|
+
const slashIndex = trimmed.indexOf("/");
|
|
296
|
+
if (slashIndex === -1) {
|
|
297
|
+
if (trimmed === "none") return empty;
|
|
298
|
+
return {
|
|
299
|
+
base: splitNames(trimmed),
|
|
300
|
+
post: null
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
const basePart = trimmed.slice(0, slashIndex);
|
|
304
|
+
const postPart = trimmed.slice(slashIndex + 1);
|
|
305
|
+
return {
|
|
306
|
+
base: basePart.trim() === "none" ? null : splitNames(basePart),
|
|
307
|
+
post: splitNames(postPart)
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
function splitNames(s) {
|
|
311
|
+
const names = s.split(/\s+/).filter(Boolean);
|
|
312
|
+
return names.length > 0 ? names : null;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Collect merged styles for a list of recipe names.
|
|
316
|
+
* Each recipe is flat-spread on top of the previous.
|
|
317
|
+
*/
|
|
318
|
+
function collectRecipeStyles(names, recipes) {
|
|
319
|
+
let merged = {};
|
|
320
|
+
for (const name of names) {
|
|
321
|
+
const recipeStyles = recipes[name];
|
|
322
|
+
if (!recipeStyles) {
|
|
323
|
+
if (devMode) console.warn(`[Tasty] Recipe "${name}" not found. Make sure it is defined in configure({ recipes: { ... } }).`);
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
merged = {
|
|
327
|
+
...merged,
|
|
328
|
+
...recipeStyles
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
return merged;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Resolve recipe references in a flat styles object (no sub-elements).
|
|
335
|
+
* Returns null if no `recipe` key is present.
|
|
336
|
+
*
|
|
337
|
+
* Resolution: base recipes → component styles → post recipes (all via mergeStyles)
|
|
338
|
+
*/
|
|
339
|
+
function resolveRecipesForLevel(styles, recipes) {
|
|
340
|
+
if (!("recipe" in styles)) return null;
|
|
341
|
+
const { base, post } = parseRecipeNames(styles.recipe);
|
|
342
|
+
const { recipe: _recipe, ...allRest } = styles;
|
|
343
|
+
const flatStyles = {};
|
|
344
|
+
const selectorStyles = {};
|
|
345
|
+
for (const key of Object.keys(allRest)) if (isSelector(key)) selectorStyles[key] = allRest[key];
|
|
346
|
+
else flatStyles[key] = allRest[key];
|
|
347
|
+
if (!base && !post) return allRest;
|
|
348
|
+
let result;
|
|
349
|
+
if (base) result = mergeStyles(collectRecipeStyles(base, recipes), flatStyles);
|
|
350
|
+
else result = { ...flatStyles };
|
|
351
|
+
if (post) {
|
|
352
|
+
const postStyles = collectRecipeStyles(post, recipes);
|
|
353
|
+
result = mergeStyles(result, postStyles);
|
|
354
|
+
}
|
|
355
|
+
for (const key of Object.keys(selectorStyles)) result[key] = selectorStyles[key];
|
|
356
|
+
return result;
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Resolve all `recipe` style properties in a styles object.
|
|
360
|
+
*
|
|
361
|
+
* Handles both top-level and sub-element recipe references.
|
|
362
|
+
* Returns the same object reference if no recipes are present anywhere
|
|
363
|
+
* (zero overhead for the common case).
|
|
364
|
+
*
|
|
365
|
+
* @param styles - The styles object potentially containing `recipe` keys
|
|
366
|
+
* @returns Resolved styles with recipe values merged in, or the original object if unchanged
|
|
367
|
+
*/
|
|
368
|
+
function resolveRecipesWith(styles, recipes) {
|
|
369
|
+
if (!recipes) return styles;
|
|
370
|
+
let changed = false;
|
|
371
|
+
const topResolved = resolveRecipesForLevel(styles, recipes);
|
|
372
|
+
let result;
|
|
373
|
+
if (topResolved) {
|
|
374
|
+
changed = true;
|
|
375
|
+
result = topResolved;
|
|
376
|
+
} else result = styles;
|
|
377
|
+
const keys = Object.keys(result);
|
|
378
|
+
for (const key of keys) {
|
|
379
|
+
if (!isSelector(key)) continue;
|
|
380
|
+
const subStyles = result[key];
|
|
381
|
+
if (!subStyles || typeof subStyles !== "object" || Array.isArray(subStyles)) continue;
|
|
382
|
+
const subRecord = subStyles;
|
|
383
|
+
if (!("recipe" in subRecord)) continue;
|
|
384
|
+
const subResolved = resolveRecipesForLevel(subRecord, recipes);
|
|
385
|
+
if (subResolved) {
|
|
386
|
+
if (!changed) {
|
|
387
|
+
changed = true;
|
|
388
|
+
result = { ...styles };
|
|
389
|
+
}
|
|
390
|
+
Object.defineProperty(result, key, {
|
|
391
|
+
configurable: true,
|
|
392
|
+
enumerable: true,
|
|
393
|
+
value: subResolved,
|
|
394
|
+
writable: true
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
return changed ? result : styles;
|
|
399
|
+
}
|
|
400
|
+
//#endregion
|
|
401
|
+
export { generateTypographyTokens as i, applyStyleConfig as n, normalizeConfig as r, resolveRecipesWith as t };
|
|
402
|
+
|
|
403
|
+
//# sourceMappingURL=config-engine-7nX85gCT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-engine-7nX85gCT.js","names":[],"sources":["../../src/utils/typography.ts","../../src/config-normalize.ts","../../src/utils/resolve-recipes-core.ts"],"sourcesContent":["import type { ConfigTokens } from '../styles/types';\n\nconst RESERVED_PRESET_NAMES = new Set([\n 'strong',\n 'bold',\n 'italic',\n 'icon',\n 'tight',\n]);\n\n/**\n * A typography token value: plain value or a state map for responsive/theme-aware presets.\n *\n * @example\n * // Plain value\n * fontWeight: '400'\n * // State map\n * fontWeight: { '': '400', '@dark': '300' }\n */\nexport type TypographyTokenValue =\n | string\n | number\n | Record<string, string | number | undefined | null | '@inherit'>;\n\n/**\n * Typography preset configuration.\n * Each preset defines font properties that get expanded into CSS custom properties.\n * All fields accept plain values or state maps for responsive/theme-aware tokens.\n *\n * Use with `generateTypographyTokens()` to create typography tokens for your design system.\n */\nexport interface TypographyPreset {\n fontSize: TypographyTokenValue;\n lineHeight: TypographyTokenValue;\n letterSpacing?: TypographyTokenValue;\n fontWeight: TypographyTokenValue;\n boldFontWeight?: TypographyTokenValue;\n iconSize?: TypographyTokenValue;\n textTransform?: TypographyTokenValue;\n fontFamily?: TypographyTokenValue;\n fontStyle?: TypographyTokenValue;\n}\n\n/**\n * Generate typography tokens with $ prefix for CSS custom properties.\n *\n * Each preset generates the following CSS custom properties:\n * - `${name}-font-size`\n * - `${name}-line-height`\n * - `${name}-letter-spacing`\n * - `${name}-font-weight`\n * - `${name}-bold-font-weight` (if defined)\n * - `${name}-icon-size` (if defined)\n * - `${name}-text-transform` (if defined)\n * - `${name}-font-family` (if defined)\n * - `${name}-font-style` (if defined)\n *\n * @param presets - Typography presets object\n * @returns ConfigTokens object with $ prefixed keys\n *\n * @example\n * const customTokens = generateTypographyTokens({\n * myHeading: { fontSize: '24px', lineHeight: '32px', fontWeight: '700' },\n * body: { fontSize: '16px', lineHeight: '24px', fontWeight: '400' },\n * });\n */\nexport function generateTypographyTokens(\n presets: Record<string, TypographyPreset>,\n): ConfigTokens {\n const tokens: ConfigTokens = {} as ConfigTokens;\n\n for (const [name, preset] of Object.entries(presets)) {\n if (RESERVED_PRESET_NAMES.has(name)) {\n throw new Error(\n `Invalid typography preset name \"${name}\". This name is reserved as a preset modifier.`,\n );\n }\n\n tokens[`$${name}-font-size`] = preset.fontSize;\n tokens[`$${name}-line-height`] = preset.lineHeight;\n tokens[`$${name}-letter-spacing`] = preset.letterSpacing ?? 'normal';\n tokens[`$${name}-font-weight`] = preset.fontWeight;\n\n if (preset.boldFontWeight !== undefined) {\n tokens[`$${name}-bold-font-weight`] = preset.boldFontWeight;\n }\n\n if (preset.iconSize !== undefined) {\n tokens[`$${name}-icon-size`] = preset.iconSize;\n }\n\n if (preset.textTransform !== undefined) {\n tokens[`$${name}-text-transform`] = preset.textTransform;\n }\n\n if (preset.fontFamily !== undefined) {\n tokens[`$${name}-font-family`] = preset.fontFamily;\n }\n\n if (preset.fontStyle !== undefined) {\n tokens[`$${name}-font-style`] = preset.fontStyle;\n }\n }\n\n return tokens;\n}\n","/**\n * Configuration processing shared by runtime and build-time paths.\n *\n * Plugins are folded first and direct configuration wins. Keeping this step\n * independent from the DOM injector lets zero-runtime tooling reuse the exact\n * same precedence and style-engine setup without loading browser infrastructure.\n */\n\nimport { registerFunctionPolyfill, splitFunctions } from './functions';\nimport {\n isFunctionsPolyfillEnabled,\n setGlobalPolyfillsState,\n} from './config-state';\nimport { setGlobalPredefinedStates } from './states';\nimport {\n normalizeHandlerDefinition,\n registerHandler,\n} from './styles/predefined';\nimport {\n CUSTOM_UNITS,\n getGlobalParseFunctions,\n getGlobalParser,\n normalizeColorTokenValue,\n setGlobalPredefinedTokens,\n} from './utils/styles';\nimport { generateTypographyTokens } from './utils/typography';\n\nimport type { TastyConfig } from './config';\nimport type { FunctionsConfig } from './functions';\nimport type {\n CounterStyleDescriptors,\n FontFaceInput,\n FunctionDefinition,\n KeyframesSteps,\n PropertyDefinition,\n} from './injector/types';\nimport type { UnitHandler } from './parser/types';\nimport type { PropHandlerDefinition } from './prop-handlers';\nimport type { ConfigTokens, RecipeStyles, Styles } from './styles/types';\nimport type { StyleHandlerDefinition } from './utils/styles';\nimport type { TypographyPreset } from './utils/typography';\n\nexport interface NormalizedConfig {\n states: Record<string, string>;\n units: Record<string, string | UnitHandler>;\n functions: FunctionsConfig;\n handlers: Record<string, StyleHandlerDefinition>;\n handlerSources: Map<string, string>;\n propHandlers: Record<string, PropHandlerDefinition>;\n propHandlerSources: Map<string, string>;\n baseStyleProps: string[];\n properties: Record<string, PropertyDefinition>;\n keyframes: Record<string, KeyframesSteps>;\n fontFaces: Record<string, FontFaceInput>;\n counterStyles: Record<string, CounterStyleDescriptors>;\n replaceTokens: Record<string, string | number | boolean>;\n tokens: ConfigTokens;\n recipes: Record<string, RecipeStyles>;\n globalStyles: Record<string, Styles>;\n}\n\ntype WarnOnce = (key: string, message: string) => void;\n\n/** Apply parser and style-engine configuration shared by every renderer. */\nexport function applyStyleConfig(\n config: Partial<TastyConfig>,\n normalized: NormalizedConfig,\n warnOnce: WarnOnce,\n): Record<string, FunctionDefinition> {\n const tokenKeys = new Set(Object.keys(normalized.tokens));\n for (const key of Object.keys(normalized.replaceTokens)) {\n if (tokenKeys.has(key)) {\n warnOnce(\n `token-conflict-${key}`,\n `[Tasty] Token \"${key}\" is defined in both \\`tokens\\` and \\`replaceTokens\\`. ` +\n `\\`replaceTokens\\` performs parse-time substitution, so the \\`tokens\\` ` +\n `CSS custom property will be injected but never used by Tasty styles. ` +\n `Remove it from one of the two.`,\n );\n }\n }\n\n if (config.colorSpace) {\n warnOnce(\n 'colorSpace-deprecated',\n '[Tasty] configure({ colorSpace }) no longer has any effect and will be ' +\n 'removed in the next major. Colors are emitted as authored, and opacity ' +\n \"is applied with relative color syntax, which reads a color's channels \" +\n 'in the browser. To address channels yourself, write ' +\n '`oklch(from var(--name-color) l c h)` against the token.',\n );\n }\n\n if (Object.keys(normalized.states).length > 0) {\n setGlobalPredefinedStates(normalized.states);\n }\n\n const parser = getGlobalParser();\n if (config.parserCacheSize !== undefined) {\n parser.updateOptions({ cacheSize: config.parserCacheSize });\n }\n if (Object.keys(normalized.units).length > 0) {\n const currentUnits = parser.getUnits() ?? CUSTOM_UNITS;\n parser.setUnits({ ...currentUnits, ...normalized.units });\n }\n\n if (config.polyfills) setGlobalPolyfillsState(config.polyfills);\n\n const { parseFuncs, functionDefs } = splitFunctions(\n normalized.functions,\n (key, kind) => {\n warnOnce(\n `functions-mismatch-${key}`,\n kind === 'expected-definition'\n ? `[Tasty] functions[\"${key}\"]: a \"$$\"-prefixed key denotes a CSS @function ` +\n `and expects a definition object, but received a function. Entry ignored.`\n : `[Tasty] functions[\"${key}\"]: a bare key denotes a parse function and ` +\n `expects a function value, but received an object. ` +\n `Did you mean \"$$${key}\"? Entry ignored.`,\n );\n },\n );\n\n if (Object.keys(parseFuncs).length > 0) {\n const currentFuncs = getGlobalParseFunctions();\n parser.setFunctions({ ...currentFuncs, ...parseFuncs });\n Object.assign(currentFuncs, parseFuncs);\n }\n\n if (isFunctionsPolyfillEnabled()) {\n for (const [name, definition] of Object.entries(functionDefs)) {\n registerFunctionPolyfill(name, definition);\n }\n }\n\n for (const [name, definition] of Object.entries(normalized.handlers)) {\n const handler = normalizeHandlerDefinition(name, definition);\n registerHandler(handler, {\n key: name,\n source: normalized.handlerSources.get(name),\n });\n }\n\n if (Object.keys(normalized.replaceTokens).length > 0) {\n const processedTokens: Record<string, string> = {};\n for (const [key, value] of Object.entries(normalized.replaceTokens)) {\n if (key.startsWith('#')) {\n const normalizedValue = normalizeColorTokenValue(value);\n if (normalizedValue === null) continue;\n processedTokens[key] = String(normalizedValue);\n } else if (value !== false) {\n processedTokens[key] = String(value);\n }\n }\n setGlobalPredefinedTokens(processedTokens);\n }\n\n return functionDefs;\n}\n\nexport function normalizeConfig(\n config: Partial<TastyConfig>,\n): NormalizedConfig {\n let states: Record<string, string> = {};\n let units: Record<string, string | UnitHandler> = {};\n let functions: FunctionsConfig = {};\n let handlers: Record<string, StyleHandlerDefinition> = {};\n const handlerSources = new Map<string, string>();\n let propHandlers: Record<string, PropHandlerDefinition> = {};\n const propHandlerSources = new Map<string, string>();\n const baseStyleProps: string[] = [];\n let properties: Record<string, PropertyDefinition> = {};\n let keyframes: Record<string, KeyframesSteps> = {};\n let fontFaces: Record<string, FontFaceInput> = {};\n let counterStyles: Record<string, CounterStyleDescriptors> = {};\n let replaceTokens: Record<string, string | number | boolean> = {};\n let tokens: ConfigTokens = {} as ConfigTokens;\n let recipes: Record<string, RecipeStyles> = {};\n let presets: Record<string, TypographyPreset> = {};\n const globalStyles: Record<string, Styles> = {};\n\n for (const plugin of config.plugins ?? []) {\n if (plugin.states) states = { ...states, ...plugin.states };\n if (plugin.units) units = { ...units, ...plugin.units };\n if (plugin.functions) functions = { ...functions, ...plugin.functions };\n if (plugin.handlers) {\n handlers = { ...handlers, ...plugin.handlers };\n for (const key of Object.keys(plugin.handlers)) {\n handlerSources.set(key, `plugin \"${plugin.name}\"`);\n }\n }\n if (plugin.propHandlers) {\n propHandlers = { ...propHandlers, ...plugin.propHandlers };\n for (const key of Object.keys(plugin.propHandlers)) {\n propHandlerSources.set(key, `plugin \"${plugin.name}\"`);\n }\n }\n if (plugin.baseStyleProps) baseStyleProps.push(...plugin.baseStyleProps);\n if (plugin.properties) {\n properties = { ...properties, ...plugin.properties };\n }\n if (plugin.keyframes) keyframes = { ...keyframes, ...plugin.keyframes };\n if (plugin.fontFaces) fontFaces = { ...fontFaces, ...plugin.fontFaces };\n if (plugin.counterStyles) {\n counterStyles = { ...counterStyles, ...plugin.counterStyles };\n }\n if (plugin.replaceTokens) {\n replaceTokens = { ...replaceTokens, ...plugin.replaceTokens };\n }\n if (plugin.tokens) tokens = { ...tokens, ...plugin.tokens };\n if (plugin.recipes) recipes = { ...recipes, ...plugin.recipes };\n if (plugin.presets) presets = { ...presets, ...plugin.presets };\n if (plugin.globalStyles) {\n mergeGlobalStyles(globalStyles, plugin.globalStyles);\n }\n }\n\n if (config.states) states = { ...states, ...config.states };\n if (config.units) units = { ...units, ...config.units };\n if (config.functions) functions = { ...functions, ...config.functions };\n if (config.handlers) {\n handlers = { ...handlers, ...config.handlers };\n for (const key of Object.keys(config.handlers)) {\n handlerSources.set(key, 'configure()');\n }\n }\n if (config.propHandlers) {\n propHandlers = { ...propHandlers, ...config.propHandlers };\n for (const key of Object.keys(config.propHandlers)) {\n propHandlerSources.set(key, 'configure()');\n }\n }\n if (config.baseStyleProps) baseStyleProps.push(...config.baseStyleProps);\n if (config.properties) properties = { ...properties, ...config.properties };\n if (config.keyframes) keyframes = { ...keyframes, ...config.keyframes };\n if (config.fontFaces) fontFaces = { ...fontFaces, ...config.fontFaces };\n if (config.counterStyles) {\n counterStyles = { ...counterStyles, ...config.counterStyles };\n }\n if (config.replaceTokens) {\n replaceTokens = { ...replaceTokens, ...config.replaceTokens };\n }\n if (config.presets) presets = { ...presets, ...config.presets };\n\n if (Object.keys(presets).length > 0) {\n tokens = { ...generateTypographyTokens(presets), ...tokens };\n }\n\n if (config.tokens) tokens = { ...tokens, ...config.tokens };\n if (config.recipes) recipes = { ...recipes, ...config.recipes };\n if (config.globalStyles) mergeGlobalStyles(globalStyles, config.globalStyles);\n\n return {\n states,\n units,\n functions,\n handlers,\n handlerSources,\n propHandlers,\n propHandlerSources,\n baseStyleProps,\n properties,\n keyframes,\n fontFaces,\n counterStyles,\n replaceTokens,\n tokens,\n recipes,\n globalStyles,\n };\n}\n\nfunction mergeGlobalStyles(\n target: Record<string, Styles>,\n source: Record<string, Styles>,\n): void {\n for (const [selector, styles] of Object.entries(source)) {\n target[selector] = target[selector]\n ? { ...target[selector], ...styles }\n : styles;\n }\n}\n","/**\n * Recipe resolution utility.\n *\n * Resolves `recipe` style properties by looking up predefined recipe styles\n * from global configuration and merging them with the component's own styles.\n *\n * Resolution order per level (top-level and each sub-element independently):\n * base_recipe_1 base_recipe_2 → component styles → post_recipe_1 post_recipe_2\n *\n * The `/` separator splits base recipes (before component styles)\n * from post recipes (after component styles). All merges use mergeStyles\n * semantics: primitives and state maps with '' key fully replace;\n * state maps without '' key extend the existing value.\n *\n * Returns the same object reference if no recipes are present (zero overhead).\n */\n\nimport type { RecipeStyles, Styles } from '../styles/types';\n\nimport { isDevEnv } from './is-dev-env';\nimport { isSelector } from './is-selector';\nimport { mergeStyles } from './merge-styles';\n\nconst devMode = isDevEnv();\n\ninterface ParsedRecipeGroups {\n base: string[] | null;\n post: string[] | null;\n}\n\n/**\n * Parse a recipe string into base and post recipe name groups.\n *\n * Syntax: `'base1 base2 / post1 post2'`\n * - Names are space-separated within each group\n * - `/` separates base (before component) from post (after component) groups\n * - `/` is optional; if absent, all names are base\n * - `none` as the sole base value means \"no base recipes\"\n *\n * Returns `{ base: null, post: null }` if the string is empty or invalid.\n */\nfunction parseRecipeNames(value: unknown): ParsedRecipeGroups {\n const empty: ParsedRecipeGroups = { base: null, post: null };\n\n if (typeof value !== 'string') return empty;\n const trimmed = value.trim();\n if (trimmed === '') return empty;\n\n const slashIndex = trimmed.indexOf('/');\n\n if (slashIndex === -1) {\n if (trimmed === 'none') return empty;\n const names = splitNames(trimmed);\n return { base: names, post: null };\n }\n\n const basePart = trimmed.slice(0, slashIndex);\n const postPart = trimmed.slice(slashIndex + 1);\n\n return {\n base: basePart.trim() === 'none' ? null : splitNames(basePart),\n post: splitNames(postPart),\n };\n}\n\nfunction splitNames(s: string): string[] | null {\n const names = s.split(/\\s+/).filter(Boolean);\n return names.length > 0 ? names : null;\n}\n\n/**\n * Collect merged styles for a list of recipe names.\n * Each recipe is flat-spread on top of the previous.\n */\nfunction collectRecipeStyles(\n names: string[],\n recipes: Record<string, RecipeStyles>,\n): Record<string, unknown> {\n let merged: Record<string, unknown> = {};\n\n for (const name of names) {\n const recipeStyles = recipes[name];\n\n if (!recipeStyles) {\n if (devMode) {\n console.warn(\n `[Tasty] Recipe \"${name}\" not found. ` +\n `Make sure it is defined in configure({ recipes: { ... } }).`,\n );\n }\n continue;\n }\n\n merged = { ...merged, ...(recipeStyles as Record<string, unknown>) };\n }\n\n return merged;\n}\n\n/**\n * Resolve recipe references in a flat styles object (no sub-elements).\n * Returns null if no `recipe` key is present.\n *\n * Resolution: base recipes → component styles → post recipes (all via mergeStyles)\n */\nfunction resolveRecipesForLevel(\n styles: Record<string, unknown>,\n recipes: Record<string, RecipeStyles>,\n): Record<string, unknown> | null {\n if (!('recipe' in styles)) return null;\n\n const { base, post } = parseRecipeNames(styles.recipe);\n\n // Separate selector keys (sub-elements) from flat style properties.\n // mergeStyles handles selectors with its own semantics (e.g. false = delete),\n // but at this level we only want recipe merging on flat properties.\n\n const { recipe: _recipe, ...allRest } = styles;\n const flatStyles: Record<string, unknown> = {};\n const selectorStyles: Record<string, unknown> = {};\n\n for (const key of Object.keys(allRest)) {\n if (isSelector(key)) {\n selectorStyles[key] = allRest[key];\n } else {\n flatStyles[key] = allRest[key];\n }\n }\n\n if (!base && !post) {\n return allRest;\n }\n\n // 1. Merge base recipes, then component styles on top (via mergeStyles)\n let result: Record<string, unknown>;\n\n if (base) {\n const baseStyles = collectRecipeStyles(base, recipes);\n result = mergeStyles(baseStyles as Styles, flatStyles as Styles) as Record<\n string,\n unknown\n >;\n } else {\n result = { ...flatStyles };\n }\n\n // 2. Apply post recipes via mergeStyles (state map extend semantics)\n if (post) {\n const postStyles = collectRecipeStyles(post, recipes);\n result = mergeStyles(result as Styles, postStyles as Styles) as Record<\n string,\n unknown\n >;\n }\n\n // Re-attach selector keys unchanged\n for (const key of Object.keys(selectorStyles)) {\n result[key] = selectorStyles[key];\n }\n\n return result;\n}\n\n/**\n * Resolve all `recipe` style properties in a styles object.\n *\n * Handles both top-level and sub-element recipe references.\n * Returns the same object reference if no recipes are present anywhere\n * (zero overhead for the common case).\n *\n * @param styles - The styles object potentially containing `recipe` keys\n * @returns Resolved styles with recipe values merged in, or the original object if unchanged\n */\nexport function resolveRecipesWith(\n styles: Styles,\n recipes: Record<string, RecipeStyles> | null,\n): Styles {\n // Fast path: no recipes configured\n if (!recipes) return styles;\n\n let changed = false;\n\n // Resolve top-level recipe\n const topResolved = resolveRecipesForLevel(\n styles as Record<string, unknown>,\n recipes,\n );\n\n let result: Record<string, unknown>;\n\n if (topResolved) {\n changed = true;\n result = topResolved;\n } else {\n // Keep reference; a shallow copy is deferred until a sub-element actually changes\n result = styles as Record<string, unknown>;\n }\n\n // Resolve sub-element recipes\n const keys = Object.keys(result);\n\n for (const key of keys) {\n if (!isSelector(key)) continue;\n\n const subStyles = result[key];\n\n if (\n !subStyles ||\n typeof subStyles !== 'object' ||\n Array.isArray(subStyles)\n ) {\n continue;\n }\n\n const subRecord = subStyles as Record<string, unknown>;\n\n if (!('recipe' in subRecord)) continue;\n\n const subResolved = resolveRecipesForLevel(subRecord, recipes);\n\n if (subResolved) {\n if (!changed) {\n // First change in sub-elements -- need to shallow-copy the top level\n changed = true;\n result = { ...(styles as Record<string, unknown>) };\n }\n // Define an own data property so even an untrusted key cannot invoke an\n // inherited setter such as Object.prototype.__proto__.\n Object.defineProperty(result, key, {\n configurable: true,\n enumerable: true,\n value: subResolved,\n writable: true,\n });\n }\n }\n\n return changed ? (result as Styles) : styles;\n}\n"],"mappings":"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"}
|