@tenphi/tasty 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +236 -0
- package/dist/_virtual/_rolldown/runtime.mjs +7 -0
- package/dist/chunks/cacheKey.d.ts +1 -0
- package/dist/chunks/cacheKey.js +70 -0
- package/dist/chunks/cacheKey.js.map +1 -0
- package/dist/chunks/cacheKey.mjs +70 -0
- package/dist/chunks/cacheKey.mjs.map +1 -0
- package/dist/chunks/definitions.d.ts +37 -0
- package/dist/chunks/definitions.js +260 -0
- package/dist/chunks/definitions.js.map +1 -0
- package/dist/chunks/definitions.mjs +260 -0
- package/dist/chunks/definitions.mjs.map +1 -0
- package/dist/chunks/index.d.ts +3 -0
- package/dist/chunks/renderChunk.d.ts +2 -0
- package/dist/chunks/renderChunk.js +61 -0
- package/dist/chunks/renderChunk.js.map +1 -0
- package/dist/chunks/renderChunk.mjs +61 -0
- package/dist/chunks/renderChunk.mjs.map +1 -0
- package/dist/config.d.ts +279 -0
- package/dist/config.js +400 -0
- package/dist/config.js.map +1 -0
- package/dist/config.mjs +231 -0
- package/dist/config.mjs.map +1 -0
- package/dist/css-writer.d.mts +45 -0
- package/dist/css-writer.mjs +74 -0
- package/dist/css-writer.mjs.map +1 -0
- package/dist/debug.d.ts +204 -0
- package/dist/debug.js +733 -0
- package/dist/debug.js.map +1 -0
- package/dist/extractor.d.mts +24 -0
- package/dist/extractor.mjs +150 -0
- package/dist/extractor.mjs.map +1 -0
- package/dist/hooks/index.d.ts +5 -0
- package/dist/hooks/useGlobalStyles.d.ts +27 -0
- package/dist/hooks/useGlobalStyles.js +56 -0
- package/dist/hooks/useGlobalStyles.js.map +1 -0
- package/dist/hooks/useKeyframes.d.ts +56 -0
- package/dist/hooks/useKeyframes.js +54 -0
- package/dist/hooks/useKeyframes.js.map +1 -0
- package/dist/hooks/useProperty.d.ts +79 -0
- package/dist/hooks/useProperty.js +91 -0
- package/dist/hooks/useProperty.js.map +1 -0
- package/dist/hooks/useRawCSS.d.ts +53 -0
- package/dist/hooks/useRawCSS.js +28 -0
- package/dist/hooks/useRawCSS.js.map +1 -0
- package/dist/hooks/useStyles.d.ts +40 -0
- package/dist/hooks/useStyles.js +169 -0
- package/dist/hooks/useStyles.js.map +1 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.js +30 -0
- package/dist/injector/index.d.ts +157 -0
- package/dist/injector/index.js +154 -0
- package/dist/injector/index.js.map +1 -0
- package/dist/injector/injector.d.ts +139 -0
- package/dist/injector/injector.js +404 -0
- package/dist/injector/injector.js.map +1 -0
- package/dist/injector/injector.mjs +404 -0
- package/dist/injector/injector.mjs.map +1 -0
- package/dist/injector/sheet-manager.d.ts +127 -0
- package/dist/injector/sheet-manager.js +714 -0
- package/dist/injector/sheet-manager.js.map +1 -0
- package/dist/injector/sheet-manager.mjs +714 -0
- package/dist/injector/sheet-manager.mjs.map +1 -0
- package/dist/injector/types.d.mts +18 -0
- package/dist/injector/types.d.ts +135 -0
- package/dist/keyframes/index.js +206 -0
- package/dist/keyframes/index.js.map +1 -0
- package/dist/keyframes/index.mjs +156 -0
- package/dist/keyframes/index.mjs.map +1 -0
- package/dist/parser/classify.js +319 -0
- package/dist/parser/classify.js.map +1 -0
- package/dist/parser/classify.mjs +319 -0
- package/dist/parser/classify.mjs.map +1 -0
- package/dist/parser/const.js +33 -0
- package/dist/parser/const.js.map +1 -0
- package/dist/parser/const.mjs +33 -0
- package/dist/parser/const.mjs.map +1 -0
- package/dist/parser/lru.js +109 -0
- package/dist/parser/lru.js.map +1 -0
- package/dist/parser/lru.mjs +109 -0
- package/dist/parser/lru.mjs.map +1 -0
- package/dist/parser/parser.d.ts +25 -0
- package/dist/parser/parser.js +116 -0
- package/dist/parser/parser.js.map +1 -0
- package/dist/parser/parser.mjs +116 -0
- package/dist/parser/parser.mjs.map +1 -0
- package/dist/parser/tokenizer.js +69 -0
- package/dist/parser/tokenizer.js.map +1 -0
- package/dist/parser/tokenizer.mjs +69 -0
- package/dist/parser/tokenizer.mjs.map +1 -0
- package/dist/parser/types.d.mts +37 -0
- package/dist/parser/types.d.ts +46 -0
- package/dist/parser/types.js +46 -0
- package/dist/parser/types.js.map +1 -0
- package/dist/parser/types.mjs +46 -0
- package/dist/parser/types.mjs.map +1 -0
- package/dist/pipeline/conditions.js +377 -0
- package/dist/pipeline/conditions.js.map +1 -0
- package/dist/pipeline/conditions.mjs +377 -0
- package/dist/pipeline/conditions.mjs.map +1 -0
- package/dist/pipeline/exclusive.d.ts +1 -0
- package/dist/pipeline/exclusive.js +231 -0
- package/dist/pipeline/exclusive.js.map +1 -0
- package/dist/pipeline/exclusive.mjs +231 -0
- package/dist/pipeline/exclusive.mjs.map +1 -0
- package/dist/pipeline/index.d.ts +53 -0
- package/dist/pipeline/index.js +641 -0
- package/dist/pipeline/index.js.map +1 -0
- package/dist/pipeline/index.mjs +635 -0
- package/dist/pipeline/index.mjs.map +1 -0
- package/dist/pipeline/materialize.js +821 -0
- package/dist/pipeline/materialize.js.map +1 -0
- package/dist/pipeline/materialize.mjs +821 -0
- package/dist/pipeline/materialize.mjs.map +1 -0
- package/dist/pipeline/parseStateKey.d.ts +1 -0
- package/dist/pipeline/parseStateKey.js +418 -0
- package/dist/pipeline/parseStateKey.js.map +1 -0
- package/dist/pipeline/parseStateKey.mjs +418 -0
- package/dist/pipeline/parseStateKey.mjs.map +1 -0
- package/dist/pipeline/simplify.js +557 -0
- package/dist/pipeline/simplify.js.map +1 -0
- package/dist/pipeline/simplify.mjs +557 -0
- package/dist/pipeline/simplify.mjs.map +1 -0
- package/dist/plugins/index.d.ts +2 -0
- package/dist/plugins/okhsl-plugin.d.ts +35 -0
- package/dist/plugins/okhsl-plugin.js +371 -0
- package/dist/plugins/okhsl-plugin.js.map +1 -0
- package/dist/plugins/okhsl-plugin.mjs +345 -0
- package/dist/plugins/okhsl-plugin.mjs.map +1 -0
- package/dist/plugins/types.d.mts +49 -0
- package/dist/plugins/types.d.ts +69 -0
- package/dist/properties/index.js +158 -0
- package/dist/properties/index.js.map +1 -0
- package/dist/properties/index.mjs +141 -0
- package/dist/properties/index.mjs.map +1 -0
- package/dist/states/index.d.ts +45 -0
- package/dist/states/index.js +389 -0
- package/dist/states/index.js.map +1 -0
- package/dist/states/index.mjs +161 -0
- package/dist/states/index.mjs.map +1 -0
- package/dist/static/index.d.ts +5 -0
- package/dist/static/index.js +5 -0
- package/dist/static/tastyStatic.d.ts +46 -0
- package/dist/static/tastyStatic.js +31 -0
- package/dist/static/tastyStatic.js.map +1 -0
- package/dist/static/types.d.ts +49 -0
- package/dist/static/types.js +24 -0
- package/dist/static/types.js.map +1 -0
- package/dist/styles/align.d.ts +15 -0
- package/dist/styles/align.js +14 -0
- package/dist/styles/align.js.map +1 -0
- package/dist/styles/align.mjs +14 -0
- package/dist/styles/align.mjs.map +1 -0
- package/dist/styles/border.d.ts +25 -0
- package/dist/styles/border.js +114 -0
- package/dist/styles/border.js.map +1 -0
- package/dist/styles/border.mjs +114 -0
- package/dist/styles/border.mjs.map +1 -0
- package/dist/styles/color.d.ts +14 -0
- package/dist/styles/color.js +23 -0
- package/dist/styles/color.js.map +1 -0
- package/dist/styles/color.mjs +23 -0
- package/dist/styles/color.mjs.map +1 -0
- package/dist/styles/createStyle.js +77 -0
- package/dist/styles/createStyle.js.map +1 -0
- package/dist/styles/createStyle.mjs +77 -0
- package/dist/styles/createStyle.mjs.map +1 -0
- package/dist/styles/dimension.js +97 -0
- package/dist/styles/dimension.js.map +1 -0
- package/dist/styles/dimension.mjs +97 -0
- package/dist/styles/dimension.mjs.map +1 -0
- package/dist/styles/display.d.ts +37 -0
- package/dist/styles/display.js +67 -0
- package/dist/styles/display.js.map +1 -0
- package/dist/styles/display.mjs +67 -0
- package/dist/styles/display.mjs.map +1 -0
- package/dist/styles/fade.d.ts +15 -0
- package/dist/styles/fade.js +58 -0
- package/dist/styles/fade.js.map +1 -0
- package/dist/styles/fade.mjs +58 -0
- package/dist/styles/fade.mjs.map +1 -0
- package/dist/styles/fill.d.ts +44 -0
- package/dist/styles/fill.js +51 -0
- package/dist/styles/fill.js.map +1 -0
- package/dist/styles/fill.mjs +51 -0
- package/dist/styles/fill.mjs.map +1 -0
- package/dist/styles/flow.d.ts +16 -0
- package/dist/styles/flow.js +12 -0
- package/dist/styles/flow.js.map +1 -0
- package/dist/styles/flow.mjs +12 -0
- package/dist/styles/flow.mjs.map +1 -0
- package/dist/styles/gap.d.ts +31 -0
- package/dist/styles/gap.js +37 -0
- package/dist/styles/gap.js.map +1 -0
- package/dist/styles/gap.mjs +37 -0
- package/dist/styles/gap.mjs.map +1 -0
- package/dist/styles/height.d.ts +17 -0
- package/dist/styles/height.js +20 -0
- package/dist/styles/height.js.map +1 -0
- package/dist/styles/height.mjs +20 -0
- package/dist/styles/height.mjs.map +1 -0
- package/dist/styles/index.d.ts +2 -0
- package/dist/styles/index.js +9 -0
- package/dist/styles/index.js.map +1 -0
- package/dist/styles/index.mjs +9 -0
- package/dist/styles/index.mjs.map +1 -0
- package/dist/styles/inset.d.ts +50 -0
- package/dist/styles/inset.js +142 -0
- package/dist/styles/inset.js.map +1 -0
- package/dist/styles/inset.mjs +142 -0
- package/dist/styles/inset.mjs.map +1 -0
- package/dist/styles/justify.d.ts +15 -0
- package/dist/styles/justify.js +14 -0
- package/dist/styles/justify.js.map +1 -0
- package/dist/styles/justify.mjs +14 -0
- package/dist/styles/justify.mjs.map +1 -0
- package/dist/styles/list.d.ts +16 -0
- package/dist/styles/list.js +98 -0
- package/dist/styles/list.js.map +1 -0
- package/dist/styles/margin.d.ts +28 -0
- package/dist/styles/margin.js +96 -0
- package/dist/styles/margin.js.map +1 -0
- package/dist/styles/margin.mjs +96 -0
- package/dist/styles/margin.mjs.map +1 -0
- package/dist/styles/outline.d.ts +29 -0
- package/dist/styles/outline.js +65 -0
- package/dist/styles/outline.js.map +1 -0
- package/dist/styles/outline.mjs +65 -0
- package/dist/styles/outline.mjs.map +1 -0
- package/dist/styles/padding.d.ts +28 -0
- package/dist/styles/padding.js +96 -0
- package/dist/styles/padding.js.map +1 -0
- package/dist/styles/padding.mjs +96 -0
- package/dist/styles/padding.mjs.map +1 -0
- package/dist/styles/predefined.d.ts +74 -0
- package/dist/styles/predefined.js +241 -0
- package/dist/styles/predefined.js.map +1 -0
- package/dist/styles/predefined.mjs +232 -0
- package/dist/styles/predefined.mjs.map +1 -0
- package/dist/styles/preset.d.ts +47 -0
- package/dist/styles/preset.js +126 -0
- package/dist/styles/preset.js.map +1 -0
- package/dist/styles/preset.mjs +126 -0
- package/dist/styles/preset.mjs.map +1 -0
- package/dist/styles/radius.d.ts +14 -0
- package/dist/styles/radius.js +51 -0
- package/dist/styles/radius.js.map +1 -0
- package/dist/styles/radius.mjs +51 -0
- package/dist/styles/radius.mjs.map +1 -0
- package/dist/styles/scrollbar.d.ts +21 -0
- package/dist/styles/scrollbar.js +105 -0
- package/dist/styles/scrollbar.js.map +1 -0
- package/dist/styles/scrollbar.mjs +105 -0
- package/dist/styles/scrollbar.mjs.map +1 -0
- package/dist/styles/shadow.d.ts +14 -0
- package/dist/styles/shadow.js +24 -0
- package/dist/styles/shadow.js.map +1 -0
- package/dist/styles/shadow.mjs +24 -0
- package/dist/styles/shadow.mjs.map +1 -0
- package/dist/styles/styledScrollbar.d.ts +47 -0
- package/dist/styles/styledScrollbar.js +38 -0
- package/dist/styles/styledScrollbar.js.map +1 -0
- package/dist/styles/styledScrollbar.mjs +38 -0
- package/dist/styles/styledScrollbar.mjs.map +1 -0
- package/dist/styles/transition.d.ts +14 -0
- package/dist/styles/transition.js +138 -0
- package/dist/styles/transition.js.map +1 -0
- package/dist/styles/transition.mjs +138 -0
- package/dist/styles/transition.mjs.map +1 -0
- package/dist/styles/types.d.mts +492 -0
- package/dist/styles/types.d.ts +496 -0
- package/dist/styles/width.d.ts +17 -0
- package/dist/styles/width.js +20 -0
- package/dist/styles/width.js.map +1 -0
- package/dist/styles/width.mjs +20 -0
- package/dist/styles/width.mjs.map +1 -0
- package/dist/tasty.d.ts +983 -0
- package/dist/tasty.js +191 -0
- package/dist/tasty.js.map +1 -0
- package/dist/tokens/typography.d.ts +19 -0
- package/dist/tokens/typography.js +237 -0
- package/dist/tokens/typography.js.map +1 -0
- package/dist/types.d.ts +182 -0
- package/dist/utils/cache-wrapper.js +26 -0
- package/dist/utils/cache-wrapper.js.map +1 -0
- package/dist/utils/cache-wrapper.mjs +26 -0
- package/dist/utils/cache-wrapper.mjs.map +1 -0
- package/dist/utils/case-converter.js +8 -0
- package/dist/utils/case-converter.js.map +1 -0
- package/dist/utils/case-converter.mjs +8 -0
- package/dist/utils/case-converter.mjs.map +1 -0
- package/dist/utils/colors.d.ts +5 -0
- package/dist/utils/colors.js +9 -0
- package/dist/utils/colors.js.map +1 -0
- package/dist/utils/dotize.d.ts +26 -0
- package/dist/utils/dotize.js +122 -0
- package/dist/utils/dotize.js.map +1 -0
- package/dist/utils/filter-base-props.d.ts +15 -0
- package/dist/utils/filter-base-props.js +45 -0
- package/dist/utils/filter-base-props.js.map +1 -0
- package/dist/utils/get-display-name.d.ts +7 -0
- package/dist/utils/get-display-name.js +10 -0
- package/dist/utils/get-display-name.js.map +1 -0
- package/dist/utils/hsl-to-rgb.js +38 -0
- package/dist/utils/hsl-to-rgb.js.map +1 -0
- package/dist/utils/hsl-to-rgb.mjs +38 -0
- package/dist/utils/hsl-to-rgb.mjs.map +1 -0
- package/dist/utils/is-dev-env.js +19 -0
- package/dist/utils/is-dev-env.js.map +1 -0
- package/dist/utils/is-dev-env.mjs +19 -0
- package/dist/utils/is-dev-env.mjs.map +1 -0
- package/dist/utils/merge-styles.d.ts +7 -0
- package/dist/utils/merge-styles.js +146 -0
- package/dist/utils/merge-styles.js.map +1 -0
- package/dist/utils/merge-styles.mjs +146 -0
- package/dist/utils/merge-styles.mjs.map +1 -0
- package/dist/utils/mod-attrs.d.ts +8 -0
- package/dist/utils/mod-attrs.js +21 -0
- package/dist/utils/mod-attrs.js.map +1 -0
- package/dist/utils/okhsl-to-rgb.js +296 -0
- package/dist/utils/okhsl-to-rgb.js.map +1 -0
- package/dist/utils/okhsl-to-rgb.mjs +296 -0
- package/dist/utils/okhsl-to-rgb.mjs.map +1 -0
- package/dist/utils/process-tokens.d.ts +31 -0
- package/dist/utils/process-tokens.js +171 -0
- package/dist/utils/process-tokens.js.map +1 -0
- package/dist/utils/process-tokens.mjs +28 -0
- package/dist/utils/process-tokens.mjs.map +1 -0
- package/dist/utils/resolve-recipes.d.ts +17 -0
- package/dist/utils/resolve-recipes.js +143 -0
- package/dist/utils/resolve-recipes.js.map +1 -0
- package/dist/utils/resolve-recipes.mjs +143 -0
- package/dist/utils/resolve-recipes.mjs.map +1 -0
- package/dist/utils/string.js +8 -0
- package/dist/utils/string.js.map +1 -0
- package/dist/utils/string.mjs +8 -0
- package/dist/utils/string.mjs.map +1 -0
- package/dist/utils/styles.d.mts +18 -0
- package/dist/utils/styles.d.ts +183 -0
- package/dist/utils/styles.js +585 -0
- package/dist/utils/styles.js.map +1 -0
- package/dist/utils/styles.mjs +346 -0
- package/dist/utils/styles.mjs.map +1 -0
- package/dist/utils/typography.d.ts +36 -0
- package/dist/utils/typography.js +53 -0
- package/dist/utils/typography.js.map +1 -0
- package/dist/utils/warnings.d.ts +16 -0
- package/dist/utils/warnings.js +16 -0
- package/dist/utils/warnings.js.map +1 -0
- package/dist/zero/babel.d.mts +108 -0
- package/dist/zero/babel.mjs +282 -0
- package/dist/zero/babel.mjs.map +1 -0
- package/dist/zero/index.d.mts +3 -0
- package/dist/zero/index.mjs +4 -0
- package/dist/zero/next.d.mts +60 -0
- package/dist/zero/next.mjs +78 -0
- package/dist/zero/next.mjs.map +1 -0
- package/package.json +127 -0
|
@@ -0,0 +1,635 @@
|
|
|
1
|
+
import { Lru } from "../parser/lru.mjs";
|
|
2
|
+
import { stringifyStyles } from "../utils/styles.mjs";
|
|
3
|
+
import { createStyle } from "../styles/createStyle.mjs";
|
|
4
|
+
import { STYLE_HANDLER_MAP } from "../styles/index.mjs";
|
|
5
|
+
import { createStateParserContext, extractLocalPredefinedStates } from "../states/index.mjs";
|
|
6
|
+
import { and, falseCondition, not, or, trueCondition } from "./conditions.mjs";
|
|
7
|
+
import { simplifyCondition } from "./simplify.mjs";
|
|
8
|
+
import { buildExclusiveConditions, expandExclusiveOrs, expandOrConditions, isValueMapping, parseStyleEntries } from "./exclusive.mjs";
|
|
9
|
+
import { buildAtRulesFromVariant, conditionToCSS, modifierToCSS, pseudoToCSS, rootConditionsToCSS } from "./materialize.mjs";
|
|
10
|
+
import { parseStateKey } from "./parseStateKey.mjs";
|
|
11
|
+
|
|
12
|
+
//#region src/pipeline/index.ts
|
|
13
|
+
/**
|
|
14
|
+
* Tasty Style Rendering Pipeline
|
|
15
|
+
*
|
|
16
|
+
* This is the main entrypoint for the new pipeline implementation.
|
|
17
|
+
* It implements the complete flow from style objects to CSS rules.
|
|
18
|
+
*
|
|
19
|
+
* Pipeline stages:
|
|
20
|
+
* 1. PARSE CONDITIONS - Parse state keys into ConditionNode trees
|
|
21
|
+
* 2. BUILD EXCLUSIVE CONDITIONS - AND with negation of higher-priority conditions
|
|
22
|
+
* 3. SIMPLIFY CONDITIONS - Apply boolean algebra, detect contradictions
|
|
23
|
+
* 4. GROUP BY HANDLER - Collect styles per handler, compute combinations
|
|
24
|
+
* 5. COMPUTE CSS VALUES - Call handlers to get CSS declarations
|
|
25
|
+
* 6. MERGE BY VALUE - Merge rules with identical CSS output
|
|
26
|
+
* 7. MATERIALIZE CSS - Convert conditions to CSS selectors + at-rules
|
|
27
|
+
*/
|
|
28
|
+
const pipelineCache = new Lru(5e3);
|
|
29
|
+
function runPipeline(styles, parserContext) {
|
|
30
|
+
const allRules = [];
|
|
31
|
+
processStyles(styles, "", parserContext, allRules);
|
|
32
|
+
const seen = /* @__PURE__ */ new Set();
|
|
33
|
+
return allRules.filter((rule) => {
|
|
34
|
+
const key = `${rule.selector}|${rule.declarations}|${JSON.stringify(rule.atRules || [])}|${rule.rootPrefix || ""}`;
|
|
35
|
+
if (seen.has(key)) return false;
|
|
36
|
+
seen.add(key);
|
|
37
|
+
return true;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Process styles at a given nesting level
|
|
42
|
+
*/
|
|
43
|
+
function processStyles(styles, selectorSuffix, parserContext, allRules) {
|
|
44
|
+
const keys = Object.keys(styles);
|
|
45
|
+
const selectorKeys = keys.filter((key) => isSelector(key));
|
|
46
|
+
const styleKeys = keys.filter((key) => !isSelector(key) && !key.startsWith("@"));
|
|
47
|
+
for (const key of selectorKeys) {
|
|
48
|
+
const nestedStyles = styles[key];
|
|
49
|
+
if (!nestedStyles || typeof nestedStyles !== "object") continue;
|
|
50
|
+
const suffixes = getAllSelectors(key, nestedStyles);
|
|
51
|
+
if (!suffixes) continue;
|
|
52
|
+
const { $: _$, ...cleanedStyles } = nestedStyles;
|
|
53
|
+
const subLocalStates = extractLocalPredefinedStates(cleanedStyles);
|
|
54
|
+
const hasSubStates = Object.keys(subLocalStates).length > 0;
|
|
55
|
+
const subContext = {
|
|
56
|
+
...parserContext,
|
|
57
|
+
isSubElement: true,
|
|
58
|
+
localPredefinedStates: hasSubStates ? {
|
|
59
|
+
...parserContext.localPredefinedStates,
|
|
60
|
+
...subLocalStates
|
|
61
|
+
} : parserContext.localPredefinedStates
|
|
62
|
+
};
|
|
63
|
+
for (const suffix of suffixes) processStyles(cleanedStyles, selectorSuffix + suffix, subContext, allRules);
|
|
64
|
+
}
|
|
65
|
+
const handlerQueue = buildHandlerQueue(styleKeys, styles);
|
|
66
|
+
for (const { handler, styleMap } of handlerQueue) {
|
|
67
|
+
const lookupStyles = handler.__lookupStyles;
|
|
68
|
+
const exclusiveByStyle = /* @__PURE__ */ new Map();
|
|
69
|
+
for (const styleName of lookupStyles) {
|
|
70
|
+
const value = styleMap[styleName];
|
|
71
|
+
if (value === void 0) continue;
|
|
72
|
+
if (isValueMapping(value)) {
|
|
73
|
+
const fullyExpanded = expandExclusiveOrs(buildExclusiveConditions(expandOrConditions(parseStyleEntries(styleName, value, (stateKey) => parseStateKey(stateKey, { context: parserContext })))));
|
|
74
|
+
exclusiveByStyle.set(styleName, fullyExpanded);
|
|
75
|
+
} else exclusiveByStyle.set(styleName, [{
|
|
76
|
+
styleKey: styleName,
|
|
77
|
+
stateKey: "",
|
|
78
|
+
value,
|
|
79
|
+
condition: trueCondition(),
|
|
80
|
+
priority: 0,
|
|
81
|
+
exclusiveCondition: trueCondition()
|
|
82
|
+
}]);
|
|
83
|
+
}
|
|
84
|
+
const stateSnapshots = computeStateCombinations(exclusiveByStyle, lookupStyles);
|
|
85
|
+
const computedRules = [];
|
|
86
|
+
for (const snapshot of stateSnapshots) {
|
|
87
|
+
const result = handler(snapshot.values);
|
|
88
|
+
if (!result) continue;
|
|
89
|
+
const results = Array.isArray(result) ? result : [result];
|
|
90
|
+
for (const r of results) {
|
|
91
|
+
if (!r || typeof r !== "object") continue;
|
|
92
|
+
const { $, ...styleProps } = r;
|
|
93
|
+
const declarations = {};
|
|
94
|
+
for (const [prop, val] of Object.entries(styleProps)) if (val != null && val !== "") declarations[prop] = String(val);
|
|
95
|
+
if (Object.keys(declarations).length === 0) continue;
|
|
96
|
+
const suffixes = $ ? (Array.isArray($) ? $ : [$]).map((s) => selectorSuffix + normalizeSelectorSuffix(String(s))) : [selectorSuffix];
|
|
97
|
+
for (const suffix of suffixes) computedRules.push({
|
|
98
|
+
condition: snapshot.condition,
|
|
99
|
+
declarations,
|
|
100
|
+
selectorSuffix: suffix
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const mergedRules = mergeByValue(computedRules);
|
|
105
|
+
for (const rule of mergedRules) {
|
|
106
|
+
const cssRules = materializeComputedRule(rule);
|
|
107
|
+
allRules.push(...cssRules);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Check if a key is a CSS selector
|
|
113
|
+
*/
|
|
114
|
+
function isSelector(key) {
|
|
115
|
+
return key.startsWith("&") || key.startsWith(".") || /^[A-Z]/.test(key);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Get all selector suffixes for a sub-element key.
|
|
119
|
+
*
|
|
120
|
+
* Handles three types of selector keys:
|
|
121
|
+
* - `&` prefix: Raw selector suffix (e.g., `&:hover` → `:hover`)
|
|
122
|
+
* - `.` prefix: Class selector (e.g., `.active` → ` .active`)
|
|
123
|
+
* - Uppercase: Sub-element with optional `$` affix pattern
|
|
124
|
+
*
|
|
125
|
+
* @param key - The sub-element key (e.g., 'Label', '&:hover', '.active')
|
|
126
|
+
* @param styles - The styles object, may contain `$` property for selector affix
|
|
127
|
+
* @returns Array of selector suffixes, or null if invalid (with console warning)
|
|
128
|
+
*
|
|
129
|
+
* @example
|
|
130
|
+
* getAllSelectors('Label', {})
|
|
131
|
+
* // → [' [data-element="Label"]']
|
|
132
|
+
*
|
|
133
|
+
* getAllSelectors('Cell', { $: '>, >Body>' })
|
|
134
|
+
* // → ['> [data-element="Cell"]', ' [data-element="Body"] > [data-element="Cell"]']
|
|
135
|
+
*/
|
|
136
|
+
function getAllSelectors(key, styles) {
|
|
137
|
+
if (key.startsWith("&")) return [key.slice(1)];
|
|
138
|
+
if (key.startsWith(".")) return [` ${key}`];
|
|
139
|
+
if (/^[A-Z]/.test(key)) {
|
|
140
|
+
const affix = styles?.$;
|
|
141
|
+
if (affix !== void 0) {
|
|
142
|
+
const result = processAffix(String(affix), key);
|
|
143
|
+
if (!result.valid) {
|
|
144
|
+
console.warn(`[Tasty] ${result.reason}`);
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
return result.selectors;
|
|
148
|
+
}
|
|
149
|
+
return [` [data-element="${key}"]`];
|
|
150
|
+
}
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Process selector affix pattern and return selector(s)
|
|
155
|
+
*
|
|
156
|
+
* Supports:
|
|
157
|
+
* - Direct child: '>'
|
|
158
|
+
* - Chained elements: '>Body>Row>'
|
|
159
|
+
* - HTML tags: 'a', '>ul>li', 'button:hover'
|
|
160
|
+
* - Pseudo-elements on root: '::before'
|
|
161
|
+
* - Pseudo on sub-element: '@::before', '>@:hover'
|
|
162
|
+
* - Classes: '.active', '>@.active'
|
|
163
|
+
* - Multiple selectors: '>, >Body>'
|
|
164
|
+
* - Sibling combinators (after element): '>Item+', '>Item~'
|
|
165
|
+
*/
|
|
166
|
+
function processAffix(affix, key) {
|
|
167
|
+
const trimmed = affix.trim();
|
|
168
|
+
if (!trimmed) return {
|
|
169
|
+
valid: true,
|
|
170
|
+
selectors: [` [data-element="${key}"]`]
|
|
171
|
+
};
|
|
172
|
+
const patterns = trimmed.split(",").map((p) => p.trim());
|
|
173
|
+
const selectors = [];
|
|
174
|
+
for (const pattern of patterns) {
|
|
175
|
+
const validation = validatePattern(pattern);
|
|
176
|
+
if (!validation.valid) return validation;
|
|
177
|
+
const selector = processSinglePattern(pattern, key);
|
|
178
|
+
selectors.push(selector);
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
valid: true,
|
|
182
|
+
selectors
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Recognized token patterns for selector affix validation.
|
|
187
|
+
*
|
|
188
|
+
* These patterns are used to tokenize and validate `$` affix strings.
|
|
189
|
+
* Order matters: more specific patterns must come first to avoid
|
|
190
|
+
* partial matches (e.g., `::before` must match before `:` alone).
|
|
191
|
+
*
|
|
192
|
+
* Unrecognized tokens (like `#id`, `*`, or numbers) will cause validation to fail.
|
|
193
|
+
*/
|
|
194
|
+
const VALID_TOKEN_PATTERNS = [
|
|
195
|
+
/^[>+~]/,
|
|
196
|
+
/^[A-Z][a-zA-Z0-9]*/,
|
|
197
|
+
/^@/,
|
|
198
|
+
/^::?[a-z][a-z0-9-]*(?:\([^)]*\))?/,
|
|
199
|
+
/^\.[a-zA-Z_-][a-zA-Z0-9_-]*/,
|
|
200
|
+
/^\[[^\]]+\]/,
|
|
201
|
+
/^[a-z][a-z0-9-]*/,
|
|
202
|
+
/^\s+/,
|
|
203
|
+
/^&/
|
|
204
|
+
];
|
|
205
|
+
/**
|
|
206
|
+
* Scan a pattern for unrecognized tokens.
|
|
207
|
+
*
|
|
208
|
+
* Iterates through the pattern, consuming recognized tokens until
|
|
209
|
+
* either the pattern is fully consumed (valid) or an unrecognized
|
|
210
|
+
* character sequence is found (invalid).
|
|
211
|
+
*
|
|
212
|
+
* @param pattern - The selector pattern to validate
|
|
213
|
+
* @returns The first unrecognized token found, or null if all tokens are valid
|
|
214
|
+
*
|
|
215
|
+
* @example
|
|
216
|
+
* findUnrecognizedTokens('>Body>Row>') // → null (valid)
|
|
217
|
+
* findUnrecognizedTokens('123') // → '123' (invalid)
|
|
218
|
+
* findUnrecognizedTokens('#myId') // → '#' (invalid)
|
|
219
|
+
*/
|
|
220
|
+
function findUnrecognizedTokens(pattern) {
|
|
221
|
+
let remaining = pattern;
|
|
222
|
+
while (remaining.length > 0) {
|
|
223
|
+
let matched = false;
|
|
224
|
+
for (const regex of VALID_TOKEN_PATTERNS) {
|
|
225
|
+
const match = remaining.match(regex);
|
|
226
|
+
if (match) {
|
|
227
|
+
remaining = remaining.slice(match[0].length);
|
|
228
|
+
matched = true;
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (!matched) {
|
|
233
|
+
const unrecognized = remaining.match(/^[^\s>+~@.:[\]A-Z]+/);
|
|
234
|
+
return unrecognized ? unrecognized[0] : remaining[0];
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Validate a selector pattern for structural correctness.
|
|
241
|
+
*
|
|
242
|
+
* Checks for:
|
|
243
|
+
* 1. Out-of-scope selectors: Patterns starting with `+` or `~` target siblings
|
|
244
|
+
* of the root element, which is outside the component's DOM scope.
|
|
245
|
+
* 2. Consecutive combinators: Patterns like `>>` or `>+` are malformed CSS.
|
|
246
|
+
* 3. Unrecognized tokens: Characters/sequences not matching valid CSS selectors.
|
|
247
|
+
*
|
|
248
|
+
* @param pattern - A single selector pattern (already split by comma)
|
|
249
|
+
* @returns AffixResult indicating validity and error reason if invalid
|
|
250
|
+
*
|
|
251
|
+
* @example
|
|
252
|
+
* validatePattern('>Body>Row>') // → { valid: true, selectors: [] }
|
|
253
|
+
* validatePattern('+') // → { valid: false, reason: '...outside root scope...' }
|
|
254
|
+
* validatePattern('>>') // → { valid: false, reason: '...consecutive combinators...' }
|
|
255
|
+
*/
|
|
256
|
+
function validatePattern(pattern) {
|
|
257
|
+
const trimmed = pattern.trim();
|
|
258
|
+
if (/^[+~]/.test(trimmed)) return {
|
|
259
|
+
valid: false,
|
|
260
|
+
reason: `Selector affix "${pattern}" targets elements outside the root scope. Sibling selectors (+, ~) must be preceded by an element inside the root. Use ">Element+" or ">Element~" instead.`
|
|
261
|
+
};
|
|
262
|
+
if (/[>+~]{2,}/.test(trimmed.replace(/\s+/g, ""))) return {
|
|
263
|
+
valid: false,
|
|
264
|
+
reason: `Selector affix "${pattern}" contains consecutive combinators.`
|
|
265
|
+
};
|
|
266
|
+
const unrecognized = findUnrecognizedTokens(trimmed);
|
|
267
|
+
if (unrecognized) return {
|
|
268
|
+
valid: false,
|
|
269
|
+
reason: `Selector affix "${pattern}" contains unrecognized token "${unrecognized}". Valid tokens: combinators (>, +, ~), element names (Uppercase), @ placeholder, pseudo (:hover, ::before), class (.name), attribute ([attr]).`
|
|
270
|
+
};
|
|
271
|
+
return {
|
|
272
|
+
valid: true,
|
|
273
|
+
selectors: []
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Process a single selector pattern into a CSS selector suffix.
|
|
278
|
+
*
|
|
279
|
+
* This is the main transformation function that converts a `$` affix pattern
|
|
280
|
+
* into a valid CSS selector suffix. It handles:
|
|
281
|
+
*
|
|
282
|
+
* 1. `@` placeholder replacement with `[data-element="key"]`
|
|
283
|
+
* 2. Key injection based on pattern ending (see `shouldInjectKey`)
|
|
284
|
+
* 3. Proper spacing for descendant vs direct child selectors
|
|
285
|
+
*
|
|
286
|
+
* @param pattern - A single validated selector pattern
|
|
287
|
+
* @param key - The sub-element key to inject (e.g., 'Label', 'Cell')
|
|
288
|
+
* @returns CSS selector suffix ready to append to the root selector
|
|
289
|
+
*
|
|
290
|
+
* @example
|
|
291
|
+
* processSinglePattern('>', 'Row')
|
|
292
|
+
* // → '> [data-element="Row"]'
|
|
293
|
+
*
|
|
294
|
+
* processSinglePattern('>Body>Row>', 'Cell')
|
|
295
|
+
* // → '> [data-element="Body"] > [data-element="Row"] > [data-element="Cell"]'
|
|
296
|
+
*
|
|
297
|
+
* processSinglePattern('::before', 'Before')
|
|
298
|
+
* // → '::before' (no key injection for pseudo on root)
|
|
299
|
+
*
|
|
300
|
+
* processSinglePattern('>@:hover', 'Item')
|
|
301
|
+
* // → '> [data-element="Item"]:hover'
|
|
302
|
+
*/
|
|
303
|
+
function processSinglePattern(pattern, key) {
|
|
304
|
+
const normalized = pattern.replace(/^&/, "").trim();
|
|
305
|
+
if (!normalized) return ` [data-element="${key}"]`;
|
|
306
|
+
const startsWithPseudo = /^::?[a-z]/.test(normalized);
|
|
307
|
+
let result = transformPattern(normalized);
|
|
308
|
+
if (result.includes("@")) {
|
|
309
|
+
result = result.replace(/@ (?=[.:])/g, "@");
|
|
310
|
+
result = result.replace(/@/g, `[data-element="${key}"]`);
|
|
311
|
+
if (!startsWithPseudo && !result.startsWith(" ")) result = " " + result;
|
|
312
|
+
return result;
|
|
313
|
+
}
|
|
314
|
+
if (shouldInjectKey(normalized)) result = result + ` [data-element="${key}"]`;
|
|
315
|
+
if (!startsWithPseudo && !result.startsWith(" ")) result = " " + result;
|
|
316
|
+
return result;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Transform a selector pattern by converting element names and normalizing spacing.
|
|
320
|
+
*
|
|
321
|
+
* This is a character-by-character tokenizer that:
|
|
322
|
+
* - Converts uppercase names to `[data-element="Name"]` selectors
|
|
323
|
+
* - Adds proper spacing around combinators (>, +, ~)
|
|
324
|
+
* - Preserves lowercase tags, classes, pseudos, and attributes as-is
|
|
325
|
+
* - Keeps @ placeholder for later replacement
|
|
326
|
+
*
|
|
327
|
+
* The tokenizer handles these token types in order:
|
|
328
|
+
* 1. Whitespace (skipped)
|
|
329
|
+
* 2. Combinators: >, +, ~ (add surrounding spaces)
|
|
330
|
+
* 3. Uppercase names: Body, Row (convert to [data-element="..."])
|
|
331
|
+
* 4. @ placeholder (keep for later replacement)
|
|
332
|
+
* 5. Pseudo: :hover, ::before (attach to previous token)
|
|
333
|
+
* 6. Tags: a, div, button (keep as-is with spacing)
|
|
334
|
+
* 7. Classes: .active (attach to previous element/tag/placeholder)
|
|
335
|
+
* 8. Attributes: [type="text"] (keep as-is)
|
|
336
|
+
*
|
|
337
|
+
* @param pattern - The raw selector pattern to transform
|
|
338
|
+
* @returns Transformed pattern with proper CSS selector syntax
|
|
339
|
+
*
|
|
340
|
+
* @example
|
|
341
|
+
* transformPattern('>Body>Row>')
|
|
342
|
+
* // → '> [data-element="Body"] > [data-element="Row"] >'
|
|
343
|
+
*
|
|
344
|
+
* transformPattern('button.primary:hover')
|
|
345
|
+
* // → 'button.primary:hover'
|
|
346
|
+
*/
|
|
347
|
+
function transformPattern(pattern) {
|
|
348
|
+
let result = "";
|
|
349
|
+
let i = 0;
|
|
350
|
+
while (i < pattern.length) {
|
|
351
|
+
const char = pattern[i];
|
|
352
|
+
if (/\s/.test(char)) {
|
|
353
|
+
i++;
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
356
|
+
if (/[>+~]/.test(char)) {
|
|
357
|
+
if (result && !result.endsWith(" ")) result += " ";
|
|
358
|
+
result += char;
|
|
359
|
+
i++;
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
if (/[A-Z]/.test(char)) {
|
|
363
|
+
let name = "";
|
|
364
|
+
while (i < pattern.length && /[a-zA-Z0-9]/.test(pattern[i])) {
|
|
365
|
+
name += pattern[i];
|
|
366
|
+
i++;
|
|
367
|
+
}
|
|
368
|
+
if (result && !result.endsWith(" ")) result += " ";
|
|
369
|
+
result += `[data-element="${name}"]`;
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
if (char === "@") {
|
|
373
|
+
if (result && !result.endsWith(" ")) result += " ";
|
|
374
|
+
result += "@";
|
|
375
|
+
i++;
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
if (char === ":") {
|
|
379
|
+
let pseudo = "";
|
|
380
|
+
while (i < pattern.length && !/[\s>+~,@]/.test(pattern[i]) && !/[A-Z]/.test(pattern[i])) {
|
|
381
|
+
pseudo += pattern[i];
|
|
382
|
+
i++;
|
|
383
|
+
}
|
|
384
|
+
result += pseudo;
|
|
385
|
+
continue;
|
|
386
|
+
}
|
|
387
|
+
if (/[a-z]/.test(char)) {
|
|
388
|
+
let tag = "";
|
|
389
|
+
while (i < pattern.length && /[a-z0-9-]/.test(pattern[i])) {
|
|
390
|
+
tag += pattern[i];
|
|
391
|
+
i++;
|
|
392
|
+
}
|
|
393
|
+
if (result && !result.endsWith(" ")) result += " ";
|
|
394
|
+
result += tag;
|
|
395
|
+
continue;
|
|
396
|
+
}
|
|
397
|
+
if (char === ".") {
|
|
398
|
+
const lastNonSpace = result.replace(/\s+$/, "").slice(-1);
|
|
399
|
+
const attachToLast = lastNonSpace === "]" || lastNonSpace === "@" || /[a-zA-Z0-9-]/.test(lastNonSpace);
|
|
400
|
+
if (result && !attachToLast && !result.endsWith(" ")) result += " ";
|
|
401
|
+
let cls = ".";
|
|
402
|
+
i++;
|
|
403
|
+
while (i < pattern.length && /[a-zA-Z0-9_-]/.test(pattern[i])) {
|
|
404
|
+
cls += pattern[i];
|
|
405
|
+
i++;
|
|
406
|
+
}
|
|
407
|
+
result += cls;
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
410
|
+
if (char === "[") {
|
|
411
|
+
const lastNonSpace = result.replace(/\s+$/, "").slice(-1);
|
|
412
|
+
const attachToLast = lastNonSpace === "]" || lastNonSpace === "@" || /[a-zA-Z0-9-]/.test(lastNonSpace);
|
|
413
|
+
if (result && !attachToLast && !result.endsWith(" ")) result += " ";
|
|
414
|
+
let attr = "";
|
|
415
|
+
let depth = 0;
|
|
416
|
+
while (i < pattern.length) {
|
|
417
|
+
attr += pattern[i];
|
|
418
|
+
if (pattern[i] === "[") depth++;
|
|
419
|
+
if (pattern[i] === "]") depth--;
|
|
420
|
+
i++;
|
|
421
|
+
if (depth === 0) break;
|
|
422
|
+
}
|
|
423
|
+
result += attr;
|
|
424
|
+
continue;
|
|
425
|
+
}
|
|
426
|
+
result += char;
|
|
427
|
+
i++;
|
|
428
|
+
}
|
|
429
|
+
return result;
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Determine if the sub-element key should be auto-injected based on pattern ending.
|
|
433
|
+
*
|
|
434
|
+
* Key injection rules (when no @ placeholder is present):
|
|
435
|
+
*
|
|
436
|
+
* | Pattern Ending | Inject Key? | Example | Result |
|
|
437
|
+
* |----------------|-------------|---------|--------|
|
|
438
|
+
* | Combinator (>, +, ~) | Yes | `'>Body>'` | `> [data-element="Body"] > [el]` |
|
|
439
|
+
* | Uppercase element | Yes | `'>Body>Row'` | `> [el1] > [el2] [key]` |
|
|
440
|
+
* | Lowercase tag | Yes | `'>ul>li'` | `> ul > li [key]` |
|
|
441
|
+
* | Pseudo (:hover, ::before) | No | `'::before'` | `::before` |
|
|
442
|
+
* | Class (.active) | No | `'.active'` | `.active` |
|
|
443
|
+
* | Attribute ([type]) | No | `'[type="text"]'` | `[type="text"]` |
|
|
444
|
+
*
|
|
445
|
+
* @param pattern - The normalized pattern (after stripping &)
|
|
446
|
+
* @returns true if key should be injected, false otherwise
|
|
447
|
+
*
|
|
448
|
+
* @example
|
|
449
|
+
* shouldInjectKey('>') // → true (trailing combinator)
|
|
450
|
+
* shouldInjectKey('>Body>Row') // → true (ends with element)
|
|
451
|
+
* shouldInjectKey('>ul>li') // → true (ends with tag)
|
|
452
|
+
* shouldInjectKey('::before') // → false (ends with pseudo)
|
|
453
|
+
* shouldInjectKey('.active') // → false (ends with class)
|
|
454
|
+
* shouldInjectKey('a:hover') // → false (ends with pseudo)
|
|
455
|
+
* shouldInjectKey('button.primary') // → false (ends with class)
|
|
456
|
+
*/
|
|
457
|
+
function shouldInjectKey(pattern) {
|
|
458
|
+
const trimmed = pattern.trim();
|
|
459
|
+
if (/[>+~]$/.test(trimmed)) return true;
|
|
460
|
+
if (/(?:^|[\s>+~\]:])[A-Z][a-zA-Z0-9]*$/.test(trimmed)) return true;
|
|
461
|
+
if (/(?<![:.])(?:^|[\s>+~])[a-z][a-z0-9-]*$/.test(trimmed)) return true;
|
|
462
|
+
return false;
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Normalize selector suffix from $ property
|
|
466
|
+
*/
|
|
467
|
+
function normalizeSelectorSuffix(suffix) {
|
|
468
|
+
if (!suffix) return "";
|
|
469
|
+
return suffix.startsWith("&") ? suffix.slice(1) : suffix;
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Build handler queue from style keys
|
|
473
|
+
*/
|
|
474
|
+
function buildHandlerQueue(styleKeys, styles) {
|
|
475
|
+
const queue = [];
|
|
476
|
+
const seenHandlers = /* @__PURE__ */ new Set();
|
|
477
|
+
for (const styleName of styleKeys) {
|
|
478
|
+
let handlers = STYLE_HANDLER_MAP[styleName];
|
|
479
|
+
if (!handlers) handlers = STYLE_HANDLER_MAP[styleName] = [createStyle(styleName)];
|
|
480
|
+
for (const handler of handlers) {
|
|
481
|
+
if (seenHandlers.has(handler)) continue;
|
|
482
|
+
seenHandlers.add(handler);
|
|
483
|
+
const lookupStyles = handler.__lookupStyles;
|
|
484
|
+
const styleMap = {};
|
|
485
|
+
for (const name of lookupStyles) {
|
|
486
|
+
const val = styles[name];
|
|
487
|
+
if (val !== void 0) styleMap[name] = val;
|
|
488
|
+
}
|
|
489
|
+
queue.push({
|
|
490
|
+
handler,
|
|
491
|
+
styleMap
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
return queue;
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Compute all valid state combinations for a handler's lookup styles
|
|
499
|
+
*/
|
|
500
|
+
function computeStateCombinations(exclusiveByStyle, lookupStyles) {
|
|
501
|
+
const combinations = cartesianProduct(lookupStyles.map((style) => exclusiveByStyle.get(style) || []));
|
|
502
|
+
const snapshots = [];
|
|
503
|
+
for (const combo of combinations) {
|
|
504
|
+
const simplified = simplifyCondition(and(...combo.map((e) => e.exclusiveCondition)));
|
|
505
|
+
if (simplified.kind === "false") continue;
|
|
506
|
+
const values = {};
|
|
507
|
+
for (const entry of combo) values[entry.styleKey] = entry.value;
|
|
508
|
+
snapshots.push({
|
|
509
|
+
condition: simplified,
|
|
510
|
+
values
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
return snapshots;
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Cartesian product of arrays
|
|
517
|
+
*/
|
|
518
|
+
function cartesianProduct(arrays) {
|
|
519
|
+
if (arrays.length === 0) return [[]];
|
|
520
|
+
const nonEmpty = arrays.filter((a) => a.length > 0);
|
|
521
|
+
if (nonEmpty.length === 0) return [[]];
|
|
522
|
+
return nonEmpty.reduce((acc, arr) => acc.flatMap((combo) => arr.map((item) => [...combo, item])), [[]]);
|
|
523
|
+
}
|
|
524
|
+
/**
|
|
525
|
+
* Merge rules with identical CSS output
|
|
526
|
+
*/
|
|
527
|
+
function mergeByValue(rules) {
|
|
528
|
+
const groups = /* @__PURE__ */ new Map();
|
|
529
|
+
for (const rule of rules) {
|
|
530
|
+
const key = `${rule.selectorSuffix}|${JSON.stringify(rule.declarations)}`;
|
|
531
|
+
if (!groups.has(key)) groups.set(key, []);
|
|
532
|
+
groups.get(key).push(rule);
|
|
533
|
+
}
|
|
534
|
+
const merged = [];
|
|
535
|
+
for (const [, groupRules] of groups) if (groupRules.length === 1) merged.push(groupRules[0]);
|
|
536
|
+
else {
|
|
537
|
+
const mergedCondition = simplifyCondition(or(...groupRules.map((r) => r.condition)));
|
|
538
|
+
merged.push({
|
|
539
|
+
condition: mergedCondition,
|
|
540
|
+
declarations: groupRules[0].declarations,
|
|
541
|
+
selectorSuffix: groupRules[0].selectorSuffix
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
return merged;
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* Build selector fragment from a variant (without className prefix)
|
|
548
|
+
*/
|
|
549
|
+
function buildSelectorFromVariant(variant, selectorSuffix) {
|
|
550
|
+
let selector = "";
|
|
551
|
+
for (const mod of variant.modifierConditions) selector += modifierToCSS(mod);
|
|
552
|
+
for (const pseudo of variant.pseudoConditions) selector += pseudoToCSS(pseudo);
|
|
553
|
+
selector += selectorSuffix;
|
|
554
|
+
for (const own of variant.ownConditions) if ("attribute" in own) selector += modifierToCSS(own);
|
|
555
|
+
else selector += pseudoToCSS(own);
|
|
556
|
+
return selector;
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* Materialize a computed rule to final CSS format
|
|
560
|
+
*
|
|
561
|
+
* Returns an array because OR conditions may generate multiple CSS rules
|
|
562
|
+
* (when different branches have different at-rules)
|
|
563
|
+
*/
|
|
564
|
+
function materializeComputedRule(rule) {
|
|
565
|
+
const components = conditionToCSS(rule.condition);
|
|
566
|
+
if (components.isImpossible || components.variants.length === 0) return [];
|
|
567
|
+
const declarations = Object.entries(rule.declarations).map(([prop, value]) => `${prop}: ${value};`).join(" ");
|
|
568
|
+
const getRootPrefixKey = (variant) => {
|
|
569
|
+
return variant.rootConditions.map((r) => r.negated ? `!${r.selector}` : r.selector).sort().join("|");
|
|
570
|
+
};
|
|
571
|
+
const byAtRules = /* @__PURE__ */ new Map();
|
|
572
|
+
for (const variant of components.variants) {
|
|
573
|
+
const atRules = buildAtRulesFromVariant(variant);
|
|
574
|
+
const key = atRules.sort().join("|||") + "###" + getRootPrefixKey(variant);
|
|
575
|
+
const group = byAtRules.get(key);
|
|
576
|
+
if (group) group.variants.push(variant);
|
|
577
|
+
else byAtRules.set(key, {
|
|
578
|
+
variants: [variant],
|
|
579
|
+
atRules,
|
|
580
|
+
rootPrefix: rootConditionsToCSS(variant.rootConditions)
|
|
581
|
+
});
|
|
582
|
+
}
|
|
583
|
+
const rules = [];
|
|
584
|
+
for (const [, group] of byAtRules) {
|
|
585
|
+
const selectorFragments = group.variants.map((v) => buildSelectorFromVariant(v, rule.selectorSuffix));
|
|
586
|
+
const cssRule = {
|
|
587
|
+
selector: selectorFragments.length === 1 ? selectorFragments[0] : selectorFragments,
|
|
588
|
+
declarations
|
|
589
|
+
};
|
|
590
|
+
if (group.atRules.length > 0) cssRule.atRules = group.atRules;
|
|
591
|
+
if (group.rootPrefix) cssRule.rootPrefix = group.rootPrefix;
|
|
592
|
+
rules.push(cssRule);
|
|
593
|
+
}
|
|
594
|
+
return rules;
|
|
595
|
+
}
|
|
596
|
+
function renderStyles(styles, classNameOrSelector, options) {
|
|
597
|
+
const directSelector = !!classNameOrSelector;
|
|
598
|
+
if (!styles) return directSelector ? [] : { rules: [] };
|
|
599
|
+
const cacheKey = stringifyStyles(styles);
|
|
600
|
+
let rules = pipelineCache.get(cacheKey);
|
|
601
|
+
if (!rules) {
|
|
602
|
+
rules = runPipeline(styles, createStateParserContext(styles));
|
|
603
|
+
pipelineCache.set(cacheKey, rules);
|
|
604
|
+
}
|
|
605
|
+
if (directSelector) {
|
|
606
|
+
const shouldDouble = options?.doubleSelector ?? false;
|
|
607
|
+
return rules.map((rule) => {
|
|
608
|
+
const result = {
|
|
609
|
+
selector: (Array.isArray(rule.selector) ? rule.selector : rule.selector ? [rule.selector] : [""]).map((part) => {
|
|
610
|
+
let sel = part ? `${classNameOrSelector}${part}` : classNameOrSelector;
|
|
611
|
+
if (shouldDouble && sel.startsWith(".")) {
|
|
612
|
+
const classMatch = sel.match(/^\.[a-zA-Z_-][a-zA-Z0-9_-]*/);
|
|
613
|
+
if (classMatch) sel = classMatch[0] + sel;
|
|
614
|
+
}
|
|
615
|
+
if (rule.rootPrefix) sel = `${rule.rootPrefix} ${sel}`;
|
|
616
|
+
return sel;
|
|
617
|
+
}).join(", "),
|
|
618
|
+
declarations: rule.declarations
|
|
619
|
+
};
|
|
620
|
+
if (rule.atRules && rule.atRules.length > 0) result.atRules = rule.atRules;
|
|
621
|
+
return result;
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
return { rules: rules.map((r) => ({
|
|
625
|
+
selector: Array.isArray(r.selector) ? r.selector.join("|||") : r.selector,
|
|
626
|
+
declarations: r.declarations,
|
|
627
|
+
atRules: r.atRules,
|
|
628
|
+
needsClassName: true,
|
|
629
|
+
rootPrefix: r.rootPrefix
|
|
630
|
+
})) };
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
//#endregion
|
|
634
|
+
export { isSelector, renderStyles };
|
|
635
|
+
//# sourceMappingURL=index.mjs.map
|