@tenphi/tasty 0.0.0-snapshot.4d272f6 → 0.0.0-snapshot.4f98f70
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/README.md +10 -5
- package/dist/{collector-DMoQRxPK.d.ts → collector-LuU1vZ68.d.ts} +2 -2
- package/dist/{collector-DM5o7SIi.js → collector-WUJKpM4q.js} +3 -3
- package/dist/{collector-DM5o7SIi.js.map → collector-WUJKpM4q.js.map} +1 -1
- package/dist/{config-CtJeETqW.js → config-raGoEeGs.js} +170 -71
- package/dist/config-raGoEeGs.js.map +1 -0
- package/dist/{config-DdnOynVC.d.ts → config-vuCRkBWX.d.ts} +2 -2
- package/dist/core/index.d.ts +4 -4
- package/dist/core/index.js +5 -5
- package/dist/{core-CD2f33ch.js → core-CrPLif0D.js} +5 -5
- package/dist/{core-CD2f33ch.js.map → core-CrPLif0D.js.map} +1 -1
- package/dist/{css-writer-CUbBb8gL.js → css-writer-BaR8ywQm.js} +3 -3
- package/dist/{css-writer-CUbBb8gL.js.map → css-writer-BaR8ywQm.js.map} +1 -1
- package/dist/{format-rules-BFgS3646.js → format-rules-B_Cuw1ZS.js} +2 -2
- package/dist/{format-rules-BFgS3646.js.map → format-rules-B_Cuw1ZS.js.map} +1 -1
- package/dist/{hydrate-BZ1SUmKW.js → hydrate-DmVyww8Y.js} +2 -2
- package/dist/{hydrate-BZ1SUmKW.js.map → hydrate-DmVyww8Y.js.map} +1 -1
- package/dist/{index-C-4JKlJ1.d.ts → index-BpNrg6Tj.d.ts} +5 -5
- package/dist/{index-DTXQTYHU.d.ts → index-dUtwpOux.d.ts} +3 -2
- package/dist/index.d.ts +4 -4
- package/dist/index.js +6 -6
- package/dist/index.js.map +1 -1
- package/dist/{keyframes-DNpu5N3R.js → keyframes-C9OD_9bX.js} +3 -2
- package/dist/{keyframes-DNpu5N3R.js.map → keyframes-C9OD_9bX.js.map} +1 -1
- package/dist/{merge-styles-QCiE0R2O.js → merge-styles-B57eQpFZ.js} +2 -2
- package/dist/{merge-styles-QCiE0R2O.js.map → merge-styles-B57eQpFZ.js.map} +1 -1
- package/dist/{merge-styles-Dwdz1IsM.d.ts → merge-styles-CtDJMhpJ.d.ts} +2 -2
- package/dist/{resolve-recipes-CHSdSpso.js → resolve-recipes-J9mdpVSZ.js} +3 -3
- package/dist/{resolve-recipes-CHSdSpso.js.map → resolve-recipes-J9mdpVSZ.js.map} +1 -1
- package/dist/ssr/astro-client.js +1 -1
- package/dist/ssr/astro.d.ts +1 -12
- package/dist/ssr/astro.js +3 -3
- package/dist/ssr/astro.js.map +1 -1
- package/dist/ssr/index.d.ts +1 -1
- package/dist/ssr/index.js +3 -3
- package/dist/ssr/next.d.ts +1 -1
- package/dist/ssr/next.js +4 -4
- package/dist/ssr/next.js.map +1 -1
- package/dist/static/index.d.ts +2 -2
- package/dist/static/index.js +1 -1
- package/dist/static/index.js.map +1 -1
- package/dist/zero/babel.d.ts +1 -1
- package/dist/zero/babel.js +4 -4
- package/dist/zero/babel.js.map +1 -1
- package/dist/zero/index.d.ts +1 -1
- package/dist/zero/index.js +1 -1
- package/docs/dsl.md +14 -12
- package/docs/injector.md +2 -2
- package/package.json +3 -2
- package/tasty.config.ts +1 -0
- package/dist/config-CtJeETqW.js.map +0 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
8
|
<strong>Deterministic styling for stateful component systems.</strong><br>
|
|
9
|
-
A design-system styling engine that compiles component states into mutually exclusive selectors.
|
|
9
|
+
A design-system styling engine that compiles component states into mutually exclusive selectors, so complex components stay predictable as they evolve.
|
|
10
10
|
</p>
|
|
11
11
|
|
|
12
12
|
<p align="center">
|
|
@@ -23,6 +23,8 @@ It compiles state maps into **mutually exclusive selectors**, so for a given pro
|
|
|
23
23
|
|
|
24
24
|
That is the core guarantee: component styling resolves from declared state logic, not from source-order accidents or specificity fights.
|
|
25
25
|
|
|
26
|
+
The practical payoff shows up later: adding states, variants, and overrides stays inside the state map instead of reopening selector logic by hand.
|
|
27
|
+
|
|
26
28
|
Tasty fits best when you are building a design system or component library with intersecting states, variants, tokens, sub-elements, responsive rules, and extension semantics that need to stay predictable over time.
|
|
27
29
|
|
|
28
30
|
On top of that foundation, Tasty gives teams a governed styling model: a CSS-like DSL, tokens, recipes, typed style props, sub-elements, and multiple rendering modes.
|
|
@@ -35,6 +37,7 @@ On top of that foundation, Tasty gives teams a governed styling model: a CSS-lik
|
|
|
35
37
|
## Why Tasty
|
|
36
38
|
|
|
37
39
|
- **Deterministic composition, not cascade fights** — Stateful styles resolve from the state map you declared, not from selector competition. See [How It Actually Works](#how-it-actually-works).
|
|
40
|
+
- **Easier to extend over time** — When components gain new states, variants, or overrides, you update declared branches instead of re-deriving selector interactions by hand.
|
|
38
41
|
- **Built for design-system teams** — Best fit for reusable component systems with complex state interactions.
|
|
39
42
|
- **A governed styling model, not just syntax sugar** — Design-system authors define the styling language product teams consume.
|
|
40
43
|
- **DSL that still feels like CSS** — Familiar property names, less selector boilerplate. Start with the [Style DSL](docs/dsl.md), then use [Style Properties](docs/styles.md) as the handler reference.
|
|
@@ -489,11 +492,13 @@ All sizes measured with [size-limit](https://github.com/ai/size-limit) — minif
|
|
|
489
492
|
|
|
490
493
|
| Entry point | Size |
|
|
491
494
|
|-------------|------|
|
|
492
|
-
| `@tenphi/tasty` (runtime + SSR) |
|
|
493
|
-
| `@tenphi/tasty/core` (runtime, no SSR) |
|
|
494
|
-
| `@tenphi/tasty/static` (zero-runtime) |
|
|
495
|
+
| `@tenphi/tasty` (runtime + SSR) | 50.19 kB |
|
|
496
|
+
| `@tenphi/tasty/core` (runtime, no SSR) | 47.76 kB |
|
|
497
|
+
| `@tenphi/tasty/static` (zero-runtime) | 16.43 kB |
|
|
498
|
+
| `@tenphi/tasty/zero` (programmatic extraction) | 29.6 kB |
|
|
499
|
+
| `@tenphi/tasty/babel-plugin` (Babel plugin entry) | 43.7 kB |
|
|
495
500
|
|
|
496
|
-
Run `pnpm size`
|
|
501
|
+
Run `pnpm size` to reproduce (outputs may shift slightly with releases).
|
|
497
502
|
|
|
498
503
|
### Runtime Benchmarks
|
|
499
504
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as StyleResult } from "./index-
|
|
1
|
+
import { n as StyleResult } from "./index-dUtwpOux.js";
|
|
2
2
|
|
|
3
3
|
//#region src/ssr/collector.d.ts
|
|
4
4
|
declare class ServerStyleCollector {
|
|
@@ -95,4 +95,4 @@ declare class ServerStyleCollector {
|
|
|
95
95
|
}
|
|
96
96
|
//#endregion
|
|
97
97
|
export { ServerStyleCollector as t };
|
|
98
|
-
//# sourceMappingURL=collector-
|
|
98
|
+
//# sourceMappingURL=collector-LuU1vZ68.d.ts.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { F as formatFontFaceRule, P as fontFaceContentHash, a as getGlobalCounterStyle, ct as hashString, i as getGlobalConfigTokens, j as formatCounterStyleRule, o as getGlobalFontFace, r as getEffectiveProperties, u as getGlobalStyles, x as renderStyles } from "./config-
|
|
2
|
-
import { n as formatPropertyCSS, t as formatRules } from "./format-rules-
|
|
1
|
+
import { F as formatFontFaceRule, P as fontFaceContentHash, a as getGlobalCounterStyle, ct as hashString, i as getGlobalConfigTokens, j as formatCounterStyleRule, o as getGlobalFontFace, r as getEffectiveProperties, u as getGlobalStyles, x as renderStyles } from "./config-raGoEeGs.js";
|
|
2
|
+
import { n as formatPropertyCSS, t as formatRules } from "./format-rules-B_Cuw1ZS.js";
|
|
3
3
|
import { t as formatGlobalRules } from "./format-global-rules-Dbc_1tc3.js";
|
|
4
4
|
//#region src/ssr/collector.ts
|
|
5
5
|
/**
|
|
@@ -227,4 +227,4 @@ var ServerStyleCollector = class {
|
|
|
227
227
|
//#endregion
|
|
228
228
|
export { ServerStyleCollector as t };
|
|
229
229
|
|
|
230
|
-
//# sourceMappingURL=collector-
|
|
230
|
+
//# sourceMappingURL=collector-WUJKpM4q.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collector-DM5o7SIi.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 (`t${hash}`), formats CSS rules into text,\n * and tracks rendered class 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 getGlobalCounterStyle,\n getGlobalFontFace,\n getGlobalConfigTokens,\n} from '../config';\nimport { formatCounterStyleRule } from '../counter-style';\nimport { fontFaceContentHash, formatFontFaceRule } from '../font-face';\nimport { renderStyles } from '../pipeline';\nimport type { StyleResult } from '../pipeline';\nimport { hashString } from '../utils/hash';\nimport { formatPropertyCSS } from './format-property';\nimport { formatGlobalRules } from './format-global-rules';\nimport { formatRules } from './format-rules';\n\nfunction generateClassName(cacheKey: string): string {\n return `t${hashString(cacheKey)}`;\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 keyframesCounter = 0;\n private counterStyleCounter = 0;\n private internalsCollected = false;\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 = getGlobalFontFace();\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 = getGlobalCounterStyle();\n if (globalCS) {\n for (const [name, descriptors] of Object.entries(globalCS)) {\n const css = formatCounterStyleRule(name, descriptors);\n this.collectCounterStyle(name, css);\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 = 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 providedName ?? `k${this.keyframesCounter++}`;\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.\n */\n collectCounterStyle(name: string, css: string): void {\n if (!this.counterStyleRules.has(name)) {\n this.counterStyleRules.set(name, css);\n }\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 providedName ?? `cs${this.counterStyleCounter++}`;\n }\n\n /**\n * Record global styles (from useGlobalStyles). Deduplicated by key.\n */\n collectGlobalStyles(key: string, css: string): void {\n if (!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 collectRawCSS(key: string, css: string): void {\n if (!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.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.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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"collector-WUJKpM4q.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 (`t${hash}`), formats CSS rules into text,\n * and tracks rendered class 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 getGlobalCounterStyle,\n getGlobalFontFace,\n getGlobalConfigTokens,\n} from '../config';\nimport { formatCounterStyleRule } from '../counter-style';\nimport { fontFaceContentHash, formatFontFaceRule } from '../font-face';\nimport { renderStyles } from '../pipeline';\nimport type { StyleResult } from '../pipeline';\nimport { hashString } from '../utils/hash';\nimport { formatPropertyCSS } from './format-property';\nimport { formatGlobalRules } from './format-global-rules';\nimport { formatRules } from './format-rules';\n\nfunction generateClassName(cacheKey: string): string {\n return `t${hashString(cacheKey)}`;\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 keyframesCounter = 0;\n private counterStyleCounter = 0;\n private internalsCollected = false;\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 = getGlobalFontFace();\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 = getGlobalCounterStyle();\n if (globalCS) {\n for (const [name, descriptors] of Object.entries(globalCS)) {\n const css = formatCounterStyleRule(name, descriptors);\n this.collectCounterStyle(name, css);\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 = 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 providedName ?? `k${this.keyframesCounter++}`;\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.\n */\n collectCounterStyle(name: string, css: string): void {\n if (!this.counterStyleRules.has(name)) {\n this.counterStyleRules.set(name, css);\n }\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 providedName ?? `cs${this.counterStyleCounter++}`;\n }\n\n /**\n * Record global styles (from useGlobalStyles). Deduplicated by key.\n */\n collectGlobalStyles(key: string, css: string): void {\n if (!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 collectRawCSS(key: string, css: string): void {\n if (!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.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.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"],"mappings":";;;;;;;;;;;;;;;AA4BA,SAAS,kBAAkB,UAA0B;AACnD,QAAO,IAAI,WAAW,SAAS;;AAGjC,IAAa,uBAAb,MAAkC;CAChC,yBAAiB,IAAI,KAAqB;CAC1C,sCAA8B,IAAI,KAAqB;CACvD,8BAAsB,IAAI,KAAa;CACvC,gCAAwB,IAAI,KAAqB;CACjD,sCAA8B,IAAI,KAAa;CAC/C,gCAAwB,IAAI,KAAqB;CACjD,sCAA8B,IAAI,KAAa;CAC/C,+BAAuB,IAAI,KAAqB;CAChD,oCAA4B,IAAI,KAAa;CAC7C,yBAAiB,IAAI,KAAqB;CAC1C,iCAAyB,IAAI,KAAa;CAC1C,gCAAwB,IAAI,KAAqB;CACjD,sCAA8B,IAAI,KAAa;CAC/C,oCAA4B,IAAI,KAAqB;CACrD,0CAAkC,IAAI,KAAa;CACnD,mBAA2B;CAC3B,sBAA8B;CAC9B,qBAA6B;;;;;;;;;;CAW7B,mBAAyB;AACvB,MAAI,KAAK,mBAAoB;AAC7B,OAAK,qBAAqB;AAE1B,OAAK,MAAM,CAAC,OAAO,eAAe,OAAO,QACvC,wBAAwB,CACzB,EAAE;GACD,MAAM,MAAM,kBAAkB,OAAO,WAAW;AAChD,OAAI,IACF,MAAK,gBAAgB,UAAU,SAAS,IAAI;;EAIhD,MAAM,cAAc,uBAAuB;AAC3C,MAAI,eAAe,OAAO,KAAK,YAAY,CAAC,SAAS,GAAG;GACtD,MAAM,aAAa,aAAa,aAAa,QAAQ;AACrD,OAAI,WAAW,SAAS,GAAG;IACzB,MAAM,MAAM,kBAAkB,WAAW;AACzC,QAAI,IACF,MAAK,oBAAoB,mBAAmB,IAAI;;;EAKtD,MAAM,WAAW,mBAAmB;AACpC,MAAI,SACF,MAAK,MAAM,CAAC,QAAQ,UAAU,OAAO,QAAQ,SAAS,EAAE;GACtD,MAAM,cAAc,MAAM,QAAQ,MAAM,GAAG,QAAQ,CAAC,MAAM;AAC1D,QAAK,MAAM,QAAQ,aAAa;IAC9B,MAAM,OAAO,oBAAoB,QAAQ,KAAK;IAC9C,MAAM,MAAM,mBAAmB,QAAQ,KAAK;AAC5C,SAAK,gBAAgB,MAAM,IAAI;;;EAKrC,MAAM,WAAW,uBAAuB;AACxC,MAAI,SACF,MAAK,MAAM,CAAC,MAAM,gBAAgB,OAAO,QAAQ,SAAS,EAAE;GAC1D,MAAM,MAAM,uBAAuB,MAAM,YAAY;AACrD,QAAK,oBAAoB,MAAM,IAAI;;EAIvC,MAAM,eAAe,iBAAiB;AACtC,MAAI;QACG,MAAM,CAAC,UAAU,WAAW,OAAO,QAAQ,aAAa,CAC3D,KAAI,OAAO,KAAK,OAAO,CAAC,SAAS,GAAG;IAClC,MAAM,QAAQ,aAAa,QAAQ,SAAS;AAC5C,QAAI,MAAM,SAAS,GAAG;KACpB,MAAM,MAAM,kBAAkB,MAAM;AACpC,SAAI,IACF,MAAK,oBAAoB,mBAAmB,YAAY,IAAI;;;;;;;;;CAYxE,kBAAkB,UAGhB;EACA,MAAM,WAAW,KAAK,oBAAoB,IAAI,SAAS;AACvD,MAAI,SACF,QAAO;GAAE,WAAW;GAAU,iBAAiB;GAAO;EAGxD,MAAM,YAAY,kBAAkB,SAAS;AAC7C,OAAK,oBAAoB,IAAI,UAAU,UAAU;AAEjD,SAAO;GAAE;GAAW,iBAAiB;GAAM;;;;;;CAO7C,aACE,UACA,WACA,OACM;AACN,MAAI,KAAK,OAAO,IAAI,SAAS,CAAE;EAC/B,MAAM,MAAM,YAAY,OAAO,UAAU;AACzC,MAAI,IACF,MAAK,OAAO,IAAI,UAAU,IAAI;;;;;CAOlC,gBAAgB,MAAc,KAAmB;AAC/C,MAAI,CAAC,KAAK,cAAc,IAAI,KAAK,CAC/B,MAAK,cAAc,IAAI,MAAM,IAAI;;;;;CAOrC,iBAAiB,MAAc,KAAmB;AAChD,MAAI,CAAC,KAAK,cAAc,IAAI,KAAK,CAC/B,MAAK,cAAc,IAAI,MAAM,IAAI;;;;;CAOrC,qBAAqB,cAA+B;AAClD,SAAO,gBAAgB,IAAI,KAAK;;;;;CAMlC,gBAAgB,KAAa,KAAmB;AAC9C,MAAI,CAAC,KAAK,cAAc,IAAI,IAAI,CAC9B,MAAK,cAAc,IAAI,KAAK,IAAI;;;;;CAOpC,oBAAoB,MAAc,KAAmB;AACnD,MAAI,CAAC,KAAK,kBAAkB,IAAI,KAAK,CACnC,MAAK,kBAAkB,IAAI,MAAM,IAAI;;;;;CAOzC,yBAAyB,cAA+B;AACtD,SAAO,gBAAgB,KAAK,KAAK;;;;;CAMnC,oBAAoB,KAAa,KAAmB;AAClD,MAAI,CAAC,KAAK,aAAa,IAAI,IAAI,CAC7B,MAAK,aAAa,IAAI,KAAK,IAAI;;;;;CAOnC,cAAc,KAAa,KAAmB;AAC5C,MAAI,CAAC,KAAK,OAAO,IAAI,IAAI,CACvB,MAAK,OAAO,IAAI,KAAK,IAAI;;;;;;;CAS7B,SAAiB;EACf,MAAM,QAAkB,EAAE;AAE1B,OAAK,MAAM,OAAO,KAAK,cAAc,QAAQ,CAC3C,OAAM,KAAK,IAAI;AAGjB,OAAK,MAAM,OAAO,KAAK,cAAc,QAAQ,CAC3C,OAAM,KAAK,IAAI;AAGjB,OAAK,MAAM,OAAO,KAAK,kBAAkB,QAAQ,CAC/C,OAAM,KAAK,IAAI;AAGjB,OAAK,MAAM,OAAO,KAAK,OAAO,QAAQ,CACpC,OAAM,KAAK,IAAI;AAGjB,OAAK,MAAM,OAAO,KAAK,aAAa,QAAQ,CAC1C,OAAM,KAAK,IAAI;AAGjB,OAAK,MAAM,OAAO,KAAK,OAAO,QAAQ,CACpC,OAAM,KAAK,IAAI;AAGjB,OAAK,MAAM,OAAO,KAAK,cAAc,QAAQ,CAC3C,OAAM,KAAK,IAAI;AAGjB,SAAO,MAAM,KAAK,KAAK;;;;;;CAOzB,WAAmB;EACjB,MAAM,QAAkB,EAAE;AAE1B,OAAK,MAAM,CAAC,MAAM,QAAQ,KAAK,cAC7B,KAAI,CAAC,KAAK,oBAAoB,IAAI,KAAK,EAAE;AACvC,SAAM,KAAK,IAAI;AACf,QAAK,oBAAoB,IAAI,KAAK;;AAItC,OAAK,MAAM,CAAC,KAAK,QAAQ,KAAK,cAC5B,KAAI,CAAC,KAAK,oBAAoB,IAAI,IAAI,EAAE;AACtC,SAAM,KAAK,IAAI;AACf,QAAK,oBAAoB,IAAI,IAAI;;AAIrC,OAAK,MAAM,CAAC,KAAK,QAAQ,KAAK,kBAC5B,KAAI,CAAC,KAAK,wBAAwB,IAAI,IAAI,EAAE;AAC1C,SAAM,KAAK,IAAI;AACf,QAAK,wBAAwB,IAAI,IAAI;;AAIzC,OAAK,MAAM,CAAC,KAAK,QAAQ,KAAK,OAC5B,KAAI,CAAC,KAAK,eAAe,IAAI,IAAI,EAAE;AACjC,SAAM,KAAK,IAAI;AACf,QAAK,eAAe,IAAI,IAAI;;AAIhC,OAAK,MAAM,CAAC,KAAK,QAAQ,KAAK,aAC5B,KAAI,CAAC,KAAK,kBAAkB,IAAI,IAAI,EAAE;AACpC,SAAM,KAAK,IAAI;AACf,QAAK,kBAAkB,IAAI,IAAI;;AAInC,OAAK,MAAM,CAAC,KAAK,QAAQ,KAAK,OAC5B,KAAI,CAAC,KAAK,YAAY,IAAI,IAAI,EAAE;AAC9B,SAAM,KAAK,IAAI;AACf,QAAK,YAAY,IAAI,IAAI;;AAI7B,OAAK,MAAM,CAAC,MAAM,QAAQ,KAAK,cAC7B,KAAI,CAAC,KAAK,oBAAoB,IAAI,KAAK,EAAE;AACvC,SAAM,KAAK,IAAI;AACf,QAAK,oBAAoB,IAAI,KAAK;;AAItC,SAAO,MAAM,KAAK,KAAK;;CAGzB,oCAA4B,IAAI,KAAa;;;;;CAM7C,wBAAkC;EAChC,MAAM,QAAkB,EAAE;AAC1B,OAAK,MAAM,aAAa,KAAK,oBAAoB,QAAQ,CACvD,KAAI,CAAC,KAAK,kBAAkB,IAAI,UAAU,EAAE;AAC1C,QAAK,kBAAkB,IAAI,UAAU;AACrC,SAAM,KAAK,UAAU;;AAGzB,SAAO"}
|
|
@@ -1439,7 +1439,7 @@ function resolveUntilStable(value, opts, recurse, maxIterations = 10) {
|
|
|
1439
1439
|
function classify(raw, opts, recurse) {
|
|
1440
1440
|
const token = raw.trim();
|
|
1441
1441
|
if (!token) return {
|
|
1442
|
-
bucket:
|
|
1442
|
+
bucket: 2,
|
|
1443
1443
|
processed: ""
|
|
1444
1444
|
};
|
|
1445
1445
|
{
|
|
@@ -1461,31 +1461,31 @@ function classify(raw, opts, recurse) {
|
|
|
1461
1461
|
if (depth !== 0) {
|
|
1462
1462
|
console.warn("tasty: skipped invalid function token with unmatched parentheses:", token);
|
|
1463
1463
|
return {
|
|
1464
|
-
bucket:
|
|
1464
|
+
bucket: 2,
|
|
1465
1465
|
processed: ""
|
|
1466
1466
|
};
|
|
1467
1467
|
}
|
|
1468
1468
|
}
|
|
1469
1469
|
if (token.startsWith("\"") && token.endsWith("\"") || token.startsWith("'") && token.endsWith("'")) return {
|
|
1470
|
-
bucket:
|
|
1470
|
+
bucket: 1,
|
|
1471
1471
|
processed: token
|
|
1472
1472
|
};
|
|
1473
1473
|
if (token.startsWith("$$")) {
|
|
1474
1474
|
const name = token.slice(2);
|
|
1475
1475
|
if (/^[a-z_][a-z0-9-_]*$/i.test(name)) return {
|
|
1476
|
-
bucket:
|
|
1476
|
+
bucket: 1,
|
|
1477
1477
|
processed: `--${name}`
|
|
1478
1478
|
};
|
|
1479
1479
|
}
|
|
1480
1480
|
if (token.startsWith("##")) {
|
|
1481
1481
|
const name = token.slice(2);
|
|
1482
1482
|
if (/^[a-z_][a-z0-9-_]*$/i.test(name)) return {
|
|
1483
|
-
bucket:
|
|
1483
|
+
bucket: 1,
|
|
1484
1484
|
processed: `--${name}-color`
|
|
1485
1485
|
};
|
|
1486
1486
|
}
|
|
1487
1487
|
if (token === "#current") return {
|
|
1488
|
-
bucket:
|
|
1488
|
+
bucket: 0,
|
|
1489
1489
|
processed: "currentcolor"
|
|
1490
1490
|
};
|
|
1491
1491
|
const currentAlphaMatch = token.match(/^#current\.(\$[a-z_][a-z0-9-_]*|[0-9]+)$/i);
|
|
@@ -1496,7 +1496,7 @@ function classify(raw, opts, recurse) {
|
|
|
1496
1496
|
else if (rawAlpha === "0") percentage = "0%";
|
|
1497
1497
|
else percentage = `${parseFloat("." + rawAlpha) * 100}%`;
|
|
1498
1498
|
return {
|
|
1499
|
-
bucket:
|
|
1499
|
+
bucket: 0,
|
|
1500
1500
|
processed: `color-mix(in oklab, currentcolor ${percentage}, transparent)`
|
|
1501
1501
|
};
|
|
1502
1502
|
}
|
|
@@ -1569,7 +1569,7 @@ function classify(raw, opts, recurse) {
|
|
|
1569
1569
|
const constructed = `${normalizedFunc}(${hasModernAlpha || hasLegacyAlpha ? normalizeArgs(hasModernAlpha ? args.slice(0, slashIdx).trim() : args.slice(0, lastTopLevelComma).trim()) : normalizeArgs(args)} / ${alpha})`;
|
|
1570
1570
|
if (!COLOR_FUNCS.has(normalizedFunc) && opts.funcs && normalizedFunc in opts.funcs) return classify(constructed, opts, recurse);
|
|
1571
1571
|
return {
|
|
1572
|
-
bucket:
|
|
1572
|
+
bucket: 0,
|
|
1573
1573
|
processed: constructed
|
|
1574
1574
|
};
|
|
1575
1575
|
}
|
|
@@ -1580,11 +1580,11 @@ function classify(raw, opts, recurse) {
|
|
|
1580
1580
|
}
|
|
1581
1581
|
}
|
|
1582
1582
|
if (token.match(/^var\(--([a-z0-9-]+)-color\)$/)) return {
|
|
1583
|
-
bucket:
|
|
1583
|
+
bucket: 0,
|
|
1584
1584
|
processed: token
|
|
1585
1585
|
};
|
|
1586
1586
|
if (token.startsWith("url(")) return {
|
|
1587
|
-
bucket:
|
|
1587
|
+
bucket: 1,
|
|
1588
1588
|
processed: token
|
|
1589
1589
|
};
|
|
1590
1590
|
if (token[0] === "$") {
|
|
@@ -1593,7 +1593,7 @@ function classify(raw, opts, recurse) {
|
|
|
1593
1593
|
const name = identMatch[1];
|
|
1594
1594
|
const processed = `var(--${name})`;
|
|
1595
1595
|
return {
|
|
1596
|
-
bucket: name.endsWith("-color") ?
|
|
1596
|
+
bucket: name.endsWith("-color") ? 0 : 1,
|
|
1597
1597
|
processed
|
|
1598
1598
|
};
|
|
1599
1599
|
}
|
|
@@ -1607,17 +1607,17 @@ function classify(raw, opts, recurse) {
|
|
|
1607
1607
|
else if (rawAlpha === "0") alpha = "0";
|
|
1608
1608
|
else alpha = `.${rawAlpha}`;
|
|
1609
1609
|
return {
|
|
1610
|
-
bucket:
|
|
1610
|
+
bucket: 0,
|
|
1611
1611
|
processed: `${getColorSpaceFunc()}(var(--${base}-color-${getColorSpaceSuffix()}) / ${alpha})`
|
|
1612
1612
|
};
|
|
1613
1613
|
}
|
|
1614
1614
|
const name = token.slice(1);
|
|
1615
1615
|
if (RE_HEX.test(name)) return {
|
|
1616
|
-
bucket:
|
|
1616
|
+
bucket: 0,
|
|
1617
1617
|
processed: `var(--${name}-color, #${name})`
|
|
1618
1618
|
};
|
|
1619
1619
|
return {
|
|
1620
|
-
bucket:
|
|
1620
|
+
bucket: 0,
|
|
1621
1621
|
processed: `var(--${name}-color)`
|
|
1622
1622
|
};
|
|
1623
1623
|
}
|
|
@@ -1628,7 +1628,7 @@ function classify(raw, opts, recurse) {
|
|
|
1628
1628
|
if (COLOR_FUNCS.has(fname)) {
|
|
1629
1629
|
const argProcessed = recurse(inner).output.replace(/,\s+/g, ",");
|
|
1630
1630
|
return {
|
|
1631
|
-
bucket:
|
|
1631
|
+
bucket: 0,
|
|
1632
1632
|
processed: `${canonicalFuncName(fname)}(${argProcessed})`
|
|
1633
1633
|
};
|
|
1634
1634
|
}
|
|
@@ -1641,7 +1641,7 @@ function classify(raw, opts, recurse) {
|
|
|
1641
1641
|
}
|
|
1642
1642
|
const argProcessed = recurse(inner).output;
|
|
1643
1643
|
return {
|
|
1644
|
-
bucket:
|
|
1644
|
+
bucket: 1,
|
|
1645
1645
|
processed: `${canonicalFuncName(fname)}(${argProcessed})`
|
|
1646
1646
|
};
|
|
1647
1647
|
}
|
|
@@ -1649,10 +1649,9 @@ function classify(raw, opts, recurse) {
|
|
|
1649
1649
|
const colorMatch = token.slice(1, -1).match(/^#([a-z0-9-]+)\s*,\s*(.*)$/i);
|
|
1650
1650
|
if (colorMatch) {
|
|
1651
1651
|
const [, name, fallback] = colorMatch;
|
|
1652
|
-
const processedFallback = recurse(fallback).output;
|
|
1653
1652
|
return {
|
|
1654
|
-
bucket:
|
|
1655
|
-
processed: `var(--${name}-color, ${
|
|
1653
|
+
bucket: 0,
|
|
1654
|
+
processed: `var(--${name}-color, ${recurse(fallback).output})`
|
|
1656
1655
|
};
|
|
1657
1656
|
}
|
|
1658
1657
|
}
|
|
@@ -1662,18 +1661,15 @@ function classify(raw, opts, recurse) {
|
|
|
1662
1661
|
const [, name, fallback] = match;
|
|
1663
1662
|
const processedFallback = recurse(fallback).output;
|
|
1664
1663
|
return {
|
|
1665
|
-
bucket: name.endsWith("-color") ?
|
|
1664
|
+
bucket: name.endsWith("-color") ? 0 : 1,
|
|
1666
1665
|
processed: `var(--${name}, ${processedFallback})`
|
|
1667
1666
|
};
|
|
1668
1667
|
}
|
|
1669
1668
|
}
|
|
1670
|
-
if (token[0] === "(" && token[token.length - 1] === ")") {
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
processed: `calc(${innerProcessed})`
|
|
1675
|
-
};
|
|
1676
|
-
}
|
|
1669
|
+
if (token[0] === "(" && token[token.length - 1] === ")") return {
|
|
1670
|
+
bucket: 1,
|
|
1671
|
+
processed: `calc(${recurse(token.slice(1, -1)).output})`
|
|
1672
|
+
};
|
|
1677
1673
|
const um = token.match(RE_UNIT_NUM);
|
|
1678
1674
|
if (um) {
|
|
1679
1675
|
const unit = um[1];
|
|
@@ -1683,47 +1679,43 @@ function classify(raw, opts, recurse) {
|
|
|
1683
1679
|
const rawMatch = handler.match(RE_RAW_UNIT);
|
|
1684
1680
|
if (rawMatch) {
|
|
1685
1681
|
const [, baseNum, cssUnit] = rawMatch;
|
|
1686
|
-
const resolved = resolveUntilStable(`${numericPart * parseFloat(baseNum)}${cssUnit}`, opts, recurse);
|
|
1687
1682
|
return {
|
|
1688
|
-
bucket:
|
|
1689
|
-
processed:
|
|
1683
|
+
bucket: 1,
|
|
1684
|
+
processed: resolveUntilStable(`${numericPart * parseFloat(baseNum)}${cssUnit}`, opts, recurse)
|
|
1690
1685
|
};
|
|
1691
1686
|
}
|
|
1692
1687
|
const base = handler;
|
|
1693
1688
|
if (numericPart === 1) return {
|
|
1694
|
-
bucket:
|
|
1689
|
+
bucket: 1,
|
|
1695
1690
|
processed: base
|
|
1696
1691
|
};
|
|
1697
1692
|
return {
|
|
1698
|
-
bucket:
|
|
1693
|
+
bucket: 1,
|
|
1699
1694
|
processed: `calc(${numericPart} * ${base})`
|
|
1700
1695
|
};
|
|
1701
|
-
} else {
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
processed: inner
|
|
1706
|
-
};
|
|
1707
|
-
}
|
|
1696
|
+
} else return {
|
|
1697
|
+
bucket: 1,
|
|
1698
|
+
processed: handler(numericPart)
|
|
1699
|
+
};
|
|
1708
1700
|
}
|
|
1709
1701
|
if (/^[+-]?(?:\d*\.\d+|\d+)[a-z%]+$/.test(token)) return {
|
|
1710
|
-
bucket:
|
|
1702
|
+
bucket: 1,
|
|
1711
1703
|
processed: token
|
|
1712
1704
|
};
|
|
1713
1705
|
if (RE_NUMBER.test(token)) return {
|
|
1714
|
-
bucket:
|
|
1706
|
+
bucket: 1,
|
|
1715
1707
|
processed: token
|
|
1716
1708
|
};
|
|
1717
1709
|
if (VALUE_KEYWORDS.has(token)) return {
|
|
1718
|
-
bucket:
|
|
1710
|
+
bucket: 1,
|
|
1719
1711
|
processed: token
|
|
1720
1712
|
};
|
|
1721
1713
|
if (token === "transparent" || token === "currentcolor") return {
|
|
1722
|
-
bucket:
|
|
1714
|
+
bucket: 0,
|
|
1723
1715
|
processed: token
|
|
1724
1716
|
};
|
|
1725
1717
|
return {
|
|
1726
|
-
bucket:
|
|
1718
|
+
bucket: 2,
|
|
1727
1719
|
processed: token
|
|
1728
1720
|
};
|
|
1729
1721
|
}
|
|
@@ -1823,13 +1815,13 @@ var StyleParser = class {
|
|
|
1823
1815
|
return;
|
|
1824
1816
|
}
|
|
1825
1817
|
switch (bucket) {
|
|
1826
|
-
case
|
|
1818
|
+
case 0:
|
|
1827
1819
|
currentPart.colors.push(processed);
|
|
1828
1820
|
break;
|
|
1829
|
-
case
|
|
1821
|
+
case 1:
|
|
1830
1822
|
currentPart.values.push(processed);
|
|
1831
1823
|
break;
|
|
1832
|
-
case
|
|
1824
|
+
case 2:
|
|
1833
1825
|
currentPart.mods.push(processed);
|
|
1834
1826
|
break;
|
|
1835
1827
|
}
|
|
@@ -6089,6 +6081,7 @@ function simplifyAnd(children) {
|
|
|
6089
6081
|
terms = sortTerms(terms);
|
|
6090
6082
|
terms = applyAbsorptionAnd(terms);
|
|
6091
6083
|
terms = applyConsensusAnd(terms);
|
|
6084
|
+
terms = pruneContradictedOrBranches(terms);
|
|
6092
6085
|
if (terms.length === 0) return trueCondition();
|
|
6093
6086
|
if (terms.length === 1) return terms[0];
|
|
6094
6087
|
return {
|
|
@@ -6375,11 +6368,14 @@ function hasContainerStyleConflict(terms) {
|
|
|
6375
6368
|
*/
|
|
6376
6369
|
function buildImpliedNegationCheck(terms) {
|
|
6377
6370
|
const positiveValues = /* @__PURE__ */ new Map();
|
|
6371
|
+
const negatedBooleanAttrs = /* @__PURE__ */ new Set();
|
|
6378
6372
|
for (const term of terms) {
|
|
6379
|
-
if (term.kind !== "state"
|
|
6380
|
-
if (term.
|
|
6381
|
-
if (term.
|
|
6382
|
-
|
|
6373
|
+
if (term.kind !== "state") continue;
|
|
6374
|
+
if (!term.negated) {
|
|
6375
|
+
if (term.type === "container" && term.subtype === "style") {
|
|
6376
|
+
if (term.propertyValue !== void 0) positiveValues.set(`c:${term.containerName || "_"}:${term.property}`, term.propertyValue);
|
|
6377
|
+
} else if (term.type === "modifier" && term.value !== void 0) positiveValues.set(`m:${term.attribute}`, term.value);
|
|
6378
|
+
} else if (term.type === "modifier" && term.value === void 0) negatedBooleanAttrs.add(term.attribute);
|
|
6383
6379
|
}
|
|
6384
6380
|
return (term) => {
|
|
6385
6381
|
if (term.kind !== "state" || !term.negated) return false;
|
|
@@ -6389,6 +6385,7 @@ function buildImpliedNegationCheck(terms) {
|
|
|
6389
6385
|
return pos !== void 0 && term.propertyValue !== pos;
|
|
6390
6386
|
}
|
|
6391
6387
|
if (term.type === "modifier" && term.value !== void 0) {
|
|
6388
|
+
if (negatedBooleanAttrs.has(term.attribute)) return true;
|
|
6392
6389
|
const pos = positiveValues.get(`m:${term.attribute}`);
|
|
6393
6390
|
return pos !== void 0 && term.value !== pos;
|
|
6394
6391
|
}
|
|
@@ -6736,6 +6733,50 @@ function tryResolvePair(aChildren, bChildren) {
|
|
|
6736
6733
|
if (common.length === 1) return common[0];
|
|
6737
6734
|
return or(...common);
|
|
6738
6735
|
}
|
|
6736
|
+
/**
|
|
6737
|
+
* For each OR child of an AND, prune branches that are impossible
|
|
6738
|
+
* given the other AND siblings.
|
|
6739
|
+
*
|
|
6740
|
+
* Example: A & OR(!A & X, Y) → A & Y
|
|
6741
|
+
*
|
|
6742
|
+
* This catches dead OR branches left by exclusive negation (Stage 2b)
|
|
6743
|
+
* where `NOT(combined)` introduces branches contradicting flat siblings.
|
|
6744
|
+
*/
|
|
6745
|
+
function pruneContradictedOrBranches(terms) {
|
|
6746
|
+
if (!terms.some((t) => t.kind === "compound" && t.operator === "OR")) return terms;
|
|
6747
|
+
let changed = false;
|
|
6748
|
+
const result = [];
|
|
6749
|
+
for (let i = 0; i < terms.length; i++) {
|
|
6750
|
+
const term = terms[i];
|
|
6751
|
+
if (term.kind !== "compound" || term.operator !== "OR") {
|
|
6752
|
+
result.push(term);
|
|
6753
|
+
continue;
|
|
6754
|
+
}
|
|
6755
|
+
const siblings = [...terms.slice(0, i), ...terms.slice(i + 1)];
|
|
6756
|
+
const surviving = [];
|
|
6757
|
+
for (const branch of term.children) if (simplifyInner({
|
|
6758
|
+
kind: "compound",
|
|
6759
|
+
operator: "AND",
|
|
6760
|
+
children: [branch, ...siblings]
|
|
6761
|
+
}).kind !== "false") surviving.push(branch);
|
|
6762
|
+
if (surviving.length === term.children.length) result.push(term);
|
|
6763
|
+
else if (surviving.length === 0) return [falseCondition()];
|
|
6764
|
+
else {
|
|
6765
|
+
changed = true;
|
|
6766
|
+
if (surviving.length === 1) result.push(surviving[0]);
|
|
6767
|
+
else result.push({
|
|
6768
|
+
kind: "compound",
|
|
6769
|
+
operator: "OR",
|
|
6770
|
+
children: surviving
|
|
6771
|
+
});
|
|
6772
|
+
}
|
|
6773
|
+
}
|
|
6774
|
+
if (!changed) return terms;
|
|
6775
|
+
const flattened = [];
|
|
6776
|
+
for (const term of result) if (term.kind === "compound" && term.operator === "AND") flattened.push(...term.children);
|
|
6777
|
+
else flattened.push(term);
|
|
6778
|
+
return flattened;
|
|
6779
|
+
}
|
|
6739
6780
|
//#endregion
|
|
6740
6781
|
//#region src/pipeline/exclusive.ts
|
|
6741
6782
|
/**
|
|
@@ -7777,7 +7818,9 @@ function dedupeSelectorConditions(conditions) {
|
|
|
7777
7818
|
if (facts.negatedBooleanAttrs.size === 0 && facts.positiveExactValuesByAttr.size === 0) return result;
|
|
7778
7819
|
return result.filter((c) => {
|
|
7779
7820
|
if (!("attribute" in c)) return true;
|
|
7780
|
-
|
|
7821
|
+
if (isSubsumedNegatedModifier(c, facts)) return false;
|
|
7822
|
+
if (!c.negated && c.value === void 0 && facts.positiveExactValuesByAttr.has(c.attribute)) return false;
|
|
7823
|
+
return true;
|
|
7781
7824
|
});
|
|
7782
7825
|
}
|
|
7783
7826
|
/**
|
|
@@ -8218,6 +8261,19 @@ function factorAndGroup(variants) {
|
|
|
8218
8261
|
modifierConditions: commonModifiers,
|
|
8219
8262
|
pseudoConditions: commonPseudos
|
|
8220
8263
|
};
|
|
8264
|
+
const factoredGroups = tryFactorIntoDimensions(branches);
|
|
8265
|
+
if (factoredGroups) return {
|
|
8266
|
+
modifierConditions: commonModifiers,
|
|
8267
|
+
pseudoConditions: commonPseudos,
|
|
8268
|
+
selectorGroups: [...variants[0].selectorGroups, ...factoredGroups],
|
|
8269
|
+
ownGroups: [...variants[0].ownGroups],
|
|
8270
|
+
mediaConditions: [...variants[0].mediaConditions],
|
|
8271
|
+
containerConditions: [...variants[0].containerConditions],
|
|
8272
|
+
supportsConditions: [...variants[0].supportsConditions],
|
|
8273
|
+
rootGroups: [...variants[0].rootGroups],
|
|
8274
|
+
parentGroups: [...variants[0].parentGroups],
|
|
8275
|
+
startingStyle: variants[0].startingStyle
|
|
8276
|
+
};
|
|
8221
8277
|
return {
|
|
8222
8278
|
modifierConditions: commonModifiers,
|
|
8223
8279
|
pseudoConditions: commonPseudos,
|
|
@@ -8235,6 +8291,39 @@ function factorAndGroup(variants) {
|
|
|
8235
8291
|
};
|
|
8236
8292
|
}
|
|
8237
8293
|
/**
|
|
8294
|
+
* Detect when branches form a complete Cartesian product of independent
|
|
8295
|
+
* modifier attribute dimensions and return one SelectorGroup per dimension.
|
|
8296
|
+
*
|
|
8297
|
+
* Example: 4 branches for 2 attributes × 2 values each →
|
|
8298
|
+
* :is(A1, A2):is(B1, B2) instead of :is(A1B1, A1B2, A2B1, A2B2)
|
|
8299
|
+
*/
|
|
8300
|
+
function tryFactorIntoDimensions(branches) {
|
|
8301
|
+
if (branches.length < 4) return null;
|
|
8302
|
+
const dimensions = /* @__PURE__ */ new Map();
|
|
8303
|
+
for (const branch of branches) for (const cond of branch) {
|
|
8304
|
+
if (!("attribute" in cond)) return null;
|
|
8305
|
+
if (!dimensions.has(cond.attribute)) dimensions.set(cond.attribute, /* @__PURE__ */ new Map());
|
|
8306
|
+
dimensions.get(cond.attribute).set(getModifierKey(cond), cond);
|
|
8307
|
+
}
|
|
8308
|
+
if (dimensions.size < 2) return null;
|
|
8309
|
+
for (const branch of branches) {
|
|
8310
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8311
|
+
for (const cond of branch) {
|
|
8312
|
+
const attr = cond.attribute;
|
|
8313
|
+
if (seen.has(attr)) return null;
|
|
8314
|
+
seen.add(attr);
|
|
8315
|
+
}
|
|
8316
|
+
if (seen.size !== dimensions.size) return null;
|
|
8317
|
+
}
|
|
8318
|
+
let expectedCount = 1;
|
|
8319
|
+
for (const vals of dimensions.values()) expectedCount *= vals.size;
|
|
8320
|
+
if (branches.length !== expectedCount) return null;
|
|
8321
|
+
return [...dimensions.values()].map((vals) => ({
|
|
8322
|
+
branches: [...vals.values()].map((cond) => [cond]),
|
|
8323
|
+
negated: false
|
|
8324
|
+
}));
|
|
8325
|
+
}
|
|
8326
|
+
/**
|
|
8238
8327
|
* Build at-rules array from a variant
|
|
8239
8328
|
*/
|
|
8240
8329
|
function buildAtRulesFromVariant(variant) {
|
|
@@ -8244,7 +8333,7 @@ function buildAtRulesFromVariant(variant) {
|
|
|
8244
8333
|
if (c.subtype === "type") return c.negated ? `not ${c.condition}` : c.condition;
|
|
8245
8334
|
else return c.negated ? `(not ${c.condition})` : c.condition;
|
|
8246
8335
|
});
|
|
8247
|
-
atRules.push(`@media ${conditionParts.join(" and ")}`);
|
|
8336
|
+
atRules.push(`@media ${conditionParts.sort().join(" and ")}`);
|
|
8248
8337
|
}
|
|
8249
8338
|
if (variant.containerConditions.length > 0) {
|
|
8250
8339
|
const byName = /* @__PURE__ */ new Map();
|
|
@@ -9106,14 +9195,15 @@ function validatePattern(pattern) {
|
|
|
9106
9195
|
* processSinglePattern('>Body>Row>', 'Cell')
|
|
9107
9196
|
* // → '> [data-element="Body"] > [data-element="Row"] > [data-element="Cell"]'
|
|
9108
9197
|
*
|
|
9109
|
-
* processSinglePattern('
|
|
9110
|
-
* // → '::before' (
|
|
9198
|
+
* processSinglePattern('&::before', 'Before')
|
|
9199
|
+
* // → '::before' (& attaches pseudo directly to root, no key injection)
|
|
9111
9200
|
*
|
|
9112
9201
|
* processSinglePattern('>@:hover', 'Item')
|
|
9113
9202
|
* // → '> [data-element="Item"]:hover'
|
|
9114
9203
|
*/
|
|
9115
9204
|
function processSinglePattern(pattern, key) {
|
|
9116
|
-
const
|
|
9205
|
+
const startsWithAmpersand = pattern.startsWith("&");
|
|
9206
|
+
const normalized = (startsWithAmpersand ? pattern.slice(1) : pattern).trim();
|
|
9117
9207
|
if (!normalized) return ` [data-element="${key}"]`;
|
|
9118
9208
|
const startsWithPseudo = /^::?[a-z]/.test(normalized);
|
|
9119
9209
|
let result = transformPattern(normalized);
|
|
@@ -9123,8 +9213,8 @@ function processSinglePattern(pattern, key) {
|
|
|
9123
9213
|
if (!startsWithPseudo && !result.startsWith(" ")) result = " " + result;
|
|
9124
9214
|
return result;
|
|
9125
9215
|
}
|
|
9126
|
-
if (shouldInjectKey(normalized)) result = result + ` [data-element="${key}"]`;
|
|
9127
|
-
if (!
|
|
9216
|
+
if (shouldInjectKey(normalized, key)) result = result + ` [data-element="${key}"]`;
|
|
9217
|
+
if (!startsWithAmpersand && !result.startsWith(" ")) result = " " + result;
|
|
9128
9218
|
return result;
|
|
9129
9219
|
}
|
|
9130
9220
|
/**
|
|
@@ -9262,22 +9352,28 @@ function transformPattern(pattern) {
|
|
|
9262
9352
|
* | Attribute ([type]) | No | `'[type="text"]'` | `[type="text"]` |
|
|
9263
9353
|
*
|
|
9264
9354
|
* @param pattern - The normalized pattern (after stripping &)
|
|
9355
|
+
* @param key - The sub-element key being styled. If the trailing element name
|
|
9356
|
+
* equals this key, it acts as an explicit placeholder for the key
|
|
9357
|
+
* (same role as `@`) and no auto-injection happens.
|
|
9265
9358
|
* @returns true if key should be injected, false otherwise
|
|
9266
9359
|
*
|
|
9267
9360
|
* @example
|
|
9268
|
-
* shouldInjectKey('>')
|
|
9269
|
-
* shouldInjectKey('>Body>Row')
|
|
9270
|
-
* shouldInjectKey('
|
|
9271
|
-
* shouldInjectKey('
|
|
9272
|
-
* shouldInjectKey('
|
|
9273
|
-
* shouldInjectKey('
|
|
9274
|
-
* shouldInjectKey('
|
|
9275
|
-
* shouldInjectKey('
|
|
9276
|
-
|
|
9277
|
-
|
|
9361
|
+
* shouldInjectKey('>', 'Key') // → true (trailing combinator)
|
|
9362
|
+
* shouldInjectKey('>Body>Row', 'Key') // → true (ends with different element)
|
|
9363
|
+
* shouldInjectKey('>Body>Key', 'Key') // → false (trailing name === key)
|
|
9364
|
+
* shouldInjectKey('Key', 'Key') // → false (sole element === key)
|
|
9365
|
+
* shouldInjectKey('h1', 'Key') // → false (ends with tag)
|
|
9366
|
+
* shouldInjectKey('*', 'Key') // → false (universal selector)
|
|
9367
|
+
* shouldInjectKey('::before', 'Key') // → false (ends with pseudo)
|
|
9368
|
+
* shouldInjectKey('.active', 'Key') // → false (ends with class)
|
|
9369
|
+
* shouldInjectKey('a:hover', 'Key') // → false (ends with pseudo)
|
|
9370
|
+
* shouldInjectKey('button.primary', 'Key') // → false (ends with class)
|
|
9371
|
+
*/
|
|
9372
|
+
function shouldInjectKey(pattern, key) {
|
|
9278
9373
|
const trimmed = pattern.trim();
|
|
9279
9374
|
if (/[>+~]$/.test(trimmed)) return true;
|
|
9280
|
-
|
|
9375
|
+
const trailingElement = trimmed.match(/(?:^|[\s>+~\]:])([A-Z][a-zA-Z0-9]*)$/);
|
|
9376
|
+
if (trailingElement) return trailingElement[1] !== key;
|
|
9281
9377
|
return false;
|
|
9282
9378
|
}
|
|
9283
9379
|
/**
|
|
@@ -9683,7 +9779,10 @@ function isTestEnvironment() {
|
|
|
9683
9779
|
const g = global;
|
|
9684
9780
|
if (g.vi || g.jest || g.expect || g.describe || g.it) return true;
|
|
9685
9781
|
}
|
|
9686
|
-
if (typeof window !== "undefined"
|
|
9782
|
+
if (typeof window !== "undefined") {
|
|
9783
|
+
const ua = window.navigator?.userAgent;
|
|
9784
|
+
if (ua?.includes("jsdom") || ua?.includes("HappyDOM")) return true;
|
|
9785
|
+
}
|
|
9687
9786
|
if (typeof globalThis !== "undefined") {
|
|
9688
9787
|
const gt = globalThis;
|
|
9689
9788
|
if (gt.vitest || gt.mocha) return true;
|
|
@@ -10125,4 +10224,4 @@ function resetConfig() {
|
|
|
10125
10224
|
//#endregion
|
|
10126
10225
|
export { parseStyle as $, extractLocalCounterStyle as A, deprecationWarning as B, camelToKebab as C, Lru as Ct, getGlobalPredefinedStates as D, extractPredefinedStateRefs as E, formatFontFaceRule as F, DIRECTIONS as G, createStyle as H, hasLocalFontFace as I, getGlobalFuncs as J, customFunc as K, SheetManager as L, hasLocalCounterStyle as M, extractLocalFontFace as N, setGlobalPredefinedStates as O, fontFaceContentHash as P, parseColor as Q, STYLE_HANDLER_MAP as R, parseStateKey as S, strToRgb as St, extractLocalPredefinedStates as T, PropertyTypeResolver as U, warn as V, CUSTOM_UNITS as W, getGlobalPredefinedTokens as X, getGlobalParser as Y, normalizeColorTokenValue as Z, resetConfig as _, getComponentPropertySyntax as _t, getGlobalCounterStyle as a, StyleParser as at, isSelector as b, hexToRgb as bt, getGlobalKeyframes as c, hashString as ct, hasGlobalKeyframes as d, hasLocalProperties as dt, resetGlobalPredefinedTokens as et, hasGlobalRecipes as f, parsePropertyToken as ft, markStylesGenerated as g, getColorSpaceSuffix as gt, isTestEnvironment as h, getColorSpaceFunc as ht, getGlobalConfigTokens as i, okhslPlugin as it, formatCounterStyleRule as j, StyleInjector as k, getGlobalRecipes as l, extractLocalProperties as lt, isConfigLocked as m, getColorSpaceComponents as mt, getConfig as n, stringifyStyles as nt, getGlobalFontFace as o, Bucket as ot, hasStylesGenerated as p, colorInitialValueToComponents as pt, filterMods as q, getEffectiveProperties as r, okhslFunc as rt, getGlobalInjector as s, isDevEnv as st, configure as t, setGlobalPredefinedTokens as tt, getGlobalStyles as u, getEffectiveDefinition as ut, generateTypographyTokens as v, getNamedColorHex as vt, createStateParserContext as w, renderStyles as x, hslToRgbValues as xt, hasPipelineCacheEntry as y, getRgbValuesFromRgbaString as yt, styleHandlers as z };
|
|
10127
10226
|
|
|
10128
|
-
//# sourceMappingURL=config-
|
|
10227
|
+
//# sourceMappingURL=config-raGoEeGs.js.map
|