@tenphi/tasty 3.0.1 → 3.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/README.md +16 -16
- package/dist/{babel-HlEpSZrj.d.ts → babel-R2qT7yLN.d.ts} +2 -2
- package/dist/{collector-D14DcZx9.js → collector-D7yzmG5G.js} +3 -3
- package/dist/{collector-D14DcZx9.js.map → collector-D7yzmG5G.js.map} +1 -1
- package/dist/{collector-BPzZezAG.d.ts → collector-D8o4Wdq-.d.ts} +2 -2
- package/dist/{config-CCcE_tqx.js → config-CwQ-fAsp.js} +674 -330
- package/dist/config-CwQ-fAsp.js.map +1 -0
- package/dist/{config-D2INrjr_.d.ts → config-De8L9NWM.d.ts} +2 -2
- package/dist/core/index.d.ts +4 -4
- package/dist/core/index.js +5 -5
- package/dist/{core-B5d0IPi2.js → core-CqSh853z.js} +11 -12
- package/dist/core-CqSh853z.js.map +1 -0
- package/dist/{css-writer-B5DBoxhf.js → css-writer-dS1srTkS.js} +3 -3
- package/dist/{css-writer-B5DBoxhf.js.map → css-writer-dS1srTkS.js.map} +1 -1
- package/dist/{format-rules-BbKDjsfO.js → format-rules-CaW4lJGg.js} +11 -9
- package/dist/format-rules-CaW4lJGg.js.map +1 -0
- package/dist/{hydrate-CwALW3J9.js → hydrate-uFv9kx7G.js} +2 -2
- package/dist/{hydrate-CwALW3J9.js.map → hydrate-uFv9kx7G.js.map} +1 -1
- package/dist/{index-BAAbdfRs.d.ts → index-DzGxoeyN.d.ts} +5 -5
- package/dist/{index-l_NdJSUS.d.ts → index-KUYya3x7.d.ts} +11 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.js +6 -6
- package/dist/{keyframes-B8M1FmtE.js → keyframes-DaZhjqkd.js} +2 -2
- package/dist/{keyframes-B8M1FmtE.js.map → keyframes-DaZhjqkd.js.map} +1 -1
- package/dist/{merge-styles-NEvqayL_.d.ts → merge-styles-DLm4wdnb.d.ts} +2 -2
- package/dist/{merge-styles--1zOSFlS.js → merge-styles-H8LFJ5HY.js} +2 -2
- package/dist/{merge-styles--1zOSFlS.js.map → merge-styles-H8LFJ5HY.js.map} +1 -1
- package/dist/{resolve-recipes-Caix5NnH.js → resolve-recipes-aN94fjqS.js} +3 -3
- package/dist/{resolve-recipes-Caix5NnH.js.map → resolve-recipes-aN94fjqS.js.map} +1 -1
- package/dist/ssr/astro-client.js +1 -1
- package/dist/ssr/astro.js +3 -3
- 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/static/index.d.ts +2 -2
- package/dist/static/index.js +1 -1
- package/dist/zero/babel.d.ts +1 -1
- package/dist/zero/babel.js +4 -4
- package/dist/zero/index.d.ts +1 -1
- package/dist/zero/index.js +1 -1
- package/dist/zero/next.d.ts +1 -1
- package/docs/ai-agents.md +3 -0
- package/docs/configuration.md +11 -6
- package/docs/dsl.md +99 -2
- package/docs/styles.md +3 -1
- package/package.json +14 -10
- package/dist/config-CCcE_tqx.js.map +0 -1
- package/dist/core-B5d0IPi2.js.map +0 -1
- package/dist/format-rules-BbKDjsfO.js.map +0 -1
|
@@ -1,136 +1,141 @@
|
|
|
1
|
-
//#region src/parser/
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const node = this.map.get(old);
|
|
86
|
-
if (!node) {
|
|
87
|
-
if (this.head === old) this.head = null;
|
|
88
|
-
this.tail = null;
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
if (node.prev) {
|
|
92
|
-
const prevNode = this.map.get(node.prev);
|
|
93
|
-
if (prevNode) prevNode.next = null;
|
|
94
|
-
}
|
|
95
|
-
this.tail = node.prev;
|
|
96
|
-
if (this.head === old) this.head = null;
|
|
97
|
-
this.map.delete(old);
|
|
98
|
-
if (this.onEvict) try {
|
|
99
|
-
this.onEvict(old, node.value);
|
|
100
|
-
} catch {}
|
|
101
|
-
}
|
|
102
|
-
clear() {
|
|
103
|
-
this.map.clear();
|
|
104
|
-
this.head = this.tail = null;
|
|
105
|
-
}
|
|
106
|
-
};
|
|
1
|
+
//#region src/parser/const.ts
|
|
2
|
+
const VALUE_KEYWORDS = new Set([
|
|
3
|
+
"auto",
|
|
4
|
+
"max-content",
|
|
5
|
+
"min-content",
|
|
6
|
+
"fit-content",
|
|
7
|
+
"stretch",
|
|
8
|
+
"initial",
|
|
9
|
+
"inherit",
|
|
10
|
+
"revert",
|
|
11
|
+
"unset",
|
|
12
|
+
"revert-layer"
|
|
13
|
+
]);
|
|
14
|
+
const CSS_WIDE_KEYWORDS = new Set([
|
|
15
|
+
"initial",
|
|
16
|
+
"inherit",
|
|
17
|
+
"revert",
|
|
18
|
+
"unset",
|
|
19
|
+
"revert-layer"
|
|
20
|
+
]);
|
|
21
|
+
/**
|
|
22
|
+
* Color functions that *derive* a color from other colors. They take no alpha
|
|
23
|
+
* channel, so opacity has to wrap the whole call in `color-mix()` instead of
|
|
24
|
+
* being appended after a slash.
|
|
25
|
+
*/
|
|
26
|
+
const DERIVED_COLOR_FUNCS_LIST = [
|
|
27
|
+
"color-mix",
|
|
28
|
+
"color-contrast",
|
|
29
|
+
"contrast-color",
|
|
30
|
+
"light-dark"
|
|
31
|
+
];
|
|
32
|
+
const DERIVED_COLOR_FUNCS = new Set(DERIVED_COLOR_FUNCS_LIST);
|
|
33
|
+
/**
|
|
34
|
+
* Every color function the parser recognizes. The ones outside
|
|
35
|
+
* `DERIVED_COLOR_FUNCS` take channels as arguments, optionally followed by
|
|
36
|
+
* `/ <alpha>` — which is where an opacity suffix writes.
|
|
37
|
+
*/
|
|
38
|
+
const COLOR_FUNCS = new Set([
|
|
39
|
+
"rgb",
|
|
40
|
+
"rgba",
|
|
41
|
+
"hsl",
|
|
42
|
+
"hsla",
|
|
43
|
+
"hwb",
|
|
44
|
+
"lab",
|
|
45
|
+
"lch",
|
|
46
|
+
"oklab",
|
|
47
|
+
"oklch",
|
|
48
|
+
"color",
|
|
49
|
+
"device-cmyk",
|
|
50
|
+
"gray",
|
|
51
|
+
...DERIVED_COLOR_FUNCS_LIST
|
|
52
|
+
]);
|
|
53
|
+
/** A value that is a single `name(args)` call: captures the name and the args. */
|
|
54
|
+
const RE_FUNC_CALL = /^([a-z][a-z0-9-]*)\((.+)\)$/i;
|
|
55
|
+
/**
|
|
56
|
+
* The color function a value calls at its top level, lowercased — or `null` when
|
|
57
|
+
* the value is not a single color function call.
|
|
58
|
+
*/
|
|
59
|
+
function colorFuncName(value) {
|
|
60
|
+
const match = value.match(RE_FUNC_CALL);
|
|
61
|
+
if (!match) return null;
|
|
62
|
+
const name = match[1].toLowerCase();
|
|
63
|
+
return COLOR_FUNCS.has(name) ? name : null;
|
|
64
|
+
}
|
|
65
|
+
const RE_UNIT_NUM = /^[+-]?(?:\d*\.\d+|\d+)([a-z][a-z0-9]*)$/;
|
|
66
|
+
const RE_NUMBER = /^[+-]?(?:\d*\.\d+|\d+)$/;
|
|
67
|
+
const RE_HEX = /^(?:[0-9a-f]{3,4}|[0-9a-f]{6}(?:[0-9a-f]{2})?)$/;
|
|
68
|
+
const RE_RAW_UNIT = /^([+-]?(?:\d*\.\d+|\d+))([a-z%]+)$/;
|
|
69
|
+
const CANONICAL_FUNC_CASE = new Map([
|
|
70
|
+
["translatex", "translateX"],
|
|
71
|
+
["translatey", "translateY"],
|
|
72
|
+
["translatez", "translateZ"],
|
|
73
|
+
["scalex", "scaleX"],
|
|
74
|
+
["scaley", "scaleY"],
|
|
75
|
+
["scalez", "scaleZ"],
|
|
76
|
+
["rotatex", "rotateX"],
|
|
77
|
+
["rotatey", "rotateY"],
|
|
78
|
+
["rotatez", "rotateZ"],
|
|
79
|
+
["skewx", "skewX"],
|
|
80
|
+
["skewy", "skewY"]
|
|
81
|
+
]);
|
|
82
|
+
function canonicalFuncName(lowered) {
|
|
83
|
+
return CANONICAL_FUNC_CASE.get(lowered) ?? lowered;
|
|
84
|
+
}
|
|
107
85
|
//#endregion
|
|
108
|
-
//#region src/utils/
|
|
109
|
-
|
|
110
|
-
|
|
86
|
+
//#region src/utils/string.ts
|
|
87
|
+
function toSnakeCase(str) {
|
|
88
|
+
return str.replace(/[A-Z]/g, (s) => `-${s.toLowerCase()}`);
|
|
89
|
+
}
|
|
111
90
|
/**
|
|
112
|
-
*
|
|
113
|
-
* into its concrete color output.
|
|
91
|
+
* Normalize a DSL identifier to the CSS custom-property name it emits.
|
|
114
92
|
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
93
|
+
* CSS custom-property names are case-sensitive, so `$myVar` has to keep its
|
|
94
|
+
* inner case to reference `--myVar`. A leading capital is the one exception:
|
|
95
|
+
* `$Foo` is not a supported way to name a property, so the first character is
|
|
96
|
+
* folded rather than kebab-cased (`--foo`, not `---foo`) and every later
|
|
97
|
+
* character is left alone.
|
|
120
98
|
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
* the `#token.alpha` injection path.
|
|
99
|
+
* Every place that turns a `$name` / `#name` identifier into a CSS name goes
|
|
100
|
+
* through this, so authoring a token and referencing it always agree.
|
|
124
101
|
*/
|
|
125
|
-
function
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
102
|
+
function normalizeDslName(name) {
|
|
103
|
+
if (!name) return name;
|
|
104
|
+
const first = name[0];
|
|
105
|
+
const lower = first.toLowerCase();
|
|
106
|
+
return lower === first ? name : lower + name.slice(1);
|
|
107
|
+
}
|
|
108
|
+
/** A DSL identifier: `$name`, `$$name`, `#name` or `##name`. */
|
|
109
|
+
const RE_DSL_IDENTIFIER = /(\$\$?|##?)([a-zA-Z_][a-zA-Z0-9_-]*)/g;
|
|
110
|
+
/**
|
|
111
|
+
* Case-fold a DSL string for parsing, preserving the case of custom-property
|
|
112
|
+
* names.
|
|
113
|
+
*
|
|
114
|
+
* Everything the parser matches on — keywords, units, modifiers, function names,
|
|
115
|
+
* color-token names — is compared lowercase, so the whole string used to be
|
|
116
|
+
* lowercased up front. That also folded custom-property names, which are
|
|
117
|
+
* case-sensitive in CSS: `$myVar` referenced `var(--myvar)` while the token
|
|
118
|
+
* definition emitted `--myVar`, so the two could never meet.
|
|
119
|
+
*
|
|
120
|
+
* Identifier bodies now keep their case (their first character still folds, see
|
|
121
|
+
* {@link normalizeDslName}); everything else is lowercased exactly as before.
|
|
122
|
+
* Hex literals are excluded — `#FF0000` is a color, not a name, and must fold to
|
|
123
|
+
* match {@link RE_HEX}.
|
|
124
|
+
*/
|
|
125
|
+
function foldDslCase(src) {
|
|
126
|
+
const folded = src.toLowerCase();
|
|
127
|
+
if (folded === src || !src.includes("$") && !src.includes("#")) return folded;
|
|
128
|
+
RE_DSL_IDENTIFIER.lastIndex = 0;
|
|
129
|
+
let out = "";
|
|
130
|
+
let last = 0;
|
|
131
|
+
let match;
|
|
132
|
+
while (match = RE_DSL_IDENTIFIER.exec(src)) {
|
|
133
|
+
const [whole, prefix, body] = match;
|
|
134
|
+
out += src.slice(last, match.index).toLowerCase();
|
|
135
|
+
out += prefix + (prefix[0] === "#" && RE_HEX.test(body.toLowerCase()) ? body.toLowerCase() : normalizeDslName(body));
|
|
136
|
+
last = match.index + whole.length;
|
|
137
|
+
}
|
|
138
|
+
return out + src.slice(last).toLowerCase();
|
|
134
139
|
}
|
|
135
140
|
//#endregion
|
|
136
141
|
//#region src/utils/color-math.ts
|
|
@@ -844,32 +849,167 @@ function hslStringToRgb(hslStr) {
|
|
|
844
849
|
return `rgb(${Math.round(r)} ${Math.round(g)} ${Math.round(b)})`;
|
|
845
850
|
}
|
|
846
851
|
/**
|
|
847
|
-
* Convert an `oklch()` color string to an `rgb()`/`rgba()` CSS string.
|
|
848
|
-
* Supports deg/turn/rad hue units and percentage lightness.
|
|
852
|
+
* Convert an `oklch()` color string to an `rgb()`/`rgba()` CSS string.
|
|
853
|
+
* Supports deg/turn/rad hue units and percentage lightness.
|
|
854
|
+
*/
|
|
855
|
+
function oklchStringToRgb(oklchStr) {
|
|
856
|
+
const match = oklchStr.match(/oklch\(([^)]+)\)/i);
|
|
857
|
+
if (!match) return null;
|
|
858
|
+
const [colorPart, alphaPart] = match[1].trim().split("/");
|
|
859
|
+
const parts = colorPart.trim().split(/[,\s]+/).filter(Boolean);
|
|
860
|
+
if (parts.length < 3) return null;
|
|
861
|
+
const parsePercent = (val) => {
|
|
862
|
+
const num = parseFloat(val);
|
|
863
|
+
return val.includes("%") ? num / 100 : num;
|
|
864
|
+
};
|
|
865
|
+
const L = Math.max(0, Math.min(1, parsePercent(parts[0])));
|
|
866
|
+
const C = Math.max(0, parseFloat(parts[1]));
|
|
867
|
+
let H = parseFloat(parts[2]);
|
|
868
|
+
const hueStr = parts[2].toLowerCase();
|
|
869
|
+
if (hueStr.endsWith("turn")) H = parseFloat(hueStr) * 360;
|
|
870
|
+
else if (hueStr.endsWith("rad")) H = parseFloat(hueStr) * 180 / Math.PI;
|
|
871
|
+
else if (hueStr.endsWith("deg")) H = parseFloat(hueStr);
|
|
872
|
+
const [r, g, b] = oklchToRgbValues(L, C, H);
|
|
873
|
+
if (alphaPart) {
|
|
874
|
+
const alpha = parseFloat(alphaPart.trim());
|
|
875
|
+
return `rgba(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)}, ${alpha})`;
|
|
876
|
+
}
|
|
877
|
+
return `rgb(${Math.round(r)} ${Math.round(g)} ${Math.round(b)})`;
|
|
878
|
+
}
|
|
879
|
+
//#endregion
|
|
880
|
+
//#region src/parser/lru.ts
|
|
881
|
+
var Lru = class {
|
|
882
|
+
limit;
|
|
883
|
+
map = /* @__PURE__ */ new Map();
|
|
884
|
+
head = null;
|
|
885
|
+
tail = null;
|
|
886
|
+
onEvict;
|
|
887
|
+
constructor(limit = 1e3, onEvict) {
|
|
888
|
+
this.limit = limit;
|
|
889
|
+
let normalized = Number.isFinite(this.limit) ? Math.floor(this.limit) : 1e3;
|
|
890
|
+
if (normalized <= 0) normalized = 1e3;
|
|
891
|
+
this.limit = normalized;
|
|
892
|
+
this.onEvict = onEvict;
|
|
893
|
+
}
|
|
894
|
+
setOnEvict(fn) {
|
|
895
|
+
this.onEvict = fn;
|
|
896
|
+
}
|
|
897
|
+
get(key) {
|
|
898
|
+
const node = this.map.get(key);
|
|
899
|
+
if (!node) return void 0;
|
|
900
|
+
this.touch(key, node);
|
|
901
|
+
return node.value;
|
|
902
|
+
}
|
|
903
|
+
set(key, value) {
|
|
904
|
+
let node = this.map.get(key);
|
|
905
|
+
if (node) {
|
|
906
|
+
node.value = value;
|
|
907
|
+
this.touch(key, node);
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
node = {
|
|
911
|
+
prev: null,
|
|
912
|
+
next: this.head,
|
|
913
|
+
value
|
|
914
|
+
};
|
|
915
|
+
if (this.head) {
|
|
916
|
+
const headNode = this.map.get(this.head);
|
|
917
|
+
if (headNode) headNode.prev = key;
|
|
918
|
+
}
|
|
919
|
+
this.head = key;
|
|
920
|
+
if (!this.tail) this.tail = key;
|
|
921
|
+
this.map.set(key, node);
|
|
922
|
+
if (this.map.size > this.limit) this.evict();
|
|
923
|
+
}
|
|
924
|
+
delete(key) {
|
|
925
|
+
const node = this.map.get(key);
|
|
926
|
+
if (!node) return;
|
|
927
|
+
if (node.prev) {
|
|
928
|
+
const prevNode = this.map.get(node.prev);
|
|
929
|
+
if (prevNode) prevNode.next = node.next;
|
|
930
|
+
}
|
|
931
|
+
if (node.next) {
|
|
932
|
+
const nextNode = this.map.get(node.next);
|
|
933
|
+
if (nextNode) nextNode.prev = node.prev;
|
|
934
|
+
}
|
|
935
|
+
if (this.head === key) this.head = node.next;
|
|
936
|
+
if (this.tail === key) this.tail = node.prev;
|
|
937
|
+
this.map.delete(key);
|
|
938
|
+
}
|
|
939
|
+
keys() {
|
|
940
|
+
return this.map.keys();
|
|
941
|
+
}
|
|
942
|
+
touch(key, node) {
|
|
943
|
+
if (this.head === key) return;
|
|
944
|
+
if (node.prev) {
|
|
945
|
+
const prevNode = this.map.get(node.prev);
|
|
946
|
+
if (prevNode) prevNode.next = node.next;
|
|
947
|
+
}
|
|
948
|
+
if (node.next) {
|
|
949
|
+
const nextNode = this.map.get(node.next);
|
|
950
|
+
if (nextNode) nextNode.prev = node.prev;
|
|
951
|
+
}
|
|
952
|
+
if (this.tail === key) this.tail = node.prev;
|
|
953
|
+
node.prev = null;
|
|
954
|
+
node.next = this.head;
|
|
955
|
+
if (this.head) {
|
|
956
|
+
const headNode = this.map.get(this.head);
|
|
957
|
+
if (headNode) headNode.prev = key;
|
|
958
|
+
}
|
|
959
|
+
this.head = key;
|
|
960
|
+
}
|
|
961
|
+
evict() {
|
|
962
|
+
const old = this.tail;
|
|
963
|
+
if (!old) return;
|
|
964
|
+
const node = this.map.get(old);
|
|
965
|
+
if (!node) {
|
|
966
|
+
if (this.head === old) this.head = null;
|
|
967
|
+
this.tail = null;
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
if (node.prev) {
|
|
971
|
+
const prevNode = this.map.get(node.prev);
|
|
972
|
+
if (prevNode) prevNode.next = null;
|
|
973
|
+
}
|
|
974
|
+
this.tail = node.prev;
|
|
975
|
+
if (this.head === old) this.head = null;
|
|
976
|
+
this.map.delete(old);
|
|
977
|
+
if (this.onEvict) try {
|
|
978
|
+
this.onEvict(old, node.value);
|
|
979
|
+
} catch {}
|
|
980
|
+
}
|
|
981
|
+
clear() {
|
|
982
|
+
this.map.clear();
|
|
983
|
+
this.head = this.tail = null;
|
|
984
|
+
}
|
|
985
|
+
};
|
|
986
|
+
//#endregion
|
|
987
|
+
//#region src/utils/function-color.ts
|
|
988
|
+
const RE_FUNC_NAME = /^([a-z][a-z0-9-]*)\s*\(/i;
|
|
989
|
+
const RE_COLOR_OUT = /^(?:rgb|hsl|hwb|lab|lch|oklab|oklch|color)\(|^#|^var\(--/i;
|
|
990
|
+
/**
|
|
991
|
+
* Resolve a `name(...)` value produced by a registered custom parse function
|
|
992
|
+
* into its concrete color output.
|
|
993
|
+
*
|
|
994
|
+
* A color function is just a `functions` entry whose output is an already
|
|
995
|
+
* supported color (`rgb`, `hsl`, `#…`, `oklch`, …). This helper delegates the
|
|
996
|
+
* value to the global parser (which already runs the registered parse function)
|
|
997
|
+
* and returns the result only when it looks like a color. Returns `null` when
|
|
998
|
+
* `str` is not a registered custom function or its output is not a color.
|
|
999
|
+
*
|
|
1000
|
+
* This is the generic replacement for the previously hardcoded okhsl/okhst
|
|
1001
|
+
* conversion branches scattered across `strToRgb`, `resolveToRgbaValues`, and
|
|
1002
|
+
* the `#token.alpha` injection path.
|
|
849
1003
|
*/
|
|
850
|
-
function
|
|
851
|
-
const
|
|
852
|
-
if (!
|
|
853
|
-
const
|
|
854
|
-
|
|
855
|
-
if (
|
|
856
|
-
const
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
};
|
|
860
|
-
const L = Math.max(0, Math.min(1, parsePercent(parts[0])));
|
|
861
|
-
const C = Math.max(0, parseFloat(parts[1]));
|
|
862
|
-
let H = parseFloat(parts[2]);
|
|
863
|
-
const hueStr = parts[2].toLowerCase();
|
|
864
|
-
if (hueStr.endsWith("turn")) H = parseFloat(hueStr) * 360;
|
|
865
|
-
else if (hueStr.endsWith("rad")) H = parseFloat(hueStr) * 180 / Math.PI;
|
|
866
|
-
else if (hueStr.endsWith("deg")) H = parseFloat(hueStr);
|
|
867
|
-
const [r, g, b] = oklchToRgbValues(L, C, H);
|
|
868
|
-
if (alphaPart) {
|
|
869
|
-
const alpha = parseFloat(alphaPart.trim());
|
|
870
|
-
return `rgba(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)}, ${alpha})`;
|
|
871
|
-
}
|
|
872
|
-
return `rgb(${Math.round(r)} ${Math.round(g)} ${Math.round(b)})`;
|
|
1004
|
+
function resolveFunctionColor(str) {
|
|
1005
|
+
const m = RE_FUNC_NAME.exec(str);
|
|
1006
|
+
if (!m) return null;
|
|
1007
|
+
const name = m[1].toLowerCase();
|
|
1008
|
+
getGlobalParser();
|
|
1009
|
+
if (!(name in getGlobalParseFunctions())) return null;
|
|
1010
|
+
const out = getGlobalParser().process(str).output;
|
|
1011
|
+
if (!out || !RE_COLOR_OUT.test(out)) return null;
|
|
1012
|
+
return out;
|
|
873
1013
|
}
|
|
874
1014
|
//#endregion
|
|
875
1015
|
//#region src/utils/color-space.ts
|
|
@@ -891,9 +1031,6 @@ function resetColorSpace() {
|
|
|
891
1031
|
function getColorSpaceSuffix() {
|
|
892
1032
|
return currentColorSpace;
|
|
893
1033
|
}
|
|
894
|
-
function getColorSpaceFunc() {
|
|
895
|
-
return currentColorSpace;
|
|
896
|
-
}
|
|
897
1034
|
function formatNum(n, precision) {
|
|
898
1035
|
return parseFloat(n.toFixed(precision)).toString();
|
|
899
1036
|
}
|
|
@@ -1150,6 +1287,91 @@ function strToColorSpace(color) {
|
|
|
1150
1287
|
return result;
|
|
1151
1288
|
}
|
|
1152
1289
|
/**
|
|
1290
|
+
* Set the alpha of a whole color, replacing any it already carries.
|
|
1291
|
+
*
|
|
1292
|
+
* CSS relative color syntax is how opacity is applied to every color Tasty
|
|
1293
|
+
* emits. `oklch(from <color> l c h / <alpha>)` copies the channels over and
|
|
1294
|
+
* writes the alpha slot, which needs nothing from the color except that it *is*
|
|
1295
|
+
* a color: a `color-mix()`, a `light-dark()`, a `currentcolor`, a
|
|
1296
|
+
* `--name-color` written by hand-authored CSS with no companion variable — all
|
|
1297
|
+
* of them work, where writing into a channel slot directly requires components
|
|
1298
|
+
* the engine may have no way to compute.
|
|
1299
|
+
*
|
|
1300
|
+
* Alpha is *replaced*, not composed. A token holding `rgb(255 0 0 / .8)` faded
|
|
1301
|
+
* to `.5` is alpha `.5`, matching what the channel-components form did and what
|
|
1302
|
+
* a statically-known color still does. `color-mix()` against `transparent`
|
|
1303
|
+
* cannot do this — it would multiply the two to `.4`.
|
|
1304
|
+
*
|
|
1305
|
+
* The alpha slot takes a `<number>` or a `<percentage>`, so an opacity custom
|
|
1306
|
+
* property passes straight through in whichever form the author declared it.
|
|
1307
|
+
*
|
|
1308
|
+
* The space is always `oklch`, regardless of the configured {@link ColorSpace}:
|
|
1309
|
+
* it is unbounded, so a wide-gamut color survives the round trip that a
|
|
1310
|
+
* gamut-limited space would clamp, and it is the space the computed value used
|
|
1311
|
+
* to be reported in. Channels are copied rather than interpolated, so the polar
|
|
1312
|
+
* form costs nothing even for an achromatic color, whose hue is carried through
|
|
1313
|
+
* untouched.
|
|
1314
|
+
*/
|
|
1315
|
+
function overrideColorAlpha(color, alpha) {
|
|
1316
|
+
return `oklch(from ${color} l c h / ${alpha})`;
|
|
1317
|
+
}
|
|
1318
|
+
/**
|
|
1319
|
+
* Compose an alpha onto a color, multiplying with any it already carries.
|
|
1320
|
+
*
|
|
1321
|
+
* This is the counterpart to {@link overrideColorAlpha}, and the difference is
|
|
1322
|
+
* the point. A design token names a color, so fading it *sets* its alpha. But
|
|
1323
|
+
* `currentcolor` is the color an element **inherits**, which an ancestor may
|
|
1324
|
+
* already have faded — `#current.4` there means "40% of what reaches me", and a
|
|
1325
|
+
* nested `#current.18` under it composes to `.072`. Design systems build ramps
|
|
1326
|
+
* out of exactly that, so `#current` composes and a token replaces.
|
|
1327
|
+
*
|
|
1328
|
+
* `color-mix()` against `transparent` is what composes: mixing premultiplied
|
|
1329
|
+
* leaves the channels alone and multiplies the alphas. Its percentage slot takes
|
|
1330
|
+
* no `<number>`, so a `$prop` alpha has to be scaled — which is why an opacity
|
|
1331
|
+
* property used as `#current.$prop` has to hold a unitless number, where a token
|
|
1332
|
+
* accepts either form.
|
|
1333
|
+
*/
|
|
1334
|
+
function mixColorAlpha(color, percentage) {
|
|
1335
|
+
return `color-mix(in oklab, ${color} ${percentage}, transparent)`;
|
|
1336
|
+
}
|
|
1337
|
+
/**
|
|
1338
|
+
* Matches what {@link overrideColorAlpha} builds. The first group is greedy so a
|
|
1339
|
+
* nested override splits on its outermost layer.
|
|
1340
|
+
*/
|
|
1341
|
+
const RE_ALPHA_OVERRIDE = /^oklch\(from (.+) l c h \/ (.+)\)$/;
|
|
1342
|
+
/**
|
|
1343
|
+
* Split what {@link overrideColorAlpha} builds back into the color it faded and
|
|
1344
|
+
* the alpha, or `null` when the value is not one of those.
|
|
1345
|
+
*/
|
|
1346
|
+
function parseAlphaOverride(value) {
|
|
1347
|
+
const match = value.match(RE_ALPHA_OVERRIDE);
|
|
1348
|
+
return match ? {
|
|
1349
|
+
color: match[1],
|
|
1350
|
+
alpha: match[2]
|
|
1351
|
+
} : null;
|
|
1352
|
+
}
|
|
1353
|
+
/** Channel names of each color space, in `<func>()` argument order. */
|
|
1354
|
+
const COLOR_SPACE_CHANNELS = {
|
|
1355
|
+
rgb: "r g b",
|
|
1356
|
+
hsl: "h s l",
|
|
1357
|
+
oklch: "l c h"
|
|
1358
|
+
};
|
|
1359
|
+
/**
|
|
1360
|
+
* Express a color as components of the configured color space *by reference*,
|
|
1361
|
+
* using CSS relative color syntax: `from <color> l c h`.
|
|
1362
|
+
*
|
|
1363
|
+
* Static colors are decomposed into numbers (see `getColorSpaceComponents`), but
|
|
1364
|
+
* a color the engine cannot evaluate at build time — a `color-mix()`, a
|
|
1365
|
+
* `light-dark()`, a `color()` in a space with no conversion, anything reached
|
|
1366
|
+
* through `var()` — has no numbers to decompose. Handing back the relative form
|
|
1367
|
+
* keeps the `--name-color-{space}` companion usable anyway: the browser resolves
|
|
1368
|
+
* the channels, so `oklch(var(--name-color-oklch) / .5)` still applies opacity to
|
|
1369
|
+
* whatever the color turns out to be.
|
|
1370
|
+
*/
|
|
1371
|
+
function toRelativeColorSpaceComponents(color) {
|
|
1372
|
+
return `from ${color} ${COLOR_SPACE_CHANNELS[currentColorSpace]}`;
|
|
1373
|
+
}
|
|
1374
|
+
/**
|
|
1153
1375
|
* Extract the decomposed components of a color in the configured color space.
|
|
1154
1376
|
* Returns a space-separated string of components without the wrapping function.
|
|
1155
1377
|
* Alpha is NOT included — components are used for alpha composition via `/ alpha`.
|
|
@@ -1170,6 +1392,41 @@ function getColorSpaceComponents(color) {
|
|
|
1170
1392
|
return result;
|
|
1171
1393
|
}
|
|
1172
1394
|
/**
|
|
1395
|
+
* Rewrite a color into the `--name-color-{space}` components that `#name.alpha`
|
|
1396
|
+
* composes opacity onto.
|
|
1397
|
+
*
|
|
1398
|
+
* A `var()` chain is rewritten reference by reference so the fallback order
|
|
1399
|
+
* survives; a color the engine can evaluate is decomposed into numbers; anything
|
|
1400
|
+
* left — a derived color function, a `color()` in a space with no conversion —
|
|
1401
|
+
* falls back to relative color syntax and lets the browser do it.
|
|
1402
|
+
*
|
|
1403
|
+
* Returns the input unchanged when there is nothing to rewrite, so callers can
|
|
1404
|
+
* tell whether the conversion found anything.
|
|
1405
|
+
*
|
|
1406
|
+
* Example: `var(--primary-color, var(--secondary-color))`
|
|
1407
|
+
* → `var(--primary-color-oklch, var(--secondary-color-oklch))`
|
|
1408
|
+
*/
|
|
1409
|
+
function convertColorChainToComponentChain(colorValue) {
|
|
1410
|
+
const suffix = getColorSpaceSuffix();
|
|
1411
|
+
const faded = parseAlphaOverride(colorValue);
|
|
1412
|
+
if (faded) return convertColorChainToComponentChain(faded.color);
|
|
1413
|
+
const componentVarMatch = colorValue.match(/^(?:rgb|hsl|oklch)a?\(\s*(var\(--[a-z0-9-]+-color-(?:rgb|hsl|oklch)\))\s*\//);
|
|
1414
|
+
if (componentVarMatch) return componentVarMatch[1];
|
|
1415
|
+
if (colorFuncName(colorValue)) {
|
|
1416
|
+
const components = getColorSpaceComponents(colorValue);
|
|
1417
|
+
return components !== colorValue ? components : toRelativeColorSpaceComponents(colorValue);
|
|
1418
|
+
}
|
|
1419
|
+
const match = colorValue.match(/var\(--([a-z0-9-]+)-color\s*(?:,\s*(.+))?\)/);
|
|
1420
|
+
if (!match) {
|
|
1421
|
+
const components = getColorSpaceComponents(colorValue);
|
|
1422
|
+
if (components !== colorValue) return components;
|
|
1423
|
+
return colorValue;
|
|
1424
|
+
}
|
|
1425
|
+
const [, name, fallback] = match;
|
|
1426
|
+
if (!fallback) return `var(--${name}-color-${suffix})`;
|
|
1427
|
+
return `var(--${name}-color-${suffix}, ${convertColorChainToComponentChain(fallback.trim())})`;
|
|
1428
|
+
}
|
|
1429
|
+
/**
|
|
1173
1430
|
* Convert a color initial value (from @property definitions) to components
|
|
1174
1431
|
* in the configured color space.
|
|
1175
1432
|
*/
|
|
@@ -1203,63 +1460,6 @@ function getComponentPropertySyntax() {
|
|
|
1203
1460
|
}
|
|
1204
1461
|
}
|
|
1205
1462
|
//#endregion
|
|
1206
|
-
//#region src/parser/const.ts
|
|
1207
|
-
const VALUE_KEYWORDS = new Set([
|
|
1208
|
-
"auto",
|
|
1209
|
-
"max-content",
|
|
1210
|
-
"min-content",
|
|
1211
|
-
"fit-content",
|
|
1212
|
-
"stretch",
|
|
1213
|
-
"initial",
|
|
1214
|
-
"inherit",
|
|
1215
|
-
"revert",
|
|
1216
|
-
"unset",
|
|
1217
|
-
"revert-layer"
|
|
1218
|
-
]);
|
|
1219
|
-
const CSS_WIDE_KEYWORDS = new Set([
|
|
1220
|
-
"initial",
|
|
1221
|
-
"inherit",
|
|
1222
|
-
"revert",
|
|
1223
|
-
"unset",
|
|
1224
|
-
"revert-layer"
|
|
1225
|
-
]);
|
|
1226
|
-
const COLOR_FUNCS = new Set([
|
|
1227
|
-
"rgb",
|
|
1228
|
-
"rgba",
|
|
1229
|
-
"hsl",
|
|
1230
|
-
"hsla",
|
|
1231
|
-
"hwb",
|
|
1232
|
-
"lab",
|
|
1233
|
-
"lch",
|
|
1234
|
-
"oklab",
|
|
1235
|
-
"oklch",
|
|
1236
|
-
"color",
|
|
1237
|
-
"device-cmyk",
|
|
1238
|
-
"gray",
|
|
1239
|
-
"color-mix",
|
|
1240
|
-
"color-contrast"
|
|
1241
|
-
]);
|
|
1242
|
-
const RE_UNIT_NUM = /^[+-]?(?:\d*\.\d+|\d+)([a-z][a-z0-9]*)$/;
|
|
1243
|
-
const RE_NUMBER = /^[+-]?(?:\d*\.\d+|\d+)$/;
|
|
1244
|
-
const RE_HEX = /^(?:[0-9a-f]{3,4}|[0-9a-f]{6}(?:[0-9a-f]{2})?)$/;
|
|
1245
|
-
const RE_RAW_UNIT = /^([+-]?(?:\d*\.\d+|\d+))([a-z%]+)$/;
|
|
1246
|
-
const CANONICAL_FUNC_CASE = new Map([
|
|
1247
|
-
["translatex", "translateX"],
|
|
1248
|
-
["translatey", "translateY"],
|
|
1249
|
-
["translatez", "translateZ"],
|
|
1250
|
-
["scalex", "scaleX"],
|
|
1251
|
-
["scaley", "scaleY"],
|
|
1252
|
-
["scalez", "scaleZ"],
|
|
1253
|
-
["rotatex", "rotateX"],
|
|
1254
|
-
["rotatey", "rotateY"],
|
|
1255
|
-
["rotatez", "rotateZ"],
|
|
1256
|
-
["skewx", "skewX"],
|
|
1257
|
-
["skewy", "skewY"]
|
|
1258
|
-
]);
|
|
1259
|
-
function canonicalFuncName(lowered) {
|
|
1260
|
-
return CANONICAL_FUNC_CASE.get(lowered) ?? lowered;
|
|
1261
|
-
}
|
|
1262
|
-
//#endregion
|
|
1263
1463
|
//#region src/parser/types.ts
|
|
1264
1464
|
const makeEmptyPart = () => ({
|
|
1265
1465
|
mods: [],
|
|
@@ -1299,6 +1499,53 @@ const finalizeGroup = (d, parts) => {
|
|
|
1299
1499
|
//#endregion
|
|
1300
1500
|
//#region src/parser/classify.ts
|
|
1301
1501
|
/**
|
|
1502
|
+
* Convert an opacity suffix to the alpha value it denotes.
|
|
1503
|
+
*
|
|
1504
|
+
* The authored digits are kept verbatim — `.07` stays `.07` rather than being
|
|
1505
|
+
* multiplied into `7.000000000000001%` — and a `$prop` suffix passes the
|
|
1506
|
+
* reference straight through, so it works whether the property holds a
|
|
1507
|
+
* `<number>` or a `<percentage>`. Both are what the alpha slot accepts.
|
|
1508
|
+
*/
|
|
1509
|
+
function alphaSuffixToAlpha(rawAlpha) {
|
|
1510
|
+
if (rawAlpha.startsWith("$")) return `var(--${rawAlpha.slice(1)})`;
|
|
1511
|
+
if (rawAlpha === "0") return "0";
|
|
1512
|
+
return `.${rawAlpha}`;
|
|
1513
|
+
}
|
|
1514
|
+
/** Apply an opacity suffix to a color, replacing any alpha it already carries. */
|
|
1515
|
+
function fadeColor(color, rawAlpha) {
|
|
1516
|
+
return overrideColorAlpha(color, alphaSuffixToAlpha(rawAlpha));
|
|
1517
|
+
}
|
|
1518
|
+
/**
|
|
1519
|
+
* Convert an opacity suffix to the percentage `color-mix()` needs, by shifting
|
|
1520
|
+
* the decimal point rather than multiplying: `.07` is `7%`, not the
|
|
1521
|
+
* `7.000000000000001%` that `parseFloat('.07') * 100` produces.
|
|
1522
|
+
*/
|
|
1523
|
+
function alphaSuffixToPercentage(rawAlpha) {
|
|
1524
|
+
if (rawAlpha.startsWith("$")) return `calc(var(--${rawAlpha.slice(1)}) * 100%)`;
|
|
1525
|
+
if (rawAlpha === "0") return "0%";
|
|
1526
|
+
const digits = rawAlpha.length === 1 ? `${rawAlpha}0` : rawAlpha;
|
|
1527
|
+
const whole = String(Number(digits.slice(0, 2)));
|
|
1528
|
+
const fraction = digits.slice(2);
|
|
1529
|
+
return `${fraction ? `${whole}.${fraction}` : whole}%`;
|
|
1530
|
+
}
|
|
1531
|
+
/**
|
|
1532
|
+
* Apply an opacity suffix to `currentcolor`, composing with any alpha an
|
|
1533
|
+
* ancestor already applied. See {@link mixColorAlpha} for why this differs from
|
|
1534
|
+
* how a token is faded.
|
|
1535
|
+
*/
|
|
1536
|
+
function fadeCurrentColor(rawAlpha) {
|
|
1537
|
+
return mixColorAlpha("currentcolor", alphaSuffixToPercentage(rawAlpha));
|
|
1538
|
+
}
|
|
1539
|
+
/**
|
|
1540
|
+
* Whether parsed function arguments hold a color. Colors reach either the color
|
|
1541
|
+
* bucket (`#token`, a nested color function, `transparent`) or — for the CSS
|
|
1542
|
+
* named colors, which the parser has no token syntax for — the modifier bucket.
|
|
1543
|
+
*/
|
|
1544
|
+
function hasColorArgs(parsed) {
|
|
1545
|
+
const namedColors = getNamedColorHex();
|
|
1546
|
+
return parsed.groups.some((group) => group.colors.length > 0 || group.mods.some((mod) => namedColors.has(mod)));
|
|
1547
|
+
}
|
|
1548
|
+
/**
|
|
1302
1549
|
* Re-parses a value through the parser until it stabilizes (no changes)
|
|
1303
1550
|
* or max iterations reached. This allows units to reference other units.
|
|
1304
1551
|
* Example: { x: '8px', y: '2x' } -> '1y' resolves to '16px'
|
|
@@ -1400,35 +1647,34 @@ function classify(raw, opts, recurse) {
|
|
|
1400
1647
|
processed: "currentcolor"
|
|
1401
1648
|
};
|
|
1402
1649
|
const currentAlphaMatch = token.match(/^#current\.(\$[a-z_][a-z0-9-_]*|[0-9]+)$/i);
|
|
1403
|
-
if (currentAlphaMatch) {
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
else if (rawAlpha === "0") percentage = "0%";
|
|
1408
|
-
else percentage = `${parseFloat("." + rawAlpha) * 100}%`;
|
|
1409
|
-
return {
|
|
1410
|
-
bucket: 0,
|
|
1411
|
-
processed: `color-mix(in oklab, currentcolor ${percentage}, transparent)`
|
|
1412
|
-
};
|
|
1413
|
-
}
|
|
1650
|
+
if (currentAlphaMatch) return {
|
|
1651
|
+
bucket: 0,
|
|
1652
|
+
processed: fadeCurrentColor(currentAlphaMatch[1])
|
|
1653
|
+
};
|
|
1414
1654
|
if (token[0] === "$" || token[0] === "#") {
|
|
1415
1655
|
const predefinedTokens = getGlobalPredefinedTokens();
|
|
1416
1656
|
if (predefinedTokens) {
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1657
|
+
const lookupKey = token.toLowerCase();
|
|
1658
|
+
if (lookupKey in predefinedTokens) {
|
|
1659
|
+
const tokenValue = predefinedTokens[lookupKey];
|
|
1660
|
+
return classify(foldDslCase(tokenValue), opts, recurse);
|
|
1420
1661
|
}
|
|
1421
1662
|
if (token[0] === "#") {
|
|
1422
1663
|
const alphaMatch = token.match(/^(#[a-z0-9-]+)\.(\$[a-z_][a-z0-9-_]*|[0-9]+)$/i);
|
|
1423
1664
|
if (alphaMatch) {
|
|
1424
1665
|
const [, baseToken, rawAlpha] = alphaMatch;
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1666
|
+
const baseKey = baseToken.toLowerCase();
|
|
1667
|
+
if (baseKey in predefinedTokens) {
|
|
1668
|
+
const resolvedValue = predefinedTokens[baseKey];
|
|
1669
|
+
if (resolvedValue.startsWith("#")) return classify(`${foldDslCase(resolvedValue)}.${rawAlpha}`, opts, recurse);
|
|
1670
|
+
const funcMatch = resolvedValue.match(RE_FUNC_CALL);
|
|
1429
1671
|
if (funcMatch) {
|
|
1430
1672
|
const [, funcName, args] = funcMatch;
|
|
1431
1673
|
const lowerFunc = funcName.toLowerCase();
|
|
1674
|
+
if (DERIVED_COLOR_FUNCS.has(lowerFunc)) return {
|
|
1675
|
+
bucket: 0,
|
|
1676
|
+
processed: fadeColor(classify(foldDslCase(resolvedValue), opts, recurse).processed, rawAlpha)
|
|
1677
|
+
};
|
|
1432
1678
|
const isCustomFunc = !!(opts.functions && lowerFunc in opts.functions && !COLOR_FUNCS.has(lowerFunc) && !COLOR_FUNCS.has(funcName.replace(/a$/i, "").toLowerCase()));
|
|
1433
1679
|
const normalizedFunc = isCustomFunc ? lowerFunc : funcName.replace(/a$/i, "").toLowerCase();
|
|
1434
1680
|
if (!(COLOR_FUNCS.has(normalizedFunc) || COLOR_FUNCS.has(lowerFunc) || isCustomFunc)) return classify(`${resolvedValue}.${rawAlpha}`, opts, recurse);
|
|
@@ -1493,7 +1739,7 @@ function classify(raw, opts, recurse) {
|
|
|
1493
1739
|
}
|
|
1494
1740
|
}
|
|
1495
1741
|
}
|
|
1496
|
-
if (token.match(/^var\(--([a-
|
|
1742
|
+
if (token.match(/^var\(--([a-zA-Z0-9-]+)-color\)$/)) return {
|
|
1497
1743
|
bucket: 0,
|
|
1498
1744
|
processed: token
|
|
1499
1745
|
};
|
|
@@ -1502,12 +1748,12 @@ function classify(raw, opts, recurse) {
|
|
|
1502
1748
|
processed: token
|
|
1503
1749
|
};
|
|
1504
1750
|
if (token[0] === "$") {
|
|
1505
|
-
const identMatch = token.match(/^\$([a-z_][a-
|
|
1751
|
+
const identMatch = token.match(/^\$([a-z_][a-zA-Z0-9-_]*)$/);
|
|
1506
1752
|
if (identMatch) {
|
|
1507
1753
|
const name = identMatch[1];
|
|
1508
1754
|
const processed = `var(--${name})`;
|
|
1509
1755
|
return {
|
|
1510
|
-
bucket: name.endsWith("-color") ?
|
|
1756
|
+
bucket: name.endsWith("-color") ? 3 : 1,
|
|
1511
1757
|
processed
|
|
1512
1758
|
};
|
|
1513
1759
|
}
|
|
@@ -1516,13 +1762,9 @@ function classify(raw, opts, recurse) {
|
|
|
1516
1762
|
const alphaMatch = token.match(/^#([a-z0-9-]+)\.(\$[a-z_][a-z0-9-_]*|[0-9]+)$/i);
|
|
1517
1763
|
if (alphaMatch) {
|
|
1518
1764
|
const [, base, rawAlpha] = alphaMatch;
|
|
1519
|
-
let alpha;
|
|
1520
|
-
if (rawAlpha.startsWith("$")) alpha = `var(--${rawAlpha.slice(1)})`;
|
|
1521
|
-
else if (rawAlpha === "0") alpha = "0";
|
|
1522
|
-
else alpha = `.${rawAlpha}`;
|
|
1523
1765
|
return {
|
|
1524
1766
|
bucket: 0,
|
|
1525
|
-
processed:
|
|
1767
|
+
processed: fadeColor(`var(--${base}-color)`, rawAlpha)
|
|
1526
1768
|
};
|
|
1527
1769
|
}
|
|
1528
1770
|
const name = token.slice(1);
|
|
@@ -1540,10 +1782,12 @@ function classify(raw, opts, recurse) {
|
|
|
1540
1782
|
const fname = token.slice(0, openIdx);
|
|
1541
1783
|
const inner = token.slice(openIdx + 1, -1);
|
|
1542
1784
|
if (COLOR_FUNCS.has(fname)) {
|
|
1543
|
-
const
|
|
1785
|
+
const parsedInner = recurse(inner);
|
|
1786
|
+
const argProcessed = parsedInner.output.replace(/,\s+/g, ",");
|
|
1787
|
+
const processed = `${canonicalFuncName(fname)}(${argProcessed})`;
|
|
1544
1788
|
return {
|
|
1545
|
-
bucket: 0,
|
|
1546
|
-
processed
|
|
1789
|
+
bucket: fname === "light-dark" && !hasColorArgs(parsedInner) ? 1 : 0,
|
|
1790
|
+
processed
|
|
1547
1791
|
};
|
|
1548
1792
|
}
|
|
1549
1793
|
if (opts.functions && fname in opts.functions) {
|
|
@@ -1570,12 +1814,12 @@ function classify(raw, opts, recurse) {
|
|
|
1570
1814
|
}
|
|
1571
1815
|
}
|
|
1572
1816
|
if (token.startsWith("(") && token.endsWith(")")) {
|
|
1573
|
-
const match = token.slice(1, -1).match(/^\$([a-z_][a-
|
|
1817
|
+
const match = token.slice(1, -1).match(/^\$([a-z_][a-zA-Z0-9-_]*)\s*,\s*(.*)$/);
|
|
1574
1818
|
if (match) {
|
|
1575
1819
|
const [, name, fallback] = match;
|
|
1576
1820
|
const processedFallback = recurse(fallback).output;
|
|
1577
1821
|
return {
|
|
1578
|
-
bucket: name.endsWith("-color") ?
|
|
1822
|
+
bucket: name.endsWith("-color") ? 3 : 1,
|
|
1579
1823
|
processed: `var(--${name}, ${processedFallback})`
|
|
1580
1824
|
};
|
|
1581
1825
|
}
|
|
@@ -1712,7 +1956,7 @@ var StyleParser = class {
|
|
|
1712
1956
|
const key = String(src);
|
|
1713
1957
|
const hit = this.cache.get(key);
|
|
1714
1958
|
if (hit) return hit;
|
|
1715
|
-
const stripped = src.replace(/\/\*[^*]*\*+(?:[^/*][^*]*\*+)*\//g, "")
|
|
1959
|
+
const stripped = foldDslCase(src.replace(/\/\*[^*]*\*+(?:[^/*][^*]*\*+)*\//g, ""));
|
|
1716
1960
|
const groups = [];
|
|
1717
1961
|
let currentGroup = makeEmptyDetails();
|
|
1718
1962
|
let currentPart = makeEmptyPart();
|
|
@@ -1739,6 +1983,10 @@ var StyleParser = class {
|
|
|
1739
1983
|
case 2:
|
|
1740
1984
|
currentPart.mods.push(processed);
|
|
1741
1985
|
break;
|
|
1986
|
+
case 3:
|
|
1987
|
+
currentPart.colors.push(processed);
|
|
1988
|
+
currentPart.values.push(processed);
|
|
1989
|
+
break;
|
|
1742
1990
|
}
|
|
1743
1991
|
currentPart.all.push(processed);
|
|
1744
1992
|
};
|
|
@@ -2015,8 +2263,8 @@ function normalizeColorTokenValue(value) {
|
|
|
2015
2263
|
if (value === false) return null;
|
|
2016
2264
|
return value;
|
|
2017
2265
|
}
|
|
2018
|
-
const COLOR_VAR_PATTERN =
|
|
2019
|
-
const COLOR_VAR_COMPONENTS_PATTERN =
|
|
2266
|
+
const COLOR_VAR_PATTERN = /^var\(--([a-z0-9-]+)-color[,)]/;
|
|
2267
|
+
const COLOR_VAR_COMPONENTS_PATTERN = /^(?:[a-z-]+\(\s*)?var\(--([a-z0-9-]+)-color-(?:rgb|hsl|oklch)[,)]/;
|
|
2020
2268
|
const RGB_ALPHA_PATTERN = /\/\s*([0-9.]+)\)/;
|
|
2021
2269
|
const RE_HEX_COLOR = /^#[0-9a-fA-F]{3,8}$/;
|
|
2022
2270
|
const RE_VAR_COLOR = /^var\(--[a-z0-9-]+-color/;
|
|
@@ -2161,6 +2409,28 @@ function parseStyle(value) {
|
|
|
2161
2409
|
else str = "";
|
|
2162
2410
|
return getOrCreateParser().process(str);
|
|
2163
2411
|
}
|
|
2412
|
+
/** A `$`-prefixed custom-property reference — the only DSL syntax that starts with `$`. */
|
|
2413
|
+
const RE_CUSTOM_PROPERTY_REF = /\$[a-zA-Z_$]/;
|
|
2414
|
+
/**
|
|
2415
|
+
* Substitute custom-property references (`$ident` → `var(--ident)`) inside a
|
|
2416
|
+
* value a handler would otherwise emit to CSS verbatim.
|
|
2417
|
+
*
|
|
2418
|
+
* Handlers for keyword-valued properties (`display`, `align`, `text-transform`,
|
|
2419
|
+
* `overflow`, …) pass their input straight through, since there are no units or
|
|
2420
|
+
* color tokens to resolve. That leaked the raw DSL into the stylesheet:
|
|
2421
|
+
* `display: '$my-display'` emitted `display: $my-display`, which the browser
|
|
2422
|
+
* drops as invalid. The same applies to color props whose value the parser could
|
|
2423
|
+
* not classify as a color — `$ident` is a color only when the name ends with
|
|
2424
|
+
* `-color`, so `fill: '$my-fill'` fell back to the unparsed input.
|
|
2425
|
+
*
|
|
2426
|
+
* Values without a `$` skip the parser entirely, so pass-through behaviour (and
|
|
2427
|
+
* the parser's case folding) is unchanged for every value that was already
|
|
2428
|
+
* valid CSS.
|
|
2429
|
+
*/
|
|
2430
|
+
function resolveCustomProperties(value) {
|
|
2431
|
+
if (!RE_CUSTOM_PROPERTY_REF.test(value)) return value;
|
|
2432
|
+
return parseStyle(value).output || value;
|
|
2433
|
+
}
|
|
2164
2434
|
/**
|
|
2165
2435
|
* Parse color. Find it value, name and opacity.
|
|
2166
2436
|
* Optimized to avoid heavy parseStyle calls for simple color patterns.
|
|
@@ -2184,11 +2454,17 @@ function parseColor(val, ignoreError = false) {
|
|
|
2184
2454
|
}
|
|
2185
2455
|
firstColor = extractedColor;
|
|
2186
2456
|
}
|
|
2187
|
-
|
|
2188
|
-
|
|
2457
|
+
const faded = parseAlphaOverride(firstColor);
|
|
2458
|
+
const baseColor = faded ? faded.color : firstColor;
|
|
2459
|
+
let nameMatch = baseColor.match(COLOR_VAR_PATTERN);
|
|
2460
|
+
if (!nameMatch) nameMatch = baseColor.match(COLOR_VAR_COMPONENTS_PATTERN);
|
|
2189
2461
|
let opacity;
|
|
2190
|
-
if (
|
|
2191
|
-
const
|
|
2462
|
+
if (faded) {
|
|
2463
|
+
const { alpha } = faded;
|
|
2464
|
+
const v = parseFloat(alpha);
|
|
2465
|
+
if (!isNaN(v)) opacity = alpha.endsWith("%") ? v : v * 100;
|
|
2466
|
+
} else if (baseColor.startsWith("rgb") || baseColor.startsWith("hsl") || baseColor.startsWith("lch") || baseColor.startsWith("oklch")) {
|
|
2467
|
+
const alphaMatch = baseColor.match(RGB_ALPHA_PATTERN);
|
|
2192
2468
|
if (alphaMatch) {
|
|
2193
2469
|
const v = parseFloat(alphaMatch[1]);
|
|
2194
2470
|
if (!isNaN(v)) opacity = v * 100;
|
|
@@ -3156,6 +3432,10 @@ function rscClassRegexGlobal(prefix) {
|
|
|
3156
3432
|
*/
|
|
3157
3433
|
const CUSTOM_PROP_DECL = /^\s*(--[a-z0-9_-]+)\s*:\s*(.+?)\s*$/i;
|
|
3158
3434
|
const SINGLE_VAR_REF = /^var\((--[a-z0-9_-]+)\)$/i;
|
|
3435
|
+
/** A `--name-color-{space}` companion holding a color's channel components. */
|
|
3436
|
+
const COLOR_COMPONENTS_DECL = /^\s*(--[a-z0-9_-]+-color-(?:rgb|hsl|oklch))\s*:\s*(.+?)\s*$/i;
|
|
3437
|
+
/** A component list the browser can type as `<number>+`. */
|
|
3438
|
+
const NUMERIC_COMPONENTS = /^[\d\s.+-]+$/;
|
|
3159
3439
|
var PropertyTypeResolver = class {
|
|
3160
3440
|
/** propName → the prop it depends on */
|
|
3161
3441
|
pendingDeps = /* @__PURE__ */ new Map();
|
|
@@ -3168,6 +3448,15 @@ var PropertyTypeResolver = class {
|
|
|
3168
3448
|
scanDeclarations(declarations, isPropertyDefined, registerProperty) {
|
|
3169
3449
|
if (!declarations.includes("--")) return;
|
|
3170
3450
|
const parts = declarations.split(/;+/);
|
|
3451
|
+
for (const part of parts) {
|
|
3452
|
+
const match = COLOR_COMPONENTS_DECL.exec(part);
|
|
3453
|
+
if (!match) continue;
|
|
3454
|
+
const propName = match[1];
|
|
3455
|
+
if (isPropertyDefined(propName)) continue;
|
|
3456
|
+
if (NUMERIC_COMPONENTS.test(match[2])) continue;
|
|
3457
|
+
if (isPropertyDefined(propName.slice(0, propName.lastIndexOf("-")))) continue;
|
|
3458
|
+
registerProperty(propName, "*", getDefaultComponents());
|
|
3459
|
+
}
|
|
3171
3460
|
for (const part of parts) {
|
|
3172
3461
|
if (!part.trim()) continue;
|
|
3173
3462
|
const match = CUSTOM_PROP_DECL.exec(part);
|
|
@@ -3259,8 +3548,59 @@ function extractCSSWideKeyword(group) {
|
|
|
3259
3548
|
if (group.values.length !== 1 || group.colors.length > 0) return null;
|
|
3260
3549
|
return CSS_WIDE_KEYWORDS.has(group.values[0]) ? group.values[0] : null;
|
|
3261
3550
|
}
|
|
3551
|
+
/** A resolved custom-property reference, i.e. `var(--name)` or `var(--name, …)`. */
|
|
3552
|
+
const RE_VAR_REFERENCE = /^var\(/;
|
|
3553
|
+
/**
|
|
3554
|
+
* Assign custom-property references to the style and color slots of a
|
|
3555
|
+
* `<line-width> <line-style> <line-color>` shorthand (`border`, `outline`).
|
|
3556
|
+
*
|
|
3557
|
+
* The parser cannot type a reference, so it buckets `$name` as a plain value and
|
|
3558
|
+
* the handler has to place it. A reference fills the first slot still free, in
|
|
3559
|
+
* shorthand order: the width takes `values[0]`, then the style, then the color.
|
|
3560
|
+
* The style would otherwise arrive as a keyword (`solid`, `dashed`, …) that a
|
|
3561
|
+
* reference has no way to match, and the color as `#name` — the `$name-color`
|
|
3562
|
+
* form the parser buckets as a color exists to reference a raw CSS custom
|
|
3563
|
+
* property, not as the way colors are written, so a reference should not reach
|
|
3564
|
+
* for the color slot until the style slot is taken.
|
|
3565
|
+
*
|
|
3566
|
+
* Lengths are left alone: a second length is not valid in these shorthands, and
|
|
3567
|
+
* promoting one would emit an invalid declaration instead of ignoring an extra
|
|
3568
|
+
* value. Callers supply their own slot defaults.
|
|
3569
|
+
*/
|
|
3570
|
+
function assignLineSlots(values, styleKeyword, colorToken) {
|
|
3571
|
+
if (styleKeyword && colorToken) return {
|
|
3572
|
+
style: styleKeyword,
|
|
3573
|
+
color: colorToken
|
|
3574
|
+
};
|
|
3575
|
+
const spare = values.slice(1).filter((value) => RE_VAR_REFERENCE.test(value) && value !== colorToken);
|
|
3576
|
+
return {
|
|
3577
|
+
style: styleKeyword || spare.shift(),
|
|
3578
|
+
color: colorToken || spare.shift()
|
|
3579
|
+
};
|
|
3580
|
+
}
|
|
3262
3581
|
/** Warning keys already emitted, so each distinct offending value warns once. */
|
|
3263
3582
|
const emittedWarnings$2 = /* @__PURE__ */ new Set();
|
|
3583
|
+
/** A resolved custom-property reference anywhere in a token. */
|
|
3584
|
+
const RE_HAS_VAR_REFERENCE = /var\(/;
|
|
3585
|
+
/**
|
|
3586
|
+
* Reject a custom-property reference used where a *token name* is expected.
|
|
3587
|
+
*
|
|
3588
|
+
* `preset` and `transition` take the name of a design token (`t3`, `fill`) and
|
|
3589
|
+
* interpolate it into a CSS custom property — `var(--t3-font-size)`. A reference
|
|
3590
|
+
* substituted into that position builds `var(--var(--x)-font-size)`, which is not
|
|
3591
|
+
* a valid custom-property name, so the browser drops the declaration and the
|
|
3592
|
+
* style silently does nothing. The DSL has no way to indirect a token name
|
|
3593
|
+
* through a custom property: the name is needed at build time, and a reference
|
|
3594
|
+
* only resolves in the browser.
|
|
3595
|
+
*
|
|
3596
|
+
* Returns true (warning once per value in dev) so the caller can fall back
|
|
3597
|
+
* instead of emitting a declaration that cannot work.
|
|
3598
|
+
*/
|
|
3599
|
+
function isTokenNameReference(property, name) {
|
|
3600
|
+
if (!RE_HAS_VAR_REFERENCE.test(name)) return false;
|
|
3601
|
+
warnOnceDev(`token-name-reference:${property}:${name}`, `${property}="${name}": a custom property cannot name a token. The name is interpolated into a CSS custom property at build time, so a reference would build an unusable name. It is ignored.`);
|
|
3602
|
+
return true;
|
|
3603
|
+
}
|
|
3264
3604
|
/**
|
|
3265
3605
|
* Emit a style-level warning at most once per `key`. No-op outside dev mode.
|
|
3266
3606
|
*
|
|
@@ -3314,13 +3654,13 @@ function warnExtraGroupValues(property, input, maxValues) {
|
|
|
3314
3654
|
function processGroup$1(group) {
|
|
3315
3655
|
const { values, mods, colors } = group;
|
|
3316
3656
|
const directions = filterMods(mods, DIRECTIONS);
|
|
3317
|
-
const
|
|
3657
|
+
const slots = assignLineSlots(values, filterMods(mods, BORDER_STYLES)[0], colors?.[0]);
|
|
3318
3658
|
return {
|
|
3319
3659
|
directions,
|
|
3320
3660
|
borderValue: {
|
|
3321
3661
|
width: values[0] || "var(--border-width)",
|
|
3322
|
-
style:
|
|
3323
|
-
color:
|
|
3662
|
+
style: slots.style || "solid",
|
|
3663
|
+
color: slots.color || "var(--border-color, currentColor)"
|
|
3324
3664
|
}
|
|
3325
3665
|
};
|
|
3326
3666
|
}
|
|
@@ -3419,32 +3759,28 @@ function borderStyle({ border }) {
|
|
|
3419
3759
|
}
|
|
3420
3760
|
borderStyle.__lookupStyles = ["border"];
|
|
3421
3761
|
//#endregion
|
|
3422
|
-
//#region src/
|
|
3423
|
-
function
|
|
3424
|
-
|
|
3762
|
+
//#region src/styles/color.ts
|
|
3763
|
+
function colorStyle({ color }) {
|
|
3764
|
+
if (!color) return null;
|
|
3765
|
+
if (color === true) color = "currentColor";
|
|
3766
|
+
color = parseColor(color, true).color || resolveCustomProperties(color);
|
|
3767
|
+
const match = color.match(/var\(--(.+?)-color/);
|
|
3768
|
+
let name = "";
|
|
3769
|
+
if (match) name = match[1];
|
|
3770
|
+
const styles = { color };
|
|
3771
|
+
if (name && name !== "current") {
|
|
3772
|
+
const suffix = getColorSpaceSuffix();
|
|
3773
|
+
Object.assign(styles, {
|
|
3774
|
+
"--current-color": color,
|
|
3775
|
+
[`--current-color-${suffix}`]: convertColorChainToComponentChain(color)
|
|
3776
|
+
});
|
|
3777
|
+
}
|
|
3778
|
+
return styles;
|
|
3425
3779
|
}
|
|
3780
|
+
colorStyle.__lookupStyles = ["color"];
|
|
3426
3781
|
//#endregion
|
|
3427
3782
|
//#region src/styles/createStyle.ts
|
|
3428
3783
|
const CACHE = {};
|
|
3429
|
-
/**
|
|
3430
|
-
* Convert color fallback chain to component fallback chain.
|
|
3431
|
-
* Example: var(--primary-color, var(--secondary-color))
|
|
3432
|
-
* → var(--primary-color-oklch, var(--secondary-color-oklch))
|
|
3433
|
-
*/
|
|
3434
|
-
function convertColorChainToComponentChain(colorValue) {
|
|
3435
|
-
const suffix = getColorSpaceSuffix();
|
|
3436
|
-
const componentVarMatch = colorValue.match(/^(?:rgb|hsl|oklch)a?\(\s*(var\(--[a-z0-9-]+-color-(?:rgb|hsl|oklch)\))\s*\//);
|
|
3437
|
-
if (componentVarMatch) return componentVarMatch[1];
|
|
3438
|
-
const match = colorValue.match(/var\(--([a-z0-9-]+)-color\s*(?:,\s*(.+))?\)/);
|
|
3439
|
-
if (!match) {
|
|
3440
|
-
const components = getColorSpaceComponents(colorValue);
|
|
3441
|
-
if (components !== colorValue) return components;
|
|
3442
|
-
return colorValue;
|
|
3443
|
-
}
|
|
3444
|
-
const [, name, fallback] = match;
|
|
3445
|
-
if (!fallback) return `var(--${name}-color-${suffix})`;
|
|
3446
|
-
return `var(--${name}-color-${suffix}, ${convertColorChainToComponentChain(fallback.trim())})`;
|
|
3447
|
-
}
|
|
3448
3784
|
function createStyle(styleName, cssStyle, converter) {
|
|
3449
3785
|
const key = `${styleName}.${cssStyle ?? ""}`;
|
|
3450
3786
|
if (!CACHE[key]) {
|
|
@@ -3453,16 +3789,18 @@ function createStyle(styleName, cssStyle, converter) {
|
|
|
3453
3789
|
if (styleValue == null || styleValue === false) return null;
|
|
3454
3790
|
let finalCssStyle;
|
|
3455
3791
|
const isColorToken = !cssStyle && typeof styleName === "string" && styleName.startsWith("#");
|
|
3456
|
-
if (isColorToken) finalCssStyle = `--${
|
|
3457
|
-
else
|
|
3792
|
+
if (isColorToken) finalCssStyle = `--${normalizeDslName(styleName.slice(1))}-color`;
|
|
3793
|
+
else if (!cssStyle && styleName[0] === "$") finalCssStyle = `--${normalizeDslName(styleName.slice(1))}`;
|
|
3794
|
+
else finalCssStyle = cssStyle || toSnakeCase(styleName);
|
|
3458
3795
|
if (isColorToken) {
|
|
3459
3796
|
const normalized = normalizeColorTokenValue(styleValue);
|
|
3460
3797
|
if (normalized === null) return null;
|
|
3461
3798
|
styleValue = normalized;
|
|
3462
3799
|
}
|
|
3463
|
-
if (converter
|
|
3464
|
-
|
|
3465
|
-
if (
|
|
3800
|
+
if (converter) {
|
|
3801
|
+
const converted = converter(styleValue);
|
|
3802
|
+
if (converted) styleValue = converted;
|
|
3803
|
+
else if (typeof styleValue !== "string") return null;
|
|
3466
3804
|
}
|
|
3467
3805
|
if (typeof styleValue === "string" && finalCssStyle.startsWith("--") && finalCssStyle.endsWith("-color")) {
|
|
3468
3806
|
styleValue = styleValue.trim();
|
|
@@ -3486,6 +3824,10 @@ function createStyle(styleName, cssStyle, converter) {
|
|
|
3486
3824
|
[finalCssStyle]: colorSpaceStr,
|
|
3487
3825
|
[`${finalCssStyle}-${suffix}`]: getColorSpaceComponents(colorSpaceStr)
|
|
3488
3826
|
};
|
|
3827
|
+
if (color && colorFuncName(color)) return {
|
|
3828
|
+
[finalCssStyle]: color,
|
|
3829
|
+
[`${finalCssStyle}-${suffix}`]: convertColorChainToComponentChain(color)
|
|
3830
|
+
};
|
|
3489
3831
|
return { [finalCssStyle]: color ?? "" };
|
|
3490
3832
|
}
|
|
3491
3833
|
const processed = parseStyle(styleValue);
|
|
@@ -3497,26 +3839,6 @@ function createStyle(styleName, cssStyle, converter) {
|
|
|
3497
3839
|
return CACHE[key];
|
|
3498
3840
|
}
|
|
3499
3841
|
//#endregion
|
|
3500
|
-
//#region src/styles/color.ts
|
|
3501
|
-
function colorStyle({ color }) {
|
|
3502
|
-
if (!color) return null;
|
|
3503
|
-
if (color === true) color = "currentColor";
|
|
3504
|
-
if (typeof color === "string" && (color.startsWith("#") || color.startsWith("(#"))) color = parseColor(color).color || color;
|
|
3505
|
-
const match = color.match(/var\(--(.+?)-color/);
|
|
3506
|
-
let name = "";
|
|
3507
|
-
if (match) name = match[1];
|
|
3508
|
-
const styles = { color };
|
|
3509
|
-
if (name && name !== "current") {
|
|
3510
|
-
const suffix = getColorSpaceSuffix();
|
|
3511
|
-
Object.assign(styles, {
|
|
3512
|
-
"--current-color": color,
|
|
3513
|
-
[`--current-color-${suffix}`]: convertColorChainToComponentChain(color)
|
|
3514
|
-
});
|
|
3515
|
-
}
|
|
3516
|
-
return styles;
|
|
3517
|
-
}
|
|
3518
|
-
colorStyle.__lookupStyles = ["color"];
|
|
3519
|
-
//#endregion
|
|
3520
3842
|
//#region src/styles/display.ts
|
|
3521
3843
|
/**
|
|
3522
3844
|
* Process textOverflow into CSS properties for truncation/clamping.
|
|
@@ -3567,14 +3889,15 @@ function processTextOverflow(textOverflow, whiteSpace) {
|
|
|
3567
3889
|
*/
|
|
3568
3890
|
function displayStyle({ display, hide, textOverflow, overflow, whiteSpace }) {
|
|
3569
3891
|
const result = {};
|
|
3892
|
+
const whiteSpaceValue = whiteSpace ? resolveCustomProperties(whiteSpace) : whiteSpace;
|
|
3570
3893
|
if (textOverflow != null && textOverflow !== false) {
|
|
3571
|
-
const textResult = processTextOverflow(textOverflow,
|
|
3894
|
+
const textResult = processTextOverflow(textOverflow, whiteSpaceValue);
|
|
3572
3895
|
if (textResult) Object.assign(result, textResult);
|
|
3573
3896
|
}
|
|
3574
|
-
if (overflow && !result["overflow"]) result["overflow"] = overflow;
|
|
3575
|
-
if (
|
|
3897
|
+
if (overflow && !result["overflow"]) result["overflow"] = resolveCustomProperties(overflow);
|
|
3898
|
+
if (whiteSpaceValue && !result["white-space"]) result["white-space"] = whiteSpaceValue;
|
|
3576
3899
|
if (hide) result["display"] = "none";
|
|
3577
|
-
else if (!result["display"] && display) result["display"] = display;
|
|
3900
|
+
else if (!result["display"] && display) result["display"] = resolveCustomProperties(display);
|
|
3578
3901
|
if (Object.keys(result).length === 0) return null;
|
|
3579
3902
|
return result;
|
|
3580
3903
|
}
|
|
@@ -3655,7 +3978,7 @@ function fillStyle({ fill, backgroundColor, image, backgroundImage, backgroundPo
|
|
|
3655
3978
|
const parsed = parseStyle(colorValue);
|
|
3656
3979
|
const firstColor = parsed.groups[0]?.colors[0];
|
|
3657
3980
|
const secondColor = parsed.groups[0]?.colors[1];
|
|
3658
|
-
result["background-color"] = firstColor || colorValue;
|
|
3981
|
+
result["background-color"] = firstColor || resolveCustomProperties(colorValue);
|
|
3659
3982
|
if (secondColor) result["--tasty-second-fill-color"] = secondColor;
|
|
3660
3983
|
}
|
|
3661
3984
|
const gradientLayer = result["--tasty-second-fill-color"] ? "linear-gradient(var(--tasty-second-fill-color), var(--tasty-second-fill-color))" : null;
|
|
@@ -3666,10 +3989,10 @@ function fillStyle({ fill, backgroundColor, image, backgroundImage, backgroundPo
|
|
|
3666
3989
|
} else if (gradientLayer) result["background-image"] = gradientLayer;
|
|
3667
3990
|
if (backgroundPosition) result["background-position"] = parseStyle(backgroundPosition).output || backgroundPosition;
|
|
3668
3991
|
if (backgroundSize) result["background-size"] = parseStyle(backgroundSize).output || backgroundSize;
|
|
3669
|
-
if (backgroundRepeat) result["background-repeat"] = backgroundRepeat;
|
|
3670
|
-
if (backgroundAttachment) result["background-attachment"] = backgroundAttachment;
|
|
3671
|
-
if (backgroundOrigin) result["background-origin"] = backgroundOrigin;
|
|
3672
|
-
if (backgroundClip) result["background-clip"] = backgroundClip;
|
|
3992
|
+
if (backgroundRepeat) result["background-repeat"] = resolveCustomProperties(backgroundRepeat);
|
|
3993
|
+
if (backgroundAttachment) result["background-attachment"] = resolveCustomProperties(backgroundAttachment);
|
|
3994
|
+
if (backgroundOrigin) result["background-origin"] = resolveCustomProperties(backgroundOrigin);
|
|
3995
|
+
if (backgroundClip) result["background-clip"] = resolveCustomProperties(backgroundClip);
|
|
3673
3996
|
if (Object.keys(result).length === 0) return null;
|
|
3674
3997
|
return result;
|
|
3675
3998
|
}
|
|
@@ -3688,7 +4011,7 @@ fillStyle.__lookupStyles = [
|
|
|
3688
4011
|
];
|
|
3689
4012
|
function svgFillStyle({ svgFill }) {
|
|
3690
4013
|
if (!svgFill) return null;
|
|
3691
|
-
svgFill = parseStyle(svgFill).groups[0]?.colors[0] || svgFill;
|
|
4014
|
+
svgFill = parseStyle(svgFill).groups[0]?.colors[0] || resolveCustomProperties(svgFill);
|
|
3692
4015
|
return { fill: svgFill };
|
|
3693
4016
|
}
|
|
3694
4017
|
svgFillStyle.__lookupStyles = ["svgFill"];
|
|
@@ -3698,7 +4021,7 @@ function flowStyle({ display = "block", flow }) {
|
|
|
3698
4021
|
let style;
|
|
3699
4022
|
if (display.includes("grid")) style = "grid-auto-flow";
|
|
3700
4023
|
else if (display.includes("flex")) style = "flex-flow";
|
|
3701
|
-
return style ? { [style]: flow } : null;
|
|
4024
|
+
return style && flow ? { [style]: resolveCustomProperties(flow) } : null;
|
|
3702
4025
|
}
|
|
3703
4026
|
flowStyle.__lookupStyles = ["display", "flow"];
|
|
3704
4027
|
//#endregion
|
|
@@ -4083,17 +4406,18 @@ function outlineStyle({ outline, outlineOffset }) {
|
|
|
4083
4406
|
};
|
|
4084
4407
|
const offsetPart = parts[1];
|
|
4085
4408
|
const typeMods = filterMods(outlinePart.mods, BORDER_STYLES);
|
|
4409
|
+
const slots = assignLineSlots(outlinePart.values, typeMods[0], outlinePart.colors[0]);
|
|
4086
4410
|
result["outline"] = [
|
|
4087
4411
|
outlinePart.values[0] || "var(--outline-width)",
|
|
4088
|
-
|
|
4089
|
-
|
|
4412
|
+
slots.style || "solid",
|
|
4413
|
+
slots.color || "var(--outline-color)"
|
|
4090
4414
|
].join(" ");
|
|
4091
4415
|
if (offsetPart?.values[0]) result["outline-offset"] = offsetPart.values[0];
|
|
4092
4416
|
}
|
|
4093
4417
|
}
|
|
4094
4418
|
if (outlineOffset != null && !result["outline-offset"]) {
|
|
4095
4419
|
const offsetValue = typeof outlineOffset === "number" ? `${outlineOffset}px` : outlineOffset;
|
|
4096
|
-
result["outline-offset"] = parseStyle(offsetValue).groups[0]?.values[0] || offsetValue;
|
|
4420
|
+
result["outline-offset"] = parseStyle(offsetValue).groups[0]?.values[0] || resolveCustomProperties(offsetValue);
|
|
4097
4421
|
}
|
|
4098
4422
|
if (Object.keys(result).length === 0) return null;
|
|
4099
4423
|
return result;
|
|
@@ -4132,7 +4456,7 @@ paddingStyle.__lookupStyles = [
|
|
|
4132
4456
|
function str(val) {
|
|
4133
4457
|
if (val == null || val === false || val === "") return null;
|
|
4134
4458
|
if (val === true) return "center";
|
|
4135
|
-
return String(val);
|
|
4459
|
+
return resolveCustomProperties(String(val));
|
|
4136
4460
|
}
|
|
4137
4461
|
/**
|
|
4138
4462
|
* Unified placement handler replacing align, justify, and place.
|
|
@@ -4214,7 +4538,7 @@ const PRESET_MODIFIERS = new Set([
|
|
|
4214
4538
|
function toCSS(value, isNumeric) {
|
|
4215
4539
|
if (value == null) return null;
|
|
4216
4540
|
if (typeof value === "number") return isNumeric ? `${value}px` : String(value);
|
|
4217
|
-
return parseStyle(String(value)).groups[0]?.values[0] || String(value);
|
|
4541
|
+
return parseStyle(String(value)).groups[0]?.values[0] || resolveCustomProperties(String(value));
|
|
4218
4542
|
}
|
|
4219
4543
|
function setCSSValue(styles, styleName, presetName, { varOnly, cssOnly } = {}) {
|
|
4220
4544
|
const value = (() => {
|
|
@@ -4236,11 +4560,11 @@ function setCSSValue(styles, styleName, presetName, { varOnly, cssOnly } = {}) {
|
|
|
4236
4560
|
* - `fontFamily="Arial"` → Arial (direct, no fallback)
|
|
4237
4561
|
*/
|
|
4238
4562
|
function resolveFontFamily(font, fontFamily) {
|
|
4239
|
-
if (fontFamily) return fontFamily;
|
|
4563
|
+
if (fontFamily) return resolveCustomProperties(fontFamily);
|
|
4240
4564
|
if (font == null || font === false) return null;
|
|
4241
4565
|
if (font === "monospace") return "var(--font-mono, var(--font-mono-fallback))";
|
|
4242
4566
|
if (font === true) return "var(--font-sans, var(--font-sans-fallback))";
|
|
4243
|
-
return `${font}, var(--font-sans, var(--font-sans-fallback))`;
|
|
4567
|
+
return `${resolveCustomProperties(font)}, var(--font-sans, var(--font-sans-fallback))`;
|
|
4244
4568
|
}
|
|
4245
4569
|
/**
|
|
4246
4570
|
* Handles typography preset and individual font properties.
|
|
@@ -4274,7 +4598,7 @@ function presetStyle({ preset, fontSize, lineHeight, textTransform, letterSpacin
|
|
|
4274
4598
|
const nameTokens = namePart?.all ?? [];
|
|
4275
4599
|
const isModOnly = nameTokens.length > 0 && nameTokens.every((t) => PRESET_MODIFIERS.has(t));
|
|
4276
4600
|
const nameToken = namePart?.mods[0] ?? namePart?.values[0] ?? "";
|
|
4277
|
-
const name = isModOnly ? "inherit" : nameToken || "inherit";
|
|
4601
|
+
const name = isModOnly || isTokenNameReference("preset", nameToken) ? "inherit" : nameToken || "inherit";
|
|
4278
4602
|
const modTokens = isModOnly ? nameTokens : modPart?.all ?? [];
|
|
4279
4603
|
const activeMods = /* @__PURE__ */ new Set();
|
|
4280
4604
|
for (const tok of modTokens) if (PRESET_MODIFIERS.has(tok)) activeMods.add(tok);
|
|
@@ -4312,7 +4636,7 @@ function presetStyle({ preset, fontSize, lineHeight, textTransform, letterSpacin
|
|
|
4312
4636
|
if (fontStyle != null) if (fontStyle === true) styles["font-style"] = "italic";
|
|
4313
4637
|
else if (typeof fontStyle === "string" && CSS_WIDE_KEYWORDS.has(fontStyle)) styles["font-style"] = fontStyle;
|
|
4314
4638
|
else styles["font-style"] = fontStyle ? "italic" : "normal";
|
|
4315
|
-
if (textTransform) styles["text-transform"] = textTransform;
|
|
4639
|
+
if (textTransform) styles["text-transform"] = resolveCustomProperties(textTransform);
|
|
4316
4640
|
const fontFamily_ = resolveFontFamily(font, fontFamily);
|
|
4317
4641
|
if (fontFamily_) styles["font-family"] = fontFamily_;
|
|
4318
4642
|
if (Object.keys(styles).length === 0) return null;
|
|
@@ -4504,10 +4828,10 @@ function scrollbarStyle({ scrollbar, overflow }) {
|
|
|
4504
4828
|
scrollbarStyle.__lookupStyles = ["scrollbar", "overflow"];
|
|
4505
4829
|
//#endregion
|
|
4506
4830
|
//#region src/styles/shadow.ts
|
|
4507
|
-
function toBoxShadow(
|
|
4508
|
-
const { values, mods, colors } =
|
|
4831
|
+
function toBoxShadow(group) {
|
|
4832
|
+
const { values, mods, colors } = group;
|
|
4509
4833
|
const mod = mods[0] || "";
|
|
4510
|
-
const shadowColor =
|
|
4834
|
+
const shadowColor = colors[0] ?? "";
|
|
4511
4835
|
return [
|
|
4512
4836
|
mod,
|
|
4513
4837
|
...values,
|
|
@@ -4518,7 +4842,8 @@ function shadowStyle({ shadow }) {
|
|
|
4518
4842
|
if (!shadow) return null;
|
|
4519
4843
|
if (shadow === true) shadow = "var(--shadow)";
|
|
4520
4844
|
if (CSS_WIDE_KEYWORDS.has(shadow)) return { "box-shadow": shadow };
|
|
4521
|
-
|
|
4845
|
+
const { groups } = parseStyle(shadow);
|
|
4846
|
+
return { "box-shadow": groups.map(toBoxShadow).join(",") };
|
|
4522
4847
|
}
|
|
4523
4848
|
shadowStyle.__lookupStyles = ["shadow"];
|
|
4524
4849
|
//#endregion
|
|
@@ -4647,6 +4972,7 @@ function transitionStyle({ transition }) {
|
|
|
4647
4972
|
const map = {};
|
|
4648
4973
|
transitions.forEach((transition) => {
|
|
4649
4974
|
const name = transition[0];
|
|
4975
|
+
if (isTokenNameReference("transition", name)) return;
|
|
4650
4976
|
let timing;
|
|
4651
4977
|
let easing;
|
|
4652
4978
|
let delay;
|
|
@@ -4667,6 +4993,7 @@ function transitionStyle({ transition }) {
|
|
|
4667
4993
|
];
|
|
4668
4994
|
});
|
|
4669
4995
|
});
|
|
4996
|
+
if (Object.keys(map).length === 0) return null;
|
|
4670
4997
|
return { transition: Object.entries(map).map(([style, [name, easing, timing, delay]]) => {
|
|
4671
4998
|
let value = `${style} ${timing || getTiming(name)}`;
|
|
4672
4999
|
if (easing || delay) value += ` ${easing || DEFAULT_EASING}`;
|
|
@@ -4703,11 +5030,28 @@ const devMode$2 = isDevEnv();
|
|
|
4703
5030
|
function inDevMode() {
|
|
4704
5031
|
return isDevEnv();
|
|
4705
5032
|
}
|
|
5033
|
+
/**
|
|
5034
|
+
* Read a grid track count, or `undefined` when the value isn't one.
|
|
5035
|
+
*
|
|
5036
|
+
* Plain digit strings count: every value inside a state map arrives as a
|
|
5037
|
+
* string, so `gridColumns: { '': '2', '@media(w < 600px)': '1' }` would
|
|
5038
|
+
* otherwise emit `grid-template-columns: 2` — invalid CSS that browsers drop
|
|
5039
|
+
* silently.
|
|
5040
|
+
*
|
|
5041
|
+
* Zero and negatives yield `undefined`. Zero already produced an empty value,
|
|
5042
|
+
* and a negative number used to throw inside `String.repeat`.
|
|
5043
|
+
*/
|
|
5044
|
+
function trackCount(val) {
|
|
5045
|
+
const count = typeof val === "number" ? val : typeof val === "string" && /^\d+$/.test(val.trim()) ? Number(val.trim()) : NaN;
|
|
5046
|
+
return Number.isFinite(count) && count >= 1 ? Math.floor(count) : void 0;
|
|
5047
|
+
}
|
|
4706
5048
|
const columnsConverter = (val) => {
|
|
4707
|
-
|
|
5049
|
+
const count = trackCount(val);
|
|
5050
|
+
return count === void 0 ? void 0 : "minmax(1px, 1fr) ".repeat(count).trim();
|
|
4708
5051
|
};
|
|
4709
5052
|
const rowsConverter = (val) => {
|
|
4710
|
-
|
|
5053
|
+
const count = trackCount(val);
|
|
5054
|
+
return count === void 0 ? void 0 : "auto ".repeat(count).trim();
|
|
4711
5055
|
};
|
|
4712
5056
|
const STYLE_HANDLER_MAP$1 = {};
|
|
4713
5057
|
let initialHandlerMapSnapshot = null;
|
|
@@ -4754,7 +5098,7 @@ function predefine() {
|
|
|
4754
5098
|
defineStyleAlias("gridRows", "grid-template-rows", rowsConverter);
|
|
4755
5099
|
defineStyleAlias("gridTemplate", "grid-template", (val) => {
|
|
4756
5100
|
if (typeof val !== "string") return;
|
|
4757
|
-
return val.split("/").map((s, i) => (i ? columnsConverter : rowsConverter)(s)).join("/");
|
|
5101
|
+
return val.split("/").map((s, i) => (i ? columnsConverter : rowsConverter)(s) ?? s).join("/");
|
|
4758
5102
|
});
|
|
4759
5103
|
[
|
|
4760
5104
|
displayStyle,
|
|
@@ -12157,6 +12501,6 @@ function resetConfig() {
|
|
|
12157
12501
|
delete storage[GLOBAL_INJECTOR_KEY];
|
|
12158
12502
|
}
|
|
12159
12503
|
//#endregion
|
|
12160
|
-
export { SheetManager as $,
|
|
12504
|
+
export { SheetManager as $, overrideColorAlpha as $t, FLOW_STYLES as A, registerFunctionPolyfill as At, createStateParserContext as B, stringifyStyles as Bt, BASE_STYLES as C, LAYOUT_CHUNK_STYLES as Ct, COLOR_STYLES as D, formatFunctionRule as Dt, BLOCK_STYLES as E, extractLocalFunctions as Et, hasPipelineCacheEntry as F, getGlobalParser as Ft, StyleInjector as G, createColorFunc as Gt, extractPredefinedStateRefs as H, okhstPlugin as Ht, isSelector as I, getGlobalPredefinedTokens as It, hasLocalCounterStyle as J, colorInitialValueToComponents as Jt, extractLocalCounterStyle as K, isDevEnv as Kt, renderStyles as L, normalizeColorTokenValue as Lt, OUTER_STYLES as M, CUSTOM_UNITS as Mt, POSITION_STYLES as N, DIRECTIONS as Nt, CONTAINER_STYLES as O, hasLocalFunctions as Ot, TEXT_STYLES as P, filterMods as Pt, hasLocalFontFace as Q, getComponentPropertySyntax as Qt, parseStateKey as R, parseColor as Rt, baseStylePropsRegistry as S, FONT_CHUNK_STYLES as St, BLOCK_OUTER_STYLES as T, STYLE_TO_CHUNK as Tt, getGlobalPredefinedStates as U, okhslFunction as Ut, extractLocalPredefinedStates as V, okhstFunction as Vt, setGlobalPredefinedStates as W, okhslPlugin as Wt, fontFaceContentHash as X, getColorSpaceComponents as Xt, extractLocalFontFace as Y, convertColorChainToComponentChain as Yt, formatFontFaceRule as Z, getColorSpaceSuffix as Zt, isFunctionsPolyfillEnabled as _, propHandlerRegistry as _t, getGlobalCounterStyles as a, hslToRgbValues as an, DEFAULT_NAME_PREFIX as at, resetConfig as b, DIMENSION_CHUNK_STYLES as bt, getGlobalInjector as c, makeCounterStyleName as ct, getGlobalStyles as d, validateNamePrefix as dt, resolveFunctionColor as en, STYLE_HANDLER_MAP as et, getNamePrefix as f, hashString as ft, isConfigLocked as g, parsePropertyToken as gt, hasStylesGenerated as h, hasLocalProperties as ht, getGlobalConfigTokens as i, hexToRgb as in, PropertyTypeResolver as it, INNER_STYLES as j, registerLocalFunctionPolyfills as jt, DIMENSION_STYLES as k, parseFunctionName as kt, getGlobalKeyframes as l, makeKeyframeName as lt, hasGlobalRecipes as m, getEffectiveDefinition as mt, getConfig as n, getNamedColorHex as nn, styleHandlers as nt, getGlobalFontFaces as o, strToRgb as on, DEFAULT_ZERO_NAME_PREFIX as ot, hasGlobalKeyframes as p, extractLocalProperties as pt, formatCounterStyleRule as q, StyleParser as qt, getEffectiveProperties as r, getRgbValuesFromRgbaString as rn, createStyle as rt, getGlobalFunctions as s, normalizeDslName as sn, makeClassName as st, configure as t, Lru as tn, defineHandler as tt, getGlobalRecipes as u, tastyClassRegex as ut, isTestEnvironment as v, APPEARANCE_CHUNK_STYLES as vt, BLOCK_INNER_STYLES as w, POSITION_CHUNK_STYLES as wt, generateTypographyTokens as x, DISPLAY_CHUNK_STYLES as xt, markStylesGenerated as y, CHUNK_NAMES as yt, camelToKebab as z, parseStyle as zt };
|
|
12161
12505
|
|
|
12162
|
-
//# sourceMappingURL=config-
|
|
12506
|
+
//# sourceMappingURL=config-CwQ-fAsp.js.map
|